---
title: "Sessions"
description: "The calls of /v1/browsers, what a session is made with and what it has, names that find a session again, when it is awake and asleep, new addresses, your own proxy, and its network. Not open to accounts yet."
---

> Documentation Index
> Fetch the complete documentation index at: https://glac.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions

**Not open yet.** Browser is not open to accounts yet. This page says how it works as it is built, ahead of its opening, and may change before then.

## The calls

| Call | What it does |
|---|---|
| `POST /v1/browsers` | Makes a session, awake (201); or answers the project's session of the name given (200), woken where it slept. |
| `GET /v1/browsers` | The project's sessions, the newest first, a page of `limit` (100, at most 1,000) after `cursor`; `status`, `kind` and `name` keep some. |
| `GET /v1/browsers/{id}` | A session, by its id or its name. |
| `PATCH /v1/browsers/{id}` | Changes its times, its metadata or its proxy. |
| `POST /v1/browsers/{id}/sleep` | Puts it to sleep now. |
| `POST /v1/browsers/{id}/rotate-url` | New addresses: the old ones stop working. |
| `DELETE /v1/browsers/{id}` | Ends it: its browser, its pages and its machine (204). One made with a profile to save saves it first, unless `?save_profile=false`. |
| `GET /v1/browsers/{id}/live`, `POST /v1/browsers/{id}/profile` | Where its page is watched live; its profile saved now ([live view and profiles](/docs/browser/live-and-profiles/)). |
| `GET /v1/browsers/profiles`, `GET`, `DELETE /v1/browsers/profiles/{name}` | The project's profiles. |

Making, changing, putting to sleep and ending a session take a key with the `write` scope; reading them, `read`. Its addresses are credentials, and a key without the `url` scope reads `cdp_url` and `live_url` as `null`.

## Making a session

Every field may be left out:

