Back to Agent Browser

Next.js + Vercel

docs/src/app/next/page.mdx

0.29.05.0 KB
Original Source

Next.js + Vercel

Run agent-browser from a Next.js app on Vercel using Vercel Sandbox. A Linux microVM spins up on demand, runs agent-browser + Chrome, and shuts down. No binary size limits, no Chromium bundling complexity.

Setup

bash
pnpm add @agent-browser/sandbox @vercel/sandbox

Server action

The Vercel Sandbox runs Amazon Linux. Chromium requires system libraries that are not installed by default, so fresh sandboxes need a dnf install step before agent-browser can launch Chrome. Use a sandbox snapshot (below) to skip this entirely in production. The @agent-browser/sandbox helper handles the bootstrap and command execution.

ts
"use server";
import { runAgentBrowserCommand, withAgentBrowserSandbox } from "@agent-browser/sandbox/vercel";

export async function screenshotUrl(url: string) {
  return withAgentBrowserSandbox(async (sandbox) => {
    await runAgentBrowserCommand(sandbox, ["open", url]);

    const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
      "screenshot",
    ]);
    const ssPath = ssResult.json?.data?.path;
    if (!ssPath) throw new Error("Screenshot did not return a file path.");

    const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
    const screenshot = (await b64Result.stdout()).trim();
    await runAgentBrowserCommand(sandbox, ["close"], { json: false });
    return { ok: true, screenshot };
  });
}

export async function snapshotUrl(url: string) {
  return withAgentBrowserSandbox(async (sandbox) => {
    await runAgentBrowserCommand(sandbox, ["open", url]);

    const result = await runAgentBrowserCommand(sandbox, ["snapshot", "-i", "-c"], {
      json: false,
    });

    await runAgentBrowserCommand(sandbox, ["close"], { json: false });
    return { ok: true, snapshot: result.stdout };
  });
}

Sandbox snapshots

Without optimization, each Sandbox run installs system dependencies + agent-browser + Chromium from scratch (~30 seconds). A sandbox snapshot is a saved VM image with everything pre-installed, similar to a Docker image for Vercel Sandbox. When AGENT_BROWSER_SNAPSHOT_ID is set, the sandbox boots from that image instead of installing, bringing startup down to sub-second.

This is different from an agent-browser accessibility snapshot (which dumps a page's accessibility tree). A sandbox snapshot is a Vercel infrastructure concept.

Create a sandbox snapshot by running the helper script once:

bash
npx tsx scripts/create-snapshot.ts

The script spins up a fresh sandbox, installs system dependencies + agent-browser + Chromium, saves the VM state, and prints the snapshot ID:

AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx

Add this to your Vercel project environment variables (or .env.local for local development). Recommended for any production deployment.

Authentication

On Vercel deployments, the Sandbox SDK authenticates automatically via OIDC. For local development, provide explicit credentials:

<table> <thead> <tr><th>Variable</th><th>Description</th></tr> </thead> <tbody> <tr><td><code>VERCEL_TOKEN</code></td><td>Vercel personal access token</td></tr> <tr><td><code>VERCEL_TEAM_ID</code></td><td>Vercel team ID</td></tr> <tr><td><code>VERCEL_PROJECT_ID</code></td><td>Vercel project ID</td></tr> </tbody> </table>

When all three are set, they are passed to Sandbox.create(). When absent, the SDK falls back to VERCEL_OIDC_TOKEN (automatic on Vercel).

Scheduled workflows (cron)

For recurring tasks like daily monitoring, use Vercel Cron Jobs:

ts
// app/api/cron/monitor/route.ts
import { runAgentBrowserCommand, withAgentBrowserSandbox } from "@agent-browser/sandbox/vercel";

export async function GET() {
  const result = await withAgentBrowserSandbox(async (sandbox) => {
    await runAgentBrowserCommand(sandbox, [
      "open", "https://example.com/pricing",
    ]);
    const snap = await runAgentBrowserCommand(sandbox, [
      "snapshot", "-i", "-c",
    ], { json: false });
    await runAgentBrowserCommand(sandbox, ["close"], { json: false });
    return snap.stdout;
  });

  // Process results, send alerts, store data...
  return Response.json({ ok: true, snapshot: result });
}
json
// vercel.json
{
  "crons": [
    { "path": "/api/cron/monitor", "schedule": "0 9 * * *" }
  ]
}

Environment variables

<table> <thead> <tr><th>Variable</th><th>Description</th></tr> </thead> <tbody> <tr><td><code>AGENT_BROWSER_SNAPSHOT_ID</code></td><td>Sandbox snapshot ID for sub-second startup (see above)</td></tr> <tr><td><code>VERCEL_TOKEN</code></td><td>Vercel personal access token (for local dev; OIDC is automatic on Vercel)</td></tr> <tr><td><code>VERCEL_TEAM_ID</code></td><td>Vercel team ID (for local dev)</td></tr> <tr><td><code>VERCEL_PROJECT_ID</code></td><td>Vercel project ID (for local dev)</td></tr> </tbody> </table>

Demo app

A working demo with streaming progress UI, rate limiting, and a deploy-to-Vercel button is at examples/environments/.