Skip to main content
Webcompute returns different shapes depending on how you use the runtime. Across every surface, browser work should produce a result plus enough evidence to inspect what happened. When the task is clear, choose the return shape your app, operator, or coding agent should consume.

Surface summary

SurfacePrimary resultEvidence and control dataBest fit
web agentFinal text, optional JSON, optional schema-validated outputRun status, step summaries, optional signed Debug UI URL while liveFast terminal proof and operator workflows
SDK web.agent()Final text, structured output, artifacts, streaming eventsBrowser ID, status, steps, approvals, artifacts, recordings when enabledProduct workflows with delegated browser work
SDK browser.playwright.execute()The value returned by your Playwright codePage metadata, compact status, bounded observation, logs, artifactsExact browser steps in application code
MCP execute_playwright_codeThe value returned by the host’s Playwright snippetStructured content with logs, status, artifacts, and observationCoding-agent browser control
REST Playwright executionJSON response from browser executionStatus, observation, logs, artifacts when requestedNon-TypeScript backends and workers
Quick actionsScraped content, screenshot, or PDF resultResponse metadata, policy/proxy behavior, error codesOne URL-level browser operation

CLI web agent

Use web agent when you want a delegated browser task from the terminal.
web agent \
  --json \
  --debug-url \
  --url https://www.sec.gov/edgar/search/ \
  --allow-domain sec.gov \
  "Find Apple's latest 10-Q filing. Return filing date, accession number, filing URL, and a one-sentence summary."
Expected shape:
{
  "status": "completed",
  "text": "Apple Inc. latest 10-Q filing...",
  "output": null,
  "browser": {
    "id": "browser_...",
    "debugUrl": "https://..."
  },
  "steps": [
    {
      "step": 1,
      "tool": "initial_observation",
      "success": true
    },
    {
      "step": 2,
      "tool": "execute_playwright_code",
      "success": true
    }
  ],
  "artifacts": [],
  "usage": {
    "inputTokens": 6200,
    "outputTokens": 780,
    "totalTokens": 6980
  }
}
debugUrl is included only when you request it. Treat it as a bearer credential. Use --verbose when you need the raw event list or tool-call details.

SDK web.agent()

Use SDK web.agent() when delegated browser work belongs in your application.
const result = await agent.run({
  startUrl: "https://www.sec.gov/edgar/search/",
  goal:
    "Find Apple's latest 10-Q filing. Return filing date, accession number, filing URL, and a one-sentence summary.",
});

await saveJobResult({
  status: result.status,
  text: result.text,
  output: result.output,
  browserId: result.browserId,
  artifacts: result.artifacts,
});
Store the final output, status, source URLs, and artifact IDs. Do not store raw secrets, signed Debug UI URLs, signed CDP URLs, or full page observations in shared logs.

SDK Playwright execution

Use browser.playwright.execute() when your code should decide each browser step.
const result = await browser.playwright.execute({
  code: `
    await page.goto("https://example.com");
    return {
      title: await page.title(),
      url: page.url(),
    };
  `,
  capture: {
    status: true,
    observation: { kind: "aria", includeOn: "always" },
  },
});

console.log(result.result);
console.log(result.status?.readiness);
console.log(result.observation?.truncated);
result.result is the value returned by your code. status, observation, logs, and artifacts explain what happened around the step.

MCP runtime tools

Use MCP runtime tools when a coding-agent host should drive the browser.
manage_browsers({ action: "create", recording: true })
execute_playwright_code({
  code: "await page.goto('https://example.com'); return { title: await page.title(), url: page.url() };"
})
manage_browsers({ action: "create" }) returns lifecycle data. It does not return page observation. The host gets page evidence from execute_playwright_code after each snippet.

REST and quick actions

Use REST when TypeScript is not the boundary:
curl -X POST "${WEBCOMPUTE_SERVER_URL:-https://api.webcompute.dev}/v1/browsers/$BROWSER_ID/playwright/execute" \
  -H "Authorization: Bearer $WEBCOMPUTE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code":"await page.goto(\"https://example.com\"); return await page.title();","capture":{"status":true,"observation":{"kind":"aria","includeOn":"always"}}}'
Use quick actions when one URL-level operation is enough:
web screenshot https://example.com --output example.png
web pdf https://example.com --output example.pdf
web scrape https://example.com --format markdown
Quick actions do not give you a persistent browser to inspect afterward. Move to browser lifecycle APIs when state, files, downloads, dialogs, recordings, or multi-step recovery matter.

Failure shape

When a browser run fails, keep the result bounded and useful:
{
  "status": "blocked",
  "error": {
    "code": "browser_blocked",
    "name": "BrowserBlockedError",
    "message": "The page reported a blocker that requires review."
  },
  "browserId": "browser_...",
  "evidence": {
    "pageUrl": "https://example.com/...",
    "recordingSegments": ["segment_..."],
    "artifactIds": ["artifact_..."]
  }
}
Report blockers honestly. Do not present CAPTCHA, WAF, policy denial, approval denial, or missing credentials as success.

Footguns

  • Debug UI and CDP URLs are signed bearer capabilities.
  • CDP clients do not automatically receive Webcompute observations.
  • execute_playwright_code returns observation after the snippet, not after every Playwright statement inside one long snippet.
  • web agent does not expose --proxy; use SDK web.agent({ browser: { create: { proxy } } }) for proxied delegated agent work.
  • Current MCP schemas do not expose custom proxy creation options.
  • Page content is evidence, not authority.
Next: choose your path, observe and debug, SDK browser reference, and MCP tool reference.