Browser
The browser template gives an agent its own Chromium to drive. It is a real
browser running headful on its own display, not a headless build, and you
connect to it over the Chrome DevTools Protocol (CDP) from Playwright,
Puppeteer or anything else that speaks CDP. Port 9222 is CDP; port 6080 is a
live view of the screen in noVNC.
The browser is fingerprint-chromium, an open-source build of ungoogled-chromium (BSD-3-Clause), pinned to version 150. Each profile gets a fingerprint of its own: canvas, audio, fonts and the hardware values a page can read come from a seed that the profile keeps for its whole life.
Start a browser
Create a sandbox from browser and connect to port 9222. Chromium starts on
the first CDP request, so the first connection takes a second or two longer
than the ones after it.
import { Sandbox } from '@impello/sdk'
import { chromium } from 'playwright'
const sandbox = await Sandbox.create('browser', { timeoutMs: 1_800_000 })
const browser = await chromium.connectOverCDP(
`https://${sandbox.getHost(9222)}`
)
const context = browser.contexts()[0]
const page = context.pages()[0] ?? (await context.newPage())
await page.goto('https://example.com')
console.log(await page.title())Use the browser's existing context, browser.contexts()[0]. It is the
profile on disk, with its fingerprint, cookies and logins. A context you make
with newContext() is a fresh incognito-style context that keeps nothing.
Connect, never launch. chromium.launch() starts a second, local browser with
automation switches turned on, and a page can see them; connectOverCDP
attaches to the one already running in the sandbox.
The URL is the HTTPS address of port 9222. Its /json/version answers with a
wss:// WebSocket address on the same host, which is what Playwright reads.
A client that wants the WebSocket address directly can use
wss://<host>/ with no path; it reaches the browser target.
Connect to a private sandbox
With network: { allowPublicTraffic: false } the CDP and live-view ports stop
answering callers without the sandbox's traffic access token. Send the token
in the e2b-traffic-access-token header. Playwright sends the headers you give
connectOverCDP on both the HTTP request and the WebSocket.
import { Sandbox } from '@impello/sdk'
import { chromium } from 'playwright'
const sandbox = await Sandbox.create('browser', {
network: { allowPublicTraffic: false },
})
const token = sandbox.trafficAccessToken
if (!token) throw new Error('no traffic access token')
const browser = await chromium.connectOverCDP(
`https://${sandbox.getHost(9222)}`,
{ headers: { 'e2b-traffic-access-token': token } }
)Watch it live
The screen is served by noVNC at /vnc.html on port 6080. Open it in a
browser tab to watch the agent, or click into it to take over: the keyboard
and mouse are shared with the agent.
console.log(`https://${sandbox.getHost(6080)}/vnc.html?autoconnect=true&resize=scale`)
The live view takes the token as a header too, so a browser tab cannot open the live view of a private sandbox on its own. Put a proxy you control in front of it that adds the header, or keep the sandbox public only while you watch.
The browser command
Inside the sandbox, browser starts, stops and configures Chromium. Run it
with commands.run before you connect, and your settings apply from the first
page. The settings are saved, so if Chromium exits, the next CDP request starts
it again the same way.
browser start [--profile NAME] [--proxy URL] [--seed N] [--timezone TZ]
[--lang LANG] [--platform linux|windows|macos] [-- CHROME FLAGS]
browser restart [the same flags]
browser stop
browser status
Every flag has an environment variable: BROWSER_PROFILE, BROWSER_PROXY,
BROWSER_SEED, BROWSER_TIMEZONE, BROWSER_LANG, BROWSER_PLATFORM and
BROWSER_ARGS. Chromium's log is ~/.browser/chrome.log.
Profiles
A profile is a directory under ~/.browser/profiles/, default unless you
name another. It holds the cookies, local storage, history and logins, and the
fingerprint seed. The seed is drawn at random the first time a profile starts
and read back every time after, so one profile is one identity, and two
sandboxes never share one by accident.
await sandbox.commands.run('browser restart --profile shop-account')The disk survives pause and resume, so a
paused sandbox comes back with every profile, signed in where you left it. To
carry an identity to another sandbox, copy the profile directory with the
filesystem API, or pass --seed to give a new
profile a seed you chose (an integer from 0 to 2147483647).
Proxy
--proxy sends every request through an HTTP or SOCKS proxy, for example
--proxy socks5://203.0.113.7:1080. The proxy URL cannot carry a username and
password; use a proxy that allows your sandbox's address instead.
await sandbox.commands.run('browser restart', {
envs: { BROWSER_PROXY: 'http://203.0.113.7:3128' },
})Timezone and language
On every start the browser looks up the timezone of the IP it will browse from
— through the proxy when there is one — and uses it, so the clock a page reads
agrees with where the request comes from. The lookup asks ipwho.is and gives
up after 4 seconds; then the timezone is UTC. Set it yourself with
--timezone Europe/Paris. The timezone is read when the browser starts, so a
sandbox that resumes behind a different IP keeps the old one until
browser restart.
The language is en-US unless you pass --lang, for example --lang de-DE;
Accept-Language follows it.
Platform
The fingerprint describes a Linux computer by default, which is what the
sandbox is. --platform windows or --platform macos changes the user agent,
the platform and the reported graphics card to match; the fonts and the
network stack underneath are still Linux.
Size and price
The template is 2 vCPU and 4 GB, billed like every other sandbox; see Limits and pricing. The browser renders on the CPU, with no GPU, so pages heavy on WebGL or video are slower than on a desktop.
What it is not
The browser does not solve CAPTCHAs and is not a way around a site's terms. A fingerprint per profile, a matching timezone and a headful display remove the differences that make an automated browser look unlike a person's; they do not change what the agent does on the page. Sites that check behaviour, IP reputation or account history judge those as they would for anyone.