> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.modbox.run/llms.txt.
> For full documentation content, see https://docs.modbox.run/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.modbox.run/_mcp/server.

# Browser Automation

Modbox browser sandboxes run a full Chromium instance with a VNC display and Chrome DevTools Protocol (CDP) endpoint exposed over HTTPS. You can connect any automation library — Playwright, Puppeteer, or an AI browser agent — to the sandbox URL.

## Use cases

* 🤖 **AI browser agents** — Connect an LLM to a live browser (like [Browser Use](https://github.com/browser-use/browser-use) or OpenAI's CUA)
* 🔍 **Web scraping** — Run authenticated scraping jobs in isolated containers
* 🧪 **E2E testing** — Spin up fresh browsers for parallel test runs
* 📸 **Screenshot / PDF generation** — Render pages headlessly and export

## How it works

A Modbox browser sandbox exposes:

* **CDP endpoint** at `wss://your-sandbox.modbox.run/cdp` — connect Playwright, Puppeteer, or any CDP client
* **VNC viewer** at `https://your-sandbox.modbox.run` — watch the browser in real time via your browser

## Example: Playwright with a Modbox sandbox

```typescript
import { chromium } from "playwright";
import { ModboxClient } from "modbox-sdk";

const modbox = new ModboxClient({ token: process.env.MODBOX_API_TOKEN });

async function scrapeWithSandbox(url: string) {
  const taskId = `scrape-${Date.now()}`;

  // 1. Provision the browser sandbox
  await modbox.provisionSandbox({
    taskId,
    imageId: process.env.BROWSER_IMAGE_ID, // Modbox Chromium image
    ttlSeconds: 300,
  });

  await modbox.waitForSandbox({ taskId, timeout: 60 });
  const sandbox = await modbox.getSandbox(taskId);

  // 2. Connect Playwright to the sandbox CDP endpoint
  const browser = await chromium.connectOverCDP(
    `wss://${new URL(sandbox.sandboxUrl).host}/cdp`
  );

  const page = await browser.newPage();

  // 3. Do your automation
  await page.goto(url);
  const title = await page.title();
  const content = await page.content();

  await browser.close();

  // 4. Clean up
  await modbox.destroySandbox({ taskId });

  return { title, content };
}
```

```python
from playwright.async_api import async_playwright
from modbox import ModboxClient
from urllib.parse import urlparse
import os, time

modbox = ModboxClient(token=os.environ["MODBOX_API_TOKEN"])

async def scrape_with_sandbox(url: str) -> dict:
    task_id = f"scrape-{int(time.time())}"

    # 1. Provision the browser sandbox
    modbox.provision_sandbox(
        task_id=task_id,
        image_id=os.environ["BROWSER_IMAGE_ID"],
        ttl_seconds=300,
    )
    modbox.wait_for_sandbox(task_id=task_id, timeout=60)
    sandbox = modbox.get_sandbox(task_id)

    # 2. Connect Playwright to the CDP endpoint
    host = urlparse(sandbox.sandbox_url).netloc
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(f"wss://{host}/cdp")
        page = await browser.new_page()
        await page.goto(url)
        title = await page.title()
        await browser.close()

    # 3. Clean up
    modbox.destroy_sandbox(task_id=task_id)
    return {"title": title}
```

## Example: AI browser agent

Connect an LLM-powered agent to a live Chromium sandbox:

```typescript
import { ModboxClient } from "modbox-sdk";
import { Agent } from "browser-use"; // or your preferred AI browser agent

const modbox = new ModboxClient({ token: process.env.MODBOX_API_TOKEN });

async function runBrowserAgent(task: string) {
  const taskId = `browser-agent-${Date.now()}`;

  await modbox.provisionSandbox({
    taskId,
    imageId: process.env.BROWSER_IMAGE_ID,
    ttlSeconds: 900, // 15 minutes for complex tasks
  });

  await modbox.waitForSandbox({ taskId, timeout: 60 });
  const sandbox = await modbox.getSandbox(taskId);

  // Connect the AI agent to the live browser
  const agent = new Agent({
    task,
    cdpUrl: `wss://${new URL(sandbox.sandboxUrl).host}/cdp`,
    llm: yourLLMClient,
  });

  const result = await agent.run();

  await modbox.destroySandbox({ taskId });
  return result;
}
```

## Parallel browser jobs

Provision multiple sandboxes in parallel for high-throughput scraping or test runs:

```typescript
const urls = ["https://example.com", "https://example.org", "https://example.net"];

// Provision all sandboxes in parallel
const sandboxes = await Promise.all(
  urls.map((url, i) =>
    modbox.provisionSandbox({ taskId: `scrape-${i}`, ttlSeconds: 120 })
  )
);

// Wait for all to be ready
await Promise.all(
  sandboxes.map((s) => modbox.waitForSandbox({ taskId: s.taskId }))
);

// Run scraping jobs in parallel
const results = await Promise.all(
  sandboxes.map((s, i) => scrapeUrl(s.sandboxUrl, urls[i]))
);
```