Vercel Sandbox를 사용한 브라우저 자동화
일시적인 Vercel Sandbox 마이크로VM 내에서 agent-browser + 헤드리스 Chrome을 실행합니다. Linux VM이 요청 시 생성되어 브라우저 명령을 실행하고 종료됩니다. 모든 Vercel 배포 프레임워크(Next.js, SvelteKit, Nuxt, Remix, Astro 등)에서 작동합니다.
종속성
pnpm add @agent-browser/sandbox @vercel/sandbox
Sandbox VM은 Chromium 시스템 종속성과 agent-browser 자체가 필요합니다. @agent-browser/sandbox 헬퍼는 기본적으로 새 Sandbox에 이를 설치하며, 아래 설명된 Sandbox 스냅샷을 사용하여 1초 미만의 시작 시간을 구현합니다. Sandbox 이미지에 이미 Chromium 필수 라이브러리가 포함된 경우에만 installSystemDependencies: false를 전달하세요.
핵심 패턴
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 --json 명령은 파일로 저장하고 경로를 반환합니다. 파일을 base64로 다시 읽습니다:
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("스크린샷이 파일 경로를 반환하지 않았습니다.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, screenshot };
});
}
접근성 스냅샷
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 };
});
}
다단계 워크플로우
Sandbox는 명령 간에 지속되므로 전체 자동화 시퀀스를 실행할 수 있습니다:
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;
// 스냅샷을 파싱하여 요소 참조를 찾습니다...
for (const [ref, value] of Object.entries(data)) {
await runAgentBrowserCommand(sandbox, ["fill", ref, value]);
}
await runAgentBrowserCommand(sandbox, ["click", "@e5"]);
// 앱별 대기를 전달합니다. 예: ["--url", "**/checkout/complete"],
// ["--text", "Thanks"], 또는 ["#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("스크린샷이 파일 경로를 반환하지 않았습니다.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { screenshot };
});
}
Sandbox 스냅샷 (빠른 시작)
Sandbox 스냅샷은 시스템 종속성 + agent-browser + Chromium이 이미 설치된 Vercel Sandbox의 저장된 VM 이미지입니다. Docker 이미지와 비슷하다고 생각하면 됩니다. 매번 처음부터 종속성을 설치하는 대신 Sandbox가 미리 빌드된 이미지에서 부팅됩니다.
이는 agent-browser의 접근성 스냅샷 기능(agent-browser snapshot)과 관련이 없습니다. agent-browser의 접근성 스냅샷은 페이지의 접근성 트리를 덤프합니다. Sandbox 스냅샷은 빠른 VM 시작을 위한 Vercel 인프라 개념입니다.
Sandbox 스냅샷이 없으면 각 실행 시 시스템 종속성 + agent-browser + Chromium을 설치합니다(~30초). 스냅샷이 있으면 시작 시간이 1초 미만입니다.
Sandbox 스냅샷 생성
스냅샷에는 시스템 종속성(dnf 통해), agent-browser 및 Chromium이 포함되어야 합니다:
const snapshotId = await createAgentBrowserSnapshot();
이것을 한 번 실행한 후 환경 변수를 설정합니다:
AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx
데모 앱에서 헬퍼 스크립트를 사용할 수 있습니다:
npx tsx examples/environments/scripts/create-snapshot.ts
Sandbox 패턴을 사용하는 모든 프로덕션 배포에 권장됩니다.
인증
Vercel 배포에서 Sandbox SDK는 OIDC를 통해 자동으로 인증됩니다. 로컬 개발 또는 명시적 제어를 위해 다음을 설정합니다:
VERCEL_TOKEN=<개인-액세스-토큰>
VERCEL_TEAM_ID=<팀-id>
VERCEL_PROJECT_ID=<프로젝트-id>
이 값들은 Sandbox.create() 호출에 전달됩니다. 존재하지 않으면 SDK는 VERCEL_OIDC_TOKEN으로 대체됩니다(Vercel에서 자동 처리).
예약 워크플로우 (Cron)
반복적인 브라우저 작업을 위해 Vercel Cron Jobs와 결합합니다:
// app/api/cron/route.ts (또는 프레임워크에 맞는 경로)
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();
});
// 결과 처리, 알림 전송, 데이터 저장...
return Response.json({ ok: true, snapshot: result });
}
// vercel.json
{ "crons": [{ "path": "/api/cron", "schedule": "0 9 * * *" }] }
환경 변수
| 변수 | 필수 | 설명 |
|---|---|---|
AGENT_BROWSER_SNAPSHOT_ID | 아니요 (권장) | 1초 미만 시작을 위한 사전 빌드된 Sandbox 스냅샷 ID (위 참조) |
VERCEL_TOKEN | 아니요 | Vercel 개인 액세스 토큰 (로컬 개발용; Vercel에서는 OIDC가 자동) |
VERCEL_TEAM_ID | 아니요 | Vercel 팀 ID (로컬 개발용) |
VERCEL_PROJECT_ID | 아니요 | Vercel 프로젝트 ID (로컬 개발용) |
프레임워크 예제
패턴은 모든 프레임워크에서 동일하게 작동합니다. 유일한 차이점은 서버 측 코드를 배치하는 위치입니다:
| 프레임워크 | 서버 코드 위치 |
|---|---|
| Next.js | 서버 액션, API 라우트, 라우트 핸들러 |
| SvelteKit | +page.server.ts, +server.ts |
| Nuxt | server/api/, server/routes/ |
| Remix | loader, action 함수 |
| Astro | .astro frontmatter, API 라우트 |
예제
작동하는 앱, Sandbox 스냅샷 생성 스크립트, 스트리밍 진행 UI 및 속도 제한을 포함한 Vercel Sandbox 패턴의 전체 예제는 agent-browser 저장소의 examples/environments/를 참조하세요.