Browser-Automatisierung mit Vercel Sandbox
Führe agent-browser + headless Chrome in flüchtigen Vercel Sandbox MicroVMs aus. Eine Linux-VM wird bei Bedarf gestartet, führt Browser-Befehle aus und fährt wieder herunter. Funktioniert mit jedem auf Vercel bereitgestellten Framework (Next.js, SvelteKit, Nuxt, Remix, Astro usw.).
Abhängigkeiten
pnpm add @agent-browser/sandbox @vercel/sandbox
Die Sandbox-VM benötigt Systemabhängigkeiten für Chromium sowie agent-browser selbst. Die @agent-browser/sandbox-Helfer installieren diese standardmäßig für neue Sandboxen und verwenden Sandbox-Snapshots (siehe unten) für einen Start unter einer Sekunde. Gib installSystemDependencies: false nur an, wenn das Sandbox-Image bereits die erforderlichen Chromium-Bibliotheken bereitstellt.
Kernmuster
import {
createAgentBrowserSnapshot,
runAgentBrowserCommand,
withAgentBrowserSandbox,
type VercelSandboxSession,
} from "@agent-browser/sandbox/vercel";
async function withBrowser<T>(
fn: (sandbox: VercelSandboxSession) => Promise<T>,
): Promise<T> {
return withAgentBrowserSandbox(fn);
}
Screenshot
Der Befehl screenshot --json speichert die Datei und gibt den Pfad zurück. Lies die Datei als Base64 aus:
export async function screenshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("Screenshot hat keinen Dateipfad zurückgegeben.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, screenshot };
});
}
Barrierefreiheits-Snapshot
export async function snapshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i", "-c"], {
json: false,
});
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, snapshot: snapResult.stdout };
});
}
Mehrstufige Workflows
Die Sandbox bleibt zwischen Befehlen bestehen, sodass du vollständige Automatisierungssequenzen ausführen kannst:
export async function fillAndSubmitForm(
url: string,
data: Record<string, string>,
postSubmitWaitArgs: string[],
) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i"], {
json: false,
});
const snapshot = snapResult.stdout;
// Snapshot parsen, um Element-Referenzen zu finden...
for (const [ref, value] of Object.entries(data)) {
await runAgentBrowserCommand(sandbox, ["fill", ref, value]);
}
await runAgentBrowserCommand(sandbox, ["click", "@e5"]);
// Übergib eine app-spezifische Wartezeit, z. B. ["--url", "**/checkout/complete"],
// ["--text", "Vielen Dank"] oder ["#confirmation"].
await runAgentBrowserCommand(sandbox, ["wait", ...postSubmitWaitArgs]);
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("Screenshot hat keinen Dateipfad zurückgegeben.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { screenshot };
});
}
Sandbox-Snapshots (Schneller Start)
Ein Sandbox-Snapshot ist ein gespeichertes VM-Image einer Vercel Sandbox, in dem bereits Systemabhängigkeiten + agent-browser + Chromium installiert sind. Stell es dir wie ein Docker-Image vor: Anstatt jedes Mal Abhängigkeiten von Grund auf zu installieren, startet die Sandbox aus dem vorgefertigten Image.
Dies ist nicht zu verwechseln mit der Barrierefreiheits-Snapshot-Funktion von agent-browser (agent-browser snapshot), die den Barrierefreiheitsbaum einer Seite ausgibt. Ein Sandbox-Snapshot ist ein Vercel-Infrastrukturkonzept für schnellen VM-Start.
Ohne Sandbox-Snapshot installiert jeder Durchlauf Systemabhängigkeiten + agent-browser + Chromium (~30s). Mit einem Snapshot erfolgt der Start in unter einer Sekunde.
Erstellen eines Sandbox-Snapshots
Der Snapshot muss Systemabhängigkeiten (über dnf), agent-browser und Chromium enthalten:
const snapshotId = await createAgentBrowserSnapshot();
Führe dies einmal aus und setze dann die Umgebungsvariable:
AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx
Ein Hilfsskript ist in der Demo-App verfügbar:
npx tsx examples/environments/scripts/create-snapshot.ts
Empfohlen für jede Produktionsbereitstellung, die das Sandbox-Muster verwendet.
Authentifizierung
Auf Vercel-Deployments authentifiziert sich das Sandbox SDK automatisch über OIDC. Für lokale Entwicklung oder explizite Steuerung setze:
VERCEL_TOKEN=<personal-access-token>
VERCEL_TEAM_ID=<team-id>
VERCEL_PROJECT_ID=<project-id>
Diese werden in Sandbox.create()-Aufrufe eingestreut. Fehlen sie, fällt das SDK auf VERCEL_OIDC_TOKEN zurück (automatisch auf Vercel).
Geplante Workflows (Cron)
Kombiniere mit Vercel Cron Jobs für wiederkehrende Browser-Aufgaben:
// app/api/cron/route.ts (oder Äquivalent in deinem Framework)
export async function GET() {
const result = await withBrowser(async (sandbox) => {
await sandbox.runCommand("agent-browser", ["open", "https://example.com/pricing"]);
const snap = await sandbox.runCommand("agent-browser", ["snapshot", "-i", "-c"]);
await sandbox.runCommand("agent-browser", ["close"]);
return await snap.stdout();
});
// Ergebnisse verarbeiten, Benachrichtigungen senden, Daten speichern...
return Response.json({ ok: true, snapshot: result });
}
// vercel.json
{ "crons": [{ "path": "/api/cron", "schedule": "0 9 * * *" }] }
Umgebungsvariablen
| Variable | Erforderlich | Beschreibung |
|---|---|---|
AGENT_BROWSER_SNAPSHOT_ID | Nein (aber empfohlen) | Vorgefertigte Sandbox-Snapshot-ID für subsekundenschnellen Start (siehe oben) |
VERCEL_TOKEN | Nein | Vercel Personal Access Token (für lokale Entwicklung; OIDC ist automatisch auf Vercel) |
VERCEL_TEAM_ID | Nein | Vercel Team-ID (für lokale Entwicklung) |
VERCEL_PROJECT_ID | Nein | Vercel Projekt-ID (für lokale Entwicklung) |
Framework-Beispiele
Das Muster funktioniert frameworksübergreifend identisch. Der einzige Unterschied ist der Ort des serverseitigen Codes:
| Framework | Ort des Server-Codes |
|---|---|
| Next.js | Server Actions, API-Routen, Route Handler |
| SvelteKit | +page.server.ts, +server.ts |
| Nuxt | server/api/, server/routes/ |
| Remix | loader-, action-Funktionen |
| Astro | .astro-Frontmatter, API-Routen |
Beispiel
Siehe examples/environments/ im agent-browser-Repository für eine funktionierende App mit dem Vercel Sandbox-Muster, einschließlich eines Skripts zur Erstellung des Sandbox-Snapshots, einer Streaming-Progress-UI und Rate-Limiting.