Browser
Every sandbox has a browser in it that shows as a browser on an ordinary computer does, and the command-line tools agents drive it with. Your own code can drive it from outside as well.
For your agent
agental.io/docs/browser.mdThere is nothing to install. The browser is run by commands, like anything else in the sandbox, with no call to turn on. A program on your own computer can drive it too, once it is turned on for that, as in Drive it from your own computer. A sandbox made before the browser was added does not have it: create a new one.
Drive it with playwright-cli
playwright-cli is Playwright's command-line tool. It keeps one browser open between commands, so each command is short, and it writes what it reads to a file instead of printing a whole page.
playwright-cli open https://example.com playwright-cli snapshot playwright-cli click e6 playwright-cli screenshot playwright-cli close
snapshotwrites the page as a list of what is on it, and says where. Each thing that can be used has a reference, such ase6, whichclick,fillandtypetake.- It drives the Chrome in the sandbox, with no window.
- With
--headedit opens a window on the desktop, when that is on. playwright-cli --helplists every command.
Send the commands as you send any other, one request each or several in one line of shell:
curl -X POST https://agental.io/v1/sandboxes/{id}/exec \
-H "Authorization: Bearer $AGENTAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command":["sh","-c","playwright-cli open https://example.com && playwright-cli snapshot"]}'Chrome by itself
For one picture, one PDF, or a page as it is once its scripts have run, Chrome alone does it:
google-chrome --headless --screenshot=/opt/agental/page.png --window-size=1280,800 https://example.com google-chrome --headless --print-to-pdf=/opt/agental/page.pdf https://example.com google-chrome --headless --dump-dom https://example.com
- A file written under
/opt/agentalis read back with the files call. - Commands run as root, and Chrome will not start as root with its own sandbox on.
google-chromeandplaywright-clihere start it without, since the machine is yours alone. - A library that starts Chrome itself, such as Puppeteer, has to be told so: pass
--no-sandbox. - Playwright finds this Chrome as the channel
chrome, so no other browser has to be downloaded. - Anything that speaks the DevTools protocol can drive it: start Chrome with
--remote-debugging-port=9222and connect to that port. While the browser is turned on as below, that port is its own, and the Chrome there is the one to connect to.
What is in the image
| What | Which |
|---|---|
| Browser | BetterChromium, the Chromium of the BetterWright project, in Chrome's place: google-chrome, and Playwright's channel chrome, start it |
| BetterWright | betterwright, BetterWright's own tool for the same browser |
| Driver | playwright-cli, from the npm package @playwright/cli |
| Runtime | Node.js 24, with npm |
| Fonts | Liberation, Noto, Noto CJK and Noto Color Emoji |
Drive it from your own computer
Playwright, Puppeteer, browser-use, Stagehand and anything else that speaks the Chrome DevTools Protocol can drive the Chrome in a sandbox from where they run. Turned on for that, Chrome runs in the sandbox's machine with its DevTools on, and keeps running between your scripts. It uses the sandbox's own CPU and memory, and is not charged for by itself.
curl -X PUT https://agental.io/v1/sandboxes/{id}/browser \
-H "Authorization: Bearer $AGENTAL_API_KEY"{
"enabled": true,
"enabledAt": "2026-10-14T09:02:11.480Z",
"running": true,
"headless": true,
"cdpUrl": "wss://b51e09c4d7a2f8e3c610.agental.site/devtools/browser",
"localCdpUrl": "http://127.0.0.1:9222"
}- The sandbox has to be running. The call answers when Chrome is up.
cdpUrlis where to connect. The address is hard to guess and asks for no login: whoever has it has the whole browser, with what it is signed in to. Keep it as you would a password, and do not paste it into a chat or a log.- It is another address each time the browser is turned on after being off. To cut off whoever has it, turn the browser off and on again.
- Asked again, the call changes nothing that is already so, and starts a Chrome that had ended.
- A sandbox made before this was added answers
409 browser_unavailable. Create a new one.
Connect to it
Playwright takes the address as it is:
import { chromium } from "playwright";
const browser = await chromium.connectOverCDP("wss://b51e09c4d7a2f8e3c610.agental.site/devtools/browser");
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.close();So does Puppeteer:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({ browserWSEndpoint: "wss://b51e09c4d7a2f8e3c610.agental.site/devtools/browser" });
const page = await browser.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.disconnect();And browser-use, where llm is one of its chat models:
import asyncio
from browser_use import Agent, Browser
async def main():
browser = Browser(cdp_url="wss://b51e09c4d7a2f8e3c610.agental.site/devtools/browser")
agent = Agent(task="Open example.com and say what it is for", llm=llm, browser=browser)
await agent.run()
asyncio.run(main())Stagehand takes it among its options for a local browser:
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({
env: "LOCAL",
localBrowserLaunchOptions: { cdpUrl: "wss://b51e09c4d7a2f8e3c610.agental.site/devtools/browser" },
});
await stagehand.init();- A sandbox has one Chrome to drive, and many clients can be connected to it at once. Each sees the tabs the others open.
- In Playwright,
browser.contexts()[0]is Chrome's own context, with the cookies and logins in its profile. One made withbrowser.newContext()starts empty. - Playwright's
browser.close()disconnects, and leaves Chrome running. Puppeteer's ends Chrome, which is started again within a second at the same address, with no tabs open. Callbrowser.disconnect()to leave it as it is.
A client that takes an http address instead, such as chrome-devtools-mcp, is given https:// and the host of cdpUrl, with no path:
npx chrome-devtools-mcp@latest --browser-url=https://b51e09c4d7a2f8e3c610.agental.site
With no window, or on the desktop
With no body, Chrome is on the desktop when one is turned on for the sandbox, and has no window when none is. A browser that is already on keeps what it has. To say which, send headless:
curl -X PUT https://agental.io/v1/sandboxes/{id}/browser \
-H "Authorization: Bearer $AGENTAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"headless":false}'falseputs Chrome on the desktop, where it is watched as it is driven. A desktop has to be turned on first, or the call answers409 desktop_not_running.truegives it no window.- Asked for the other, Chrome is started again so, which closes its tabs.
cdpUrlstays the same. - A Chrome on the desktop waits while the desktop is off, with
runningfalse, and comes back on it when the desktop is turned on again.
The same Chrome from inside
localCdpUrl is where programs in the sandbox reach it. playwright-cli attaches to it, and its commands then drive the browser your own code drives:
playwright-cli attach --cdp=http://127.0.0.1:9222 playwright-cli snapshot playwright-cli detach
playwright-cli detachlets go of it, and leaves it running.- So a script on your computer and an agent in the sandbox can use one browser, with one profile.
After a stop
The browser stays turned on for the sandbox. Chrome ends when the sandbox stops, and is started again by itself a moment after the sandbox runs again, with no tabs open.
- It changes nothing.
runningis false while the sandbox is not running, and for a moment after a start.cdpUrlis null then. - The address is the same after a start, so a client that lost its connection connects to it again once
runningis true. - Chrome's profile is in
/root/.config/agental-browser, on the sandbox's disk. Its cookies and logins are kept through a stop, and go with snapshots and forks. A fork does not have the browser turned on.
Turn it off
Stops Chrome, which closes its tabs. Its address leads nowhere from then on, and what is connected through it is cut. The profile stays on the sandbox's disk, and is there when the browser is turned on again.
In the console
A sandbox's Browser view turns it on, with no window or on the desktop, and off. While Chrome runs it shows the address, the lines that connect Playwright, Puppeteer and browser-use to it, and the command that attaches playwright-cli in the sandbox.
Errors
| Answer | Meaning |
|---|---|
409 sandbox_not_running | The sandbox is stopped. Start it, then repeat the request. |
409 desktop_not_running | Chrome was to be on the desktop, and no desktop is turned on. Turn one on, or send {"headless": true}. |
409 browser_unavailable | The machine was made from an image that cannot run the browser to be driven from outside, or Chrome did not start. message says which. |
501 browser_not_configured | Sandboxes here have no browser to drive from outside. GET /v1/policy says so as browser. |
The full machine-readable reference is OpenAPI 3.1. Every page as Markdown, for an agent: llms.txt. Questions: [email protected]