Advanced

Cloud Browsers

No screen locally, no Chrome, not even an always-on server? chrome-use runs anyway. There are two proven ways to move the browser into the cloud: Vercel Sandbox's on-demand microVMs, and AWS Bedrock AgentCore's managed cloud browser sessions. The command-line usage is almost identical to what you type locally — the only difference is which machine the browser runs on.

ℹ️ What this page solves
Use this page when your automation needs to run in a headless environment — serverless functions, CI, scheduled jobs, or the backend of a user-facing web app. If what you want to drive is the Chrome you're actively using on your own machine, see Connect to real Chrome.

Vercel Sandbox: on-demand microVMs

Vercel Sandbox spins up a Linux microVM on demand, runs your browser commands inside it, and destroys it when you're done. It works with any framework deployed on Vercel (Next.js, SvelteKit, Nuxt, Remix, Astro, and more), and it's not subject to the serverless binary size limit — because Chromium lives inside the VM, not bundled into your function.

Install dependencies

First, add the Sandbox SDK to your project:

bash
$ pnpm add @vercel/sandbox

Inside the VM you need Chromium's system libraries, chrome-use itself, and the Chromium browser. On the first run, install the system libraries via dnf (Amazon Linux), install chrome-use with npm, and finally run chrome-use install to fetch the browser:

withBrowser.ts
import { Sandbox } from "@vercel/sandbox";

// System libraries Chromium needs on the sandbox VM (Amazon Linux / dnf)
const CHROMIUM_SYSTEM_DEPS = [
  "nss", "nspr", "libxkbcommon", "atk", "at-spi2-atk", "at-spi2-core",
  "libXcomposite", "libXdamage", "libXrandr", "libXfixes", "libXcursor",
  "libXi", "libXtst", "libXScrnSaver", "libXext", "mesa-libgbm", "libdrm",
  "mesa-libGL", "mesa-libEGL", "cups-libs", "alsa-lib", "pango", "cairo",
  "gtk3", "dbus-libs",
];

async function withBrowser<T>(
  fn: (sandbox: InstanceType<typeof Sandbox>) => Promise<T>,
): Promise<T> {
  const snapshotId = process.env.AGENT_BROWSER_SNAPSHOT_ID;

  const sandbox = snapshotId
    ? await Sandbox.create({ source: { type: "snapshot", snapshotId }, timeout: 120_000 })
    : await Sandbox.create({ runtime: "node24", timeout: 120_000 });

  if (!snapshotId) {
    await sandbox.runCommand("sh", ["-c",
      `sudo dnf install -y --skip-broken ${CHROMIUM_SYSTEM_DEPS.join(" ")} && sudo ldconfig`]);
    await sandbox.runCommand("npm", ["install", "-g", "chrome-use"]);
    await sandbox.runCommand("npx", ["chrome-use", "install"]);
  }

  try { return await fn(sandbox); }
  finally { await sandbox.stop(); }
}
✅ Commands match local
Once the VM is up, what you run inside it is plain chrome-use open, chrome-use snapshot, chrome-use click… no different from local. The sandbox just ferries those commands into the microVM to execute.

Screenshots and snapshots

screenshot --json saves the image to a file and returns its path; read that file back as base64 to hand it to your frontend. To read the page structure, use snapshot -i -c (interactive elements + compact output). The sandbox stays alive across multiple commands, so you can chain a complete flow:

screenshotUrl.ts
return withBrowser(async (sandbox) => {
  await sandbox.runCommand("chrome-use", ["open", url]);

  // Get the title
  const t = await sandbox.runCommand("chrome-use", ["get", "title", "--json"]);
  const title = JSON.parse(await t.stdout())?.data?.title || url;

  // Screenshot → read file → base64
  const ss = await sandbox.runCommand("chrome-use", ["screenshot", "--json"]);
  const ssPath = JSON.parse(await ss.stdout())?.data?.path;
  const b64 = await sandbox.runCommand("base64", ["-w", "0", ssPath]);

  await sandbox.runCommand("chrome-use", ["close"]);
  return { title, screenshot: (await b64.stdout()).trim() };
});