| Field | What it is |
|---|---|
| `kind` | `chromium-headless` (the default): Chromium's headless shell. `chromium`: the full Chromium, on a screen of 1280×800. `lightpanda`: [Lightpanda](/docs/browser/#lightpanda), which has no layout engine (its screenshots and PDFs hold the page's text alone): a `profile` with it is refused (400 `kind_unsupported`). Another kind is refused (400 `unknown_kind`). |
| `name` | 1 to 63 lower-case letters, digits and hyphens, as a sandbox's, and the project's for one sandbox at a time. A create with the name of the project's session answers that session (below). |
| `region` | `na`, `eu` or `ap`: where it is made. Without it, the region of the control plane. |
| `sleep_after_seconds` | How long after its last connection closed (and its last request) it falls asleep: 1 to 3,600, 10 unless you say. |
| `connection_idle_seconds` | How long a connection to its browser may carry nothing either way before it is closed: 60 to 86,400, 600 unless you say. |
| `delete_after_idle_seconds` | How long it may sleep before it is deleted: 60 seconds to a year. Without it, it is never deleted for sleeping. |
| `metadata` | Keys and values of your own, strings. Not the key `product`, which is the platform's (400 `reserved_metadata`). |
| `profile` | `{name, save, version}`: a [profile](/docs/browser/live-and-profiles/#profiles) loaded before the session is answered (its newest version, or `version`), and saved again when the session is deleted where `save` is `true`. |
| `proxy` | Your own proxy, `{"url": "http://user:password@host:port"}`, on a paid plan: its web traffic goes out through it ([your own proxy](#your-own-proxy)). 403 `proxy_not_on_plan` on the free plan. |

```http
POST /v1/browsers
{"name": "agent-42", "region": "eu", "sleep_after_seconds": 30}
```

The answer is the session (201), with `Location: /v1/browsers/<id>`. A create takes an `Idempotency-Key`, and one sent again under the same key answers as the first did.

A create can be refused for what the plan lets the account have awake at once (403 `plan_cap_reached`, `param` `instances`, `vcpus` or `memory_bytes`), or where no machine has room for it now (503 `no_capacity`, `retryable`). A control plane that was given no image for the kind makes none of it (503 `not_served_here`, `param` `kind`). A session whose browser could not be started (its image could not be had, the browser did not come up) is no session: the create is refused (503 `session_failed`, `retryable`), with what its machine said and its code in `message`, and nothing is left of it.

## What a session has

| Field | What it is |
|---|---|
| `id` | The id of its sandbox (`sbx-…`): every call of `/v1/sandboxes/{id}/…` works on it too. |
| `name`, `kind`, `region` | As it was made. `region` is that of the machine that holds it. |
| `status` | `awake` while it runs, `asleep` while it sleeps (or is held asleep), `unavailable` while its machine cannot be reached, `failed` where it stopped and did not come back. A session that fails is told by the event `browser.failed`. |
| `error` | Why it failed, `{code, message}`, as its machine says it; `null` unless `status` is `failed`. |
| `cdp_url` | Where CDP clients connect: the signed address of its browser's port, `https://9222-<id>-<signature>.<preview domain>`. The credential is in the host name. |
| `live_url` | Where its page (a `chromium` session's screen) is watched and driven live: see [live view](/docs/browser/live-and-profiles/#watching-a-session-live). |
| `profile` | The profile it was made with, or saved last: `{name, save, version}`; `null` for none. |
| `connections` | The connections to it open now, which keep it awake: its clients', and its viewers'. |
| `sleep_after_seconds`, `connection_idle_seconds`, `delete_after_idle_seconds` | Its times, as above. |
| `metadata`, `created_at` | Yours; when it was made. |
| `proxy` | Its own proxy, `{url, username}`: its address (`http://host:port`) and the user name it is asked with, never the password. `null` for none. |
| `usage.awake_seconds` | How long it has been awake, as its bill counts it, to the millisecond. |
| `usage.proxy_bytes` | What went through its proxy since it was made, both ways, to the byte; `usage.proxy_sent_bytes` and `usage.proxy_received_bytes` are each way. |

## The same name, the same session

A create with the name of a session the project has answers that session (200), woken where it slept, its pages as they were: an agent asks for `agent-42` every turn and gets the same browser back. The wake is held to what the plan lets the account have awake at once, as any wake is. Two creates of one name at once make one session, which both answer.

A name a plain sandbox of the project has is refused (409 `name_taken`): no sandbox becomes a session. So is the name of a session of another kind, and `profiles` (400 `invalid_name`), which is the profiles' address.

## Awake and asleep

A session is awake while a client is connected to its browser, or to a `chromium` session's screen, whatever its pages are doing; a page's timers and network do not keep it awake by themselves. It falls asleep `sleep_after_seconds` after the last connection closed (and the last request), with its memory and its disk: its tabs and pages are there when it wakes. A connection that carries nothing either way for `connection_idle_seconds` is closed, so a client that went away without closing does not keep the session awake.

- `POST /v1/browsers/{id}/sleep` puts it to sleep now. A connection that is open stays open, and its next message wakes the session.
- A connection to its address wakes it.
- `PATCH /v1/browsers/{id}` changes `sleep_after_seconds`, `connection_idle_seconds`, `delete_after_idle_seconds`, `metadata` (replaced whole) and `proxy`; `null` puts a time back to its default, `delete_after_idle_seconds: null` keeps it for good, and `proxy: null` takes the proxy away.

## New addresses

`POST /v1/browsers/{id}/rotate-url` gives the session a new secret for its addresses. Every address given out before is refused from then on (401 `invalid_link`), and the connections they let in, its CDP clients' among them, are ended before the call answers. The answer is the session with its new `cdp_url`. Do it when an address has been seen by someone it should not have been.

## Your own proxy

On a paid plan, a session can send its web traffic through an HTTP proxy of yours: give it `proxy` when you make it, or change it later.

```http
POST /v1/browsers
{"name": "agent-42", "proxy": {"url": "http://user:password@proxy.example.com:3128"}}
```

- **What goes through it**: the session's TCP connections to ports 80 and 443, which is what a browser loads pages over. A relay beside the browser, on the machine that runs it, reads where each connection goes (the server name of its TLS handshake, the `Host` of its HTTP request) and asks your proxy for a tunnel there (`CONNECT name:port`, your credentials in a `Proxy-Authorization: Basic` header). The site sees your proxy's address, and the name is resolved at the proxy. Inside the tunnel nothing is read or changed: TLS goes on between the browser and the site.
- **QUIC is refused**: UDP to port 443, which no HTTP proxy carries, does not leave the session, so the browser speaks HTTP over TCP, through the proxy. Connections to any other port go out as they would without a proxy.
- **The browser is not told**: no setting of the browser's says a proxy, nothing is started again for it, and nothing inside the session holds the credentials (no file, environment variable or process). They are kept by the machine the session runs on, and no answer of the API has them: `proxy` shows the address and the user name.
- **The proxy** is an HTTP proxy that takes `CONNECT` to ports 80 and 443 (Squid lets `CONNECT` through to port 443 alone unless you allow port 80 too), at a host name or an address on the internet: `http://` only, a user name and a password written `%XX` where they hold characters a URL does not take (`@`, `:`, `/`). A proxy reached over TLS (`https://`), SOCKS, and an address no sandbox reaches (a private range, link-local, loopback) are refused, 400 `invalid_proxy` (`param` `proxy.url`); the message never repeats the URL.
- **Changing it**: `PATCH /v1/browsers/{id}` with another `proxy`, or `null` for none, holds from the next connection: the browser and its pages go on as they are, the connections through the proxy before are ended, and the browser opens new ones that go where the session goes now.
- **When the proxy takes no tunnel** (it cannot be reached, or answers `CONNECT` with something other than 2xx, 407 for credentials it does not take): a page loaded over HTTP gets 502 `proxy_failed`, whose message says the proxy's address and its answer, never the credentials; one over HTTPS fails its TLS handshake. The session's machine notes it in its log, without the credentials.
- **What it costs**: what went through the proxy is counted both ways (`usage.proxy_bytes`), and is the session's traffic as any: what leaves for your proxy is egress, priced as a sandbox's.
- **Not with request rules**: a session whose [network rules](/docs/sandbox/network/) read its requests (`inject`, `http`) takes no proxy, 400 `invalid_proxy`; rules by address, by port and by name hold for what goes through the proxy as for the rest.
- A proxy is a session's: a plain sandbox takes none (400 `unknown_field`).

## Its network

A session reaches the internet as a sandbox does, and never ports 25, 465 and 587 (mail) or the ports mining pools listen on (3333, 4444, 5555, 7777, 14444, 45700): its machine refuses them before anything else. A session's [network rules](/docs/sandbox/network/) are changed through `PATCH /v1/sandboxes/{id}` with `egress`, and keep those ports closed whatever they say.

Source: https://glac.ai/docs/browser/sessions/index.mdx
