Skip to documentation
API + guides

01Documentation

Chrome Shared Desktop

Share one headed Chromium-based browser (Chrome Stable) between a human and a coding agent inside a Sandbox0 sandbox. Both use the same tabs and login state, and can inspect applications served on sandbox loopback ports.

The chrome template includes sandbox0-browser: a foreground command that starts Chromium, its desktop, and a built-in web viewer. Open the viewer through a Private Preview and attach the agent through local CDP. No additional template, desktop script, or frontend is required.

The same runtime is also included in coding-agent and used by Sandpi. The chrome template contains Chrome, the full desktop and Playwright CLI without installing the coding-agent harnesses. In the dashboard, use Open browser on the sandbox to start the supervised browser and open its private viewer.

Quickstart#

Use a chrome image containing sandbox0-browser. Existing sandboxes retain their installed files when a template changes; check availability with sandbox0-browser --version inside the sandbox. If the command is missing, use an updated template for a new sandbox or explicitly upgrade the old RootFS. See Coding Agents.

Install the JavaScript SDK and save the following as browser.mjs:

bash
npm install sandbox0@^0.10.1
javascript
import { Client } from "sandbox0"; import { setTimeout as sleep } from "node:timers/promises"; const token = process.env.SANDBOX0_API_KEY; const baseUrl = process.env.SANDBOX0_API_URL; if (!token || !baseUrl) { throw new Error("SANDBOX0_API_KEY and SANDBOX0_API_URL are required"); } const client = new Client({ token, baseUrl, }); const sandbox = await client.sandboxes.claim("chrome", { ttl: 3600, hardTtl: 7200, resources: { memory: "2Gi" }, }); try { const session = await sandbox.createSession({ command: ["sandbox0-browser", "--require-version", "2"], cwd: "/workspace", readiness: { type: "output", output: "Browser ready:", timeoutMs: 60000, }, lifecycle: { restart: { policy: "on_failure" }, runtimeRecovery: "restart", }, }, { idempotencyKey: "shared-browser" }); let ready = false; for (let attempt = 0; attempt < 75; attempt++) { const current = await sandbox.getSession(session.id); if (current.phase === "running") { ready = true; break; } if (["failed", "exited", "stopped", "suspended"].includes(current.phase)) { throw new Error(`Browser session ended: ${current.phase}`); } await sleep(1000); } if (!ready) throw new Error("Browser readiness timed out"); const preview = await sandbox.createPreview({ port: 6080, protocol: "http", path: "/", ttlSeconds: 900, }); console.log("Sandbox:", sandbox.id); console.log("Browser session:", session.id); console.log("Preview grant:", preview.id); console.log("Open this one-time link in your browser:", preview.url); } catch (error) { await client.sandboxes.delete(sandbox.id); throw error; }

Set SANDBOX0_API_KEY and SANDBOX0_API_URL for your deployment, then run node browser.mjs. Open the printed link in your browser to see and control Chromium. Keep this link private and do not fetch it from your backend first: it contains a one-time credential that the browser exchanges for a preview cookie. The SDK/API key stays in your backend or local script.

The supervised session keeps running after this script exits. A Private Preview expires independently; renew it before expiration or create a new grant to open another viewer. See Private Previews for renewal, revocation, and runtime generation behavior.

To stop the browser, call sandbox.setSessionDesiredState(sessionId, "stopped"). To remove the test sandbox and its RootFS, call client.sandboxes.delete(sandboxId).

Use An Existing Sandbox#

Run the helper in a supervised session rather than an interactive terminal:

bash
s0 sandbox session create "$SANDBOX_ID" \ --restart on_failure --runtime-recovery restart \ --readiness output --ready-output 'Browser ready:' \ --ready-timeout-ms 60000 -- sandbox0-browser --require-version 2

Wait until the session is running, then create a Private Preview for port 6080 as above or with the HTTP API:

bash
curl -X POST "$SANDBOX0_API_URL/api/v1/sandboxes/$SANDBOX_ID/previews" \ -H "Authorization: Bearer $SANDBOX0_API_KEY" \ -H "Content-Type: application/json" \ -d '{"port":6080,"protocol":"http","path":"/","ttl_seconds":900}'

Open data.url in your browser. Creating a preview does not start the browser process. Run only one shared browser per sandbox; starting a second helper fails instead of taking over an active profile.

Attach The Agent#

With the browser ready, run these commands inside the same sandbox:

bash
playwright-cli attach --cdp=http://127.0.0.1:9222 playwright-cli tab-list playwright-cli snapshot

Read the installed CLI's version-matched Agent Skill before using automation commands. attach reuses the existing browser and tabs. A separately launched browser or isolated context does not share the same interaction. See the upstream Playwright CLI guide.

The human can sign in through the viewer and let the agent continue in the same browser. Coordinate before navigating, typing, or closing tabs: sharing a browser does not serialize human and agent input. When the agent finishes, use playwright-cli detach to leave Chromium running. Closing the viewer also leaves the browser running.

Defaults And Configuration#

Runtime version 2 includes wallpaper, a bottom taskbar and browser launcher. Task buttons and the launcher restore minimized windows without duplicating them. Closing the final browser window keeps the desktop and viewer connected; the launcher reopens the same profile, retaining cookies. CDP is restarted without opening a window, so automation can reconnect after Chrome exits. Native maximize/restore and F11 fullscreen are available. Normal windows are fitted to the current work area after restoring or shrinking the desktop, and the taskbar reserves its space when windows are maximized. Small viewers scale a desktop of at least 640×480 while preserving their aspect ratio.

SettingDefault
Viewer HTTP and WebSocket127.0.0.1:6080, page /, WebSocket /vnc
Readiness endpointGET /healthz, available after desktop and CDP readiness
Agent CDPhttp://127.0.0.1:9222
Desktop VNC127.0.0.1:5900
Persistent browser profile/workspace/.browser/profile
Persistent downloads/workspace/browser-downloads
Browser usersandbox-browser, with Chromium's process sandbox enabled
Initial desktop size1440x900
Launcher control127.0.0.1:9224, local POST /open, browser Origins rejected

Use sandbox0-browser --help for command options. For example:

bash
sandbox0-browser --profile /workspace/my-browser/profile \ --downloads /workspace/my-browser/downloads --size 1920x1080

Profile and download paths must be separate canonical directories under /workspace, with no symbolic-link ancestors. The helper prepares directory permissions, serializes startup, and recovers stale Chromium singleton links only after checking that the profile has no active browser process. Stopping the helper stops its desktop, window manager, Chromium, and viewer together. Launch the helper as sandbox root; it starts Chrome and the window manager as the dedicated browser user.

The viewer is bundled with the image; browser and desktop dependencies are installed at build time. Claiming a sandbox does not automatically start them. The helper has no independent authentication: keep its default loopback bind and use Private Preview, or protect every published route with service auth. CDP and VNC remain on loopback and are not exposed by the viewer.

Preview Local Web Applications#

Open http://127.0.0.1:3000 in the shared Chromium to inspect a development server in the same sandbox. Here, localhost refers to the sandbox. Your device connects to the viewer while the remote browser connects to the web app, so you do not need to publish each development server.

For a direct link rendered in the human's own browser, use a Private Preview of the application's port.

Integrate Into Your Application#

Applications such as Sandpi can use the same helper with an existing noVNC frontend and an authenticated backend proxy. Register a command-backed Sandbox Service that exposes only the VNC bridge to your backend:

yaml
services: - id: shared-browser port: 6080 runtime: type: cmd command: [sandbox0-browser, --require-version, "2", --host, 0.0.0.0] cwd: /workspace ingress: public: true routes: - id: viewer path_prefix: /vnc methods: [GET] auth: mode: header header_name: X-Browser-Proxy header_value_sha256: <sha256-of-backend-route-token> resume: true

The helper uses SANDBOX0_SERVICE_PORT when a service injects it. It opens the viewer listener only after the desktop and CDP are ready, so the default TCP service readiness check covers browser startup. Include all services you want to retain when updating the service list: PUT /services replaces the list.

Your backend authorizes access to the sandbox and relays the frontend's WebSocket to the service's public_url plus /vnc, using wss and the configured auth header. Browser clients cannot set that header directly. Keep the route token and deployment API key in the backend. Enable sandbox auto_resume and route resume when viewing should wake a paused sandbox.

Sandpi's unified runtime integration invokes this command directly, retaining its existing profile at /workspace/.sandpi/browser/profile. Upgrade retained Environment RootFS generations to runtime version 2 before deploying that integration. Applications must not assume a template promotion changes files already installed in an existing sandbox.

Upgrade An Existing RootFS#

The candidate build workflow produces browser-runtime.tar.gz and records its SHA-256 in coding-agent-release.json. These assets belong to private candidate prereleases; building them does not qualify them for production or make them publicly downloadable. Obtain an approved exact-image archive from your platform operator. The archive is checked to be identical across architectures. Applications can use it to upgrade only the browser runtime on an existing RootFS, preserving workspace, profile, and Agent processes.

Stop only the supervised Browser session/service, extract the verified archive into a separate staging directory, and run bash /path/to/staged-runtime/upgrade-runtime.sh /path/to/staged-runtime as sandbox root. The installer refuses occupied Browser ports, installs missing desktop packages, creates the template's browser user if absent, retains the previous runtime for recovery, and installs the shared launcher. The archive includes its WebSocket library, so it does not depend on that library being installed by a retained coding-agent image. Restart the Browser service and verify sandbox0-browser --version, the viewer, and your Agent's process continuity. The helper uses the existing profile when passed with --profile.

Archived snapshots retain their original binaries. Rerun this upgrade after restoring an old snapshot. Do not replace RootFS or use disk-only pause/resume to upgrade a live Environment. If network policy blocks package repositories, provision the required packages separately or arrange an explicit policy change.

Retired Steel Template#

The former public browser template used Steel's session API. New shared desktop sandboxes use chrome. This is an API change, not a template alias: Steel session, screenshot, scrape and PDF calls do not become Chrome endpoints. Use Playwright against the existing Chrome CDP connection instead.

Existing Steel sandboxes keep their own RootFS and are not converted. See Legacy Steel Browser for their integration. The default agent endpoint remains sandbox-local. An agent outside the sandbox can execute Playwright through Sandbox0's execution API; do not publish bare CDP.

Persistence And Recovery#

StateRecovery behavior
Committed profile files, cookies, and local storageRestored with RootFS; websites may still expire login sessions
DownloadsRestored with RootFS
Browser and desktop processesRestarted after filesystem-only recovery by the session/service; supported memory checkpoint/restore can retain execution state
Viewer and CDP connectionsReconnect after resume or transport failure
Live tabs and in-memory page stateNot guaranteed by RootFS recovery or Chromium session restore
Private Preview grantsRecreate after runtime replacement; renew before expiration

See Pause And Resume for memory checkpoint support and compatibility. Profile persistence does not guarantee continuation of an in-flight browser operation. Reattach the agent when its CDP connection is lost.

RootFS snapshots and forks include profile files, which can contain authenticated sessions. Anyone with workspace access can access those files; grant access to copies accordingly.

Next Steps#