---
title: "Read a cloud browser session"
method: GET
path: "/browser-sessions/{sid}"
tags: ["Cloud browser"]
---

# Read a cloud browser session

`GET /browser-sessions/{sid}`

## Request

- Base URL: `https://api.customdomain.ai/v1`
- URL: `https://api.customdomain.ai/v1/browser-sessions/{sid}`
- Auth: HTTP bearer

The session view. Every call is the popup's heartbeat: a session that is not polled for 90 seconds before approval is ended and its browser released. The response is `Cache-Control: no-store`, because the view can carry the live view address, which anyone holding can drive.

## Path parameters

- `sid` string, required

## Response `200`

The session as the popup may see it.

- BrowserSessionView: One cloud browser session as the popup may see it. `live_view_url` and `live_view_origin` are present only in `awaiting_sign_in` and `manual_assist` (`interactive` true) and, read only, in `checking`, `plan_ready`, `applying` and `verifying`; never in a terminal state. The address is a bearer: anyone holding it can drive the browser. While the customer signs in it is the live view of the newest tab of the remote browser (a sign in popup), and the first tab's again once that one closes.
  - `id` string, required
  - `state` 'created' | 'awaiting_sign_in' | 'checking' | 'plan_ready' | 'applying' | 'verifying' | 'manual_assist' | 'done' | 'done_manual' | 'cancelled' | 'expired' | 'abandoned' | 'failed', required
  - `provider` string, required
  - `provider_name` string
  - `vendor` string: The browser hosting company.
  - `domain` string, required
  - `site` string: The provider's registrable domain, for example namecheap.com. The popup shows it beside a lock while the customer signs in.
  - `interactive` boolean: True when the customer may type in the live view.
  - `live_view_url` string, uri
  - `live_view_origin` string
  - `deadline` string, date-time: The next timer that matters: the sign in window in `awaiting_sign_in`, the approval window in `plan_ready`, the apply window in `applying`, the hard cap otherwise.
  - `plan` BrowserPlan
    - `hash` string, required: The sha256 of the plan, 64 hex characters. `:approve` sends all of it.
    - `base_hash` string, required: The hash of the page the plan was made from.
    - `changes` object[], required: Removes, then changes, then adds. Values are shown in full.
      - `op` 'add' | 'replace' | 'remove', required
      - `type` string, required
      - `name` string, required: The name as the provider's page shows it, `@` for the root.
      - `old` string
      - `new` string
      - `ttl` integer: The rounded value that will be written.
      - `priority` integer
      - `reason` string: Why a record that is not ours goes.
    - `unchanged` integer, required: How many records on the page stay as they are.
    - `approve_by` string, date-time, required
  - `manual` object: Present in `manual_assist`: the records the customer adds by hand.
    - `records` object[]
      - `type` string
      - `name` string
      - `value` string
      - `ttl` integer
      - `present` boolean: The live tick from public DNS, refreshed about every 8 seconds.
    - `guide_url` string
  - `notice` 'not_signed_in': Present after a `:signed-in` that landed on the sign in page, until the customer presses the button again.
  - `error` object: Present in `manual_assist` and `failed`, and in `checking` after the records changed under a plan.
    - `code` string
    - `message` string
  - `sign_in_viewport` BrowserViewport: The remote screen's size in CSS pixels, sent with the live view: `sign_in_viewport` while the customer signs in, `work_viewport` after.
    - `width` integer, required
    - `height` integer, required
  - `work_viewport` BrowserViewport: The remote screen's size in CSS pixels, sent with the live view: `sign_in_viewport` while the customer signs in, `work_viewport` after.
    - `width` integer, required
    - `height` integer, required
  - `sign_in_frame` integer: In `awaiting_sign_in` only: the bottom edge of the provider's sign in card on the remote screen, in CSS pixels from the top and under `sign_in_viewport`'s height, measured when the sign in page opened. The popup ends its frame just under it, so the links below the card stay out of sight. Sent only while the sign in tab still shows the page it was measured on and no human check or second window is on screen; once that changes it is gone for the rest of the session. Absent means show the whole screen.
  - `signed_in_detected` boolean: In `awaiting_sign_in` only: the provider's sign in page gave way to its DNS panel page and the panel held across two polls, so the customer looks signed in. A hint: the popup then calls `:signed-in`, which checks the page itself. Absent means not detected.
  - `check` boolean: In `awaiting_sign_in` only: the vendor reports the sign in tab with the title of a known human check page (Cloudflare's "Just a moment..."), so the popup asks the customer to tick the box. Only this boolean is sent, never the title. A page can fake its title, so it is a hint for the popup's words and nothing else: it never counts toward `signed_in_detected`, and nothing clicks or types because of it. Absent means no check page.

## Other responses

- `401`: `browser_expired`: the token is wrong, expired, or for another session.
- `404`: Error envelope: {code, title, details}.
- `503`: Error envelope: {code, title, details}.

---

[API](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api.md) · [All operations](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/llms.txt) · [OpenAPI document](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/revisions/34d89cb7a7cd?raw)