Multi-step form flows

Because the sandbox persists across commands, a full automation — fill → submit → wait for load → screenshot — runs in one go. A typical sequence is opensnapshot -i to get element @refs → fill each one → clickwait --load networkidle:

fillAndSubmitForm.ts
await sandbox.runCommand("chrome-use", ["open", url]);
const snap = await sandbox.runCommand("chrome-use", ["snapshot", "-i"]);
// Parse the snapshot to get each field's ref…

for (const [ref, value] of Object.entries(data)) {
  await sandbox.runCommand("chrome-use", ["fill", ref, value]);
}

await sandbox.runCommand("chrome-use", ["click", "@e5"]);
await sandbox.runCommand("chrome-use", ["wait", "--load", "networkidle"]);

Sandbox snapshots: sub-second cold starts

A sandbox snapshot is a VM image with the system libraries + chrome-use + Chromium already installed, much like a Docker image: on boot it starts straight from the image instead of installing everything from scratch each time. Without a snapshot, every run installs dependencies + chrome-use + Chromium (about 30 seconds); with a snapshot, startup drops into sub-second territory.

⚠️ Don't confuse the two "snapshots"
A sandbox snapshot is a Vercel infrastructure concept, used to start VMs quickly; it's an entirely different thing from chrome-use's accessibility snapshot (chrome-use snapshot, which exports the page's a11y tree).

Create a snapshot once, then store the returned ID in an environment variable:

bash
# The repo demo ships a ready-made creation script
$ npx tsx examples/environments/scripts/create-snapshot.ts

# The script returns a snapshotId; write it into an env var
$ AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx
✅ Recommended for production
Any production deployment on the Sandbox path should pre-build a snapshot to squeeze cold starts from 30 seconds down to sub-second.

Authentication

When deployed on Vercel, the Sandbox SDK authenticates automatically via OIDC — no extra configuration needed. For local development or when you need explicit control, set the following three variables; they're spread into Sandbox.create(), and when absent the SDK falls back to the auto-injected VERCEL_OIDC_TOKEN:

.env (local development)
VERCEL_TOKEN=<personal-access-token>
VERCEL_TEAM_ID=<team-id>
VERCEL_PROJECT_ID=<project-id>

Scheduled jobs (Cron)

Wire withBrowser into Vercel Cron Jobs to run periodic browser tasks — for example, scrape a pricing page every morning at 9 and compare it for alerts:

vercel.json
{ "crons": [{ "path": "/api/cron", "schedule": "0 9 * * *" }] }

Vercel environment variables at a glance

VariableRequiredDescription
AGENT_BROWSER_SNAPSHOT_IDNo (recommended)Pre-built sandbox snapshot ID, for sub-second startup
VERCEL_TOKENNoVercel personal access token (for local dev; automatic via OIDC on Vercel)
VERCEL_TEAM_IDNoVercel team ID (for local dev)
VERCEL_PROJECT_IDNoVercel project ID (for local dev)

The same pattern is written identically across frameworks — only the location of the server-side code differs: Next.js uses server actions / route handlers, SvelteKit uses +page.server.ts / +server.ts, Nuxt uses server/api/, Remix uses loader / action, and Astro uses .astro frontmatter or API routes. A full runnable example lives upstream in agent-browser's examples/environments/ (not vendored here; see Lineage & Upstream).


AWS Bedrock AgentCore: managed cloud browser

AgentCore runs the browser session as a managed service on AWS, and the usage of every chrome-use command is completely unchanged — the only difference is that the browser runs on AWS. Just add a -p agentcore and everything else stays the same:

bash
# Open a page on the AgentCore cloud browser
$ chrome-use -p agentcore open https://example.com

# From here on, exactly like local Chrome
$ chrome-use snapshot -i
$ chrome-use click @e1
$ chrome-use screenshot page.png
$ chrome-use close

Credential resolution

AWS credentials are resolved automatically; when usable credentials already exist, no extra configuration is needed. The resolution order is:

bash
# Explicit credentials (CI/CD, scripts)
$ export AWS_ACCESS_KEY_ID=AKIA...
$ export AWS_SECRET_ACCESS_KEY=...
$ chrome-use -p agentcore open https://example.com

# SSO (interactive)
$ aws sso login --profile my-profile
$ AWS_PROFILE=my-profile chrome-use -p agentcore open https://example.com

# IAM role / default credential chain
$ chrome-use -p agentcore open https://example.com

Persistent profiles: keep the login

Use AGENTCORE_PROFILE_ID to persist browser state (cookies, localStorage) across sessions — perfect for keeping a login alive: run the login flow once, and every run after that is already logged in. For a fuller take on login and session reuse, see Sessions and Login & auth.

bash
# First time: log in
$ AGENTCORE_PROFILE_ID=my-app chrome-use -p agentcore open https://app.example.com/login
$ chrome-use snapshot -i
$ chrome-use fill @e1 "user@example.com"
$ chrome-use fill @e2 "password"
$ chrome-use click @e3
$ chrome-use close

# Later: already logged in
$ AGENTCORE_PROFILE_ID=my-app chrome-use -p agentcore open https://app.example.com/dashboard

Live View: watch it in the console in real time

When a session starts, AgentCore prints a Live View URL to stderr. Open it in a browser and you can watch this session's screen live from the AWS console — especially handy when debugging headless flows:

stderr
Session: abc123-def456
Live View: https://us-east-1.console.aws.amazon.com/bedrock-agentcore/browser/aws.browser.v1/session/abc123-def456#

Pick a region / set the provider via env var

The default region is us-east-1; switch it explicitly with AGENTCORE_REGION. If you don't want to add -p agentcore on every command, set AGENT_BROWSER_PROVIDER:

bash
# Explicit region
$ AGENTCORE_REGION=eu-west-1 chrome-use -p agentcore open https://example.com

# Pin the provider via env var so commands no longer need -p
$ export AGENT_BROWSER_PROVIDER=agentcore
$ export AGENTCORE_REGION=us-east-2
$ chrome-use open https://example.com
$ chrome-use snapshot -i
$ chrome-use close

AgentCore environment variables at a glance

VariableDescriptionDefault
AGENTCORE_REGIONAWS regionus-east-1
AGENTCORE_BROWSER_IDBrowser identifieraws.browser.v1
AGENTCORE_PROFILE_IDPersistent browser profile (cookies, localStorage)(none)
AGENTCORE_SESSION_TIMEOUTSession timeout (seconds)3600
AWS_PROFILEAWS CLI profile used for credential resolutiondefault

Common issues

⚠️ Troubleshooting checklist
  • Failed to run aws CLI: the AWS CLI isn't installed or isn't on PATH. Install it, or just set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
  • AWS CLI failed: ... Run 'aws sso login': SSO credentials expired; run aws sso login once to refresh.
  • Session timeout: the default is 3600 seconds (1 hour). For long tasks, extend it with AGENTCORE_SESSION_TIMEOUT=7200.

How to choose between the two paths

Vercel Sandbox

Choose it when you already deploy your app on Vercel, want on-demand microVMs that spin up and tear down, and don't want to be blocked by the serverless binary size limit. Use a sandbox snapshot for second-scale cold starts.

☁︎ AWS Bedrock AgentCore

Choose it when you live in the AWS ecosystem, want a managed cloud browser session, need a persistent profile to keep a login alive, or want to watch a session live in the console via Live View. The command-line experience is no different from local.

ℹ️ Related reading
To drive local Chrome instead of the cloud, see Connect to real Chrome; for the general approach to reusing a login across sessions, see Sessions.