---
title: "Browser"
description: "Hosted Chromium (and Lightpanda) sessions that Playwright, Puppeteer or any other client of the Chrome DevTools Protocol drives from outside. A session is awake while a client is connected, and sleeps with its pages when the last one leaves. 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.

# Browser

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

Browser gives each task a Chromium of its own, in a machine of its own, which your code drives from outside over the Chrome DevTools Protocol (CDP): Playwright, Puppeteer or any other CDP client. Each browser is a **session**. You make one with an API call and get its address; your client connects there, and the address is the credential.

A session is awake while a client is connected to it, whatever its pages are doing, and falls asleep a few seconds after the last one leaves, with its tabs, its pages and their cookies kept. The next connection wakes it where it was.

## When to use Browser

- **An agent that browses**: a model that reads web pages and acts on them, through a CDP client of yours or an MCP server that drives a browser at an address.
- **Pages that need a real browser**: scraping, testing, filling forms; a session per job or per user, made by name and found again by name.
- **A browser that keeps where it was**: a session that sleeps between turns keeps its pages and its logins, and wakes where it was; a [profile](/docs/browser/live-and-profiles/#profiles) carries a login to new sessions.
- **Watching an agent at work**: a session's page, [live](/docs/browser/live-and-profiles/#watching-a-session-live) in any browser, with an address for people who may only look.

## How it works

1. **Make.** `POST /v1/browsers` makes a session, awake, and answers with its CDP address, `cdp_url`. A session has a name if you give it one: a create with the name of a session the project has answers that session, woken where it slept.
2. **Connect.** Your client connects at `cdp_url`: Playwright's `connectOverCDP`, Puppeteer's `connect` with `browserURL`.
3. **Sleep.** When the last connection closes, the session sleeps `sleep_after_seconds` later (10 unless you say), its memory and disk kept. A connection wakes it.
4. **End.** `DELETE /v1/browsers/{id}` ends it, with its pages.

Three kinds of session:

- `chromium-headless`, the default: Chromium's headless shell, a browser with no screen.
- `chromium`: the full Chromium, on a screen of 1280×800 that a person can watch.
- `lightpanda`: [Lightpanda](#lightpanda), a browser made for programs, which runs a page's scripts and keeps its DOM, and has no layout engine: its screenshots and PDFs hold the page's text alone.

Every session is a machine of 1 vCPU and 2 GiB. Its id is a sandbox's, and a session is a sandbox the platform made for it: every call of `/v1/sandboxes/{id}/…` works on it too, so you can run a command in it or read its files. A plain sandbox never becomes a session, whatever it runs.

## Connecting a client

`cdp_url` is all a CDP client needs, and is a credential: whoever has it drives the browser. Playwright connects with `chromium.connectOverCDP(cdp_url)` (`connect_over_cdp` in Python), Puppeteer with `puppeteer.connect({ browserURL: cdp_url })`. Playwright needs no browser of its own for it.

```bash
CDP=$(glac browsers create --name agent-42)       # prints the session's CDP address, and nothing else
npx @playwright/mcp --cdp-endpoint "$CDP"          # an agent's browser tools, driving the session
```

```python
from glac import Glac

glac = Glac()
with glac.browsers.create(name="agent-42") as session:   # deleted when the block ends
    browser = session.connect()                          # Playwright, connected over CDP
    page = browser.contexts[0].pages[0]
    page.goto("https://example.com")
```

`POST /v1/browsers/{id}/rotate-url` gives a session new addresses: the old ones are refused from then on, and the connections they let in are ended at once ([new addresses](/docs/browser/sessions/#new-addresses)).

The command line has `glac browsers`; the Python and TypeScript SDKs have `glac.browsers`, with every call; the Go, Rust and Java SDKs make, find and end sessions; the MCP server opens, lists and closes them (`browser_open`, `browser_list`, `browser_close`). See the [command line](/docs/cli/#browser), the [Python SDK](/docs/sdks/python/#browser) and the [MCP server](/docs/mcp/#browser).

## What it costs

A session is billed as every instance is, by the Cube resources it uses, at the [list prices](/docs/platform/pricing/): its CPU time while it computes, its memory while it is awake, and its traffic out. It has no price of its own. A session is 1 vCPU and 2 GiB; the calculator on the site's Browser page takes its vCPU busy half the time it is awake, unless you say otherwise.

| Meter | Price | Free, each day | Paid includes a month |
|---|---|---|---|
| CPU, while it computes | $0.01 a million CPU-ms | 1M CPU-ms | 60M CPU-ms |
| Memory, while awake or paused in memory | $0.008 a GiB-hour | 6 GiB-hours | 250 GiB-hours |
| What a sleeping instance keeps (its memory and its own disk) | $0.02 a GB-month | 15 GB of data in all, with snapshots and Drives | 20 GB-months of data, with snapshots and Drives |
| Traffic out to the internet, from North America | $0.004 a GB | 3 GB, from any region | 1 TB, from any region |
| Traffic out to the internet, from Europe | $0.004 a GB |  |  |
| Traffic out to the internet, from Asia-Pacific | $0.01 a GB |  |  |

- **Asleep**, a session is billed as any sleeping sandbox: what it keeps (its memory and the part of its disk that is its own), at $0.02 a GB-month, and nothing else. That holds while it is held paused in the machine's memory before it is saved, too: what it holds there is billed as what it keeps, never as memory.
- **On Free**, its CPU and memory come out of Free's quotas of the day, with everything else the account runs; **on Paid**, out of the month's inclusions, then the balance. See [pricing and plans](/docs/platform/pricing/).

## Lightpanda

A session of the kind `lightpanda` runs [Lightpanda](https://github.com/lightpanda-io/browser) 1.0.2, a browser made for programs: it fetches pages, runs their scripts and keeps their DOM, and has no layout engine. Use it to read pages and act on them where nothing has to be seen; use `chromium-headless` where something does. It is made, priced and limited as the other kinds are, and its `cdp_url` and `ws_url` work the same way. Lightpanda is open source (AGPL-3.0), and runs in the session as its makers release it.

Connect with a context and a page of your own, as Lightpanda's makers show: the page a connection finds already open is Lightpanda's starting point, and does not navigate.

```js
const browser = await chromium.connectOverCDP(session.cdp_url);   // Playwright
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://example.com");
console.log(await page.textContent("h1"));
```

With Puppeteer, `puppeteer.connect({ browserURL: session.cdp_url })` (or `browserWSEndpoint: session.ws_url`), then `(await browser.pages())[0]` or `browser.newPage()`.

What was tried, through the platform's edge, with Playwright 1.64 and Puppeteer 24.43:

| Works | Does not |
|---|---|
| Loading pages, links and back and forward (`goto`, a click that navigates, `waitForURL` and `waitForNavigation`, `goBack`, `reload`); reading the page (`content`, `textContent`, `innerText`, `evaluate`, `$$eval`, locators, `waitForSelector`) | A second page in a connection (`newPage` once one is open: `TargetAlreadyLoaded`), and a second context (`Cannot have more than one browser context at a time`). Each connection is a browser of its own: open another connection for another page (16 at once at the most) |
| Typing and clicking (`fill`, `type`, `keyboard.type`, `click`) | A screencast (`Page.startScreencast`): there is nothing to stream, and it is refused at once with an error that names `chromium-headless` |
| Cookies (`context.cookies`, `addCookies`; `page.cookies`, `setCookie`), extra headers (`setExtraHTTPHeaders`), requests answered by the client (Playwright's `page.route`, Puppeteer's request interception) | The live view, and profiles (400 `kind_unsupported`) |
| `setViewportSize` and `setViewport`, scripts before the page's own (`addInitScript`, `evaluateOnNewDocument`), `exposeFunction`, console messages, Puppeteer's `accessibility.snapshot()` | A message to the browser larger than 16 MiB |
| Screenshots and PDFs (`page.screenshot()`, `page.pdf()`): of the page's text alone, below | |

**A screenshot or a PDF holds only the page's text.** Lightpanda has no layout engine: `page.screenshot()` gives a PNG of the page's text, set in blocks one under another, and `page.pdf()` a PDF of that text. Neither is the page as a person would see it: no layout, no images, no colours of the page's own. `chromium-headless` gives the rendered page.

## Limits

- **Awake at once**: a session counts as one sandbox of 1 vCPU and 2 GiB against what the account's plan lets it have awake at once, with its sandboxes and Cubes' instances (5 on Free: see [limits](/docs/platform/limits/)).
- **Ports closed for good**: a session's traffic never reaches ports 25, 465 and 587 (mail) or the ports mining pools listen on (3333, 4444, 5555, 7777, 14444, 45700), whatever its network rules say.
- **Proxies**: on a paid plan a session's web traffic can go out through an HTTP proxy of your own ([your own proxy](/docs/browser/sessions/#your-own-proxy)); the free plan has none (403 `proxy_not_on_plan`).

## Next

- [Sessions](/docs/browser/sessions/): the calls, what a session has, names, sleep and wake, new addresses, your own proxy.
- [Live view and profiles](/docs/browser/live-and-profiles/): watching a session's page, and logins kept in profiles.

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