Skip to main content
Treat browser work as a job with evidence. A production workflow should create or reuse a browser, run delegated or deterministic steps, store the result and artifacts, then clean up the browser.
1

Create a job

Store the user request, target URLs, policy boundary, timeout, and output shape in your application.
2

Run browser work

Use web.agent() for delegated browsing, browser.playwright.execute() for deterministic steps, or MCP runtime tools for coding-agent hosts.
3

Capture evidence

Store the final result, browser ID, status, artifacts, downloads, recordings, events, and redacted errors that matter for review.
4

Handle retries

Retry transient infrastructure or timeout failures with a fresh browser when needed. Do not blindly retry policy denials, approval denials, or blocker states.
5

Clean up

Close browsers your application creates unless the workflow intentionally needs continuity.

Delegated browser job

import { Web } from "@webcompute/sdk";

const web = new Web();

const agent = web.agent({
  model: {
    route: "openrouter",
    model: "openai/gpt-5.4-mini",
    apiKeyEnv: "OPENROUTER_API_KEY",
  },
  browser: {
    create: { recording: true },
    policy: { allowedDomains: ["sec.gov"] },
  },
  approval: "ask",
  timeoutMs: 180_000,
});

const result = await agent.run({
  startUrl: "https://www.sec.gov/edgar/search/",
  goal: "Find Apple's latest 10-Q filing and return filing metadata.",
});

await saveJobResult({
  status: result.status,
  text: result.text,
  output: result.output,
  browserId: result.browserId,
  artifacts: result.artifacts,
});

Deterministic browser job

import { Web } from "@webcompute/sdk";

const web = new Web();

const browser = await web.browser.create({
  recording: true,
  policy: { allowedDomains: ["example.com"] },
});

try {
  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" } },
  });

  await saveJobResult({
    status: result.status,
    output: result.result,
    observation: result.observation,
  });
} finally {
  await browser.close();
}
saveJobResult represents your application’s persistence layer.

What your app should own

Webcompute runs browser sessions and returns evidence. Your application should own queueing, job IDs, user authorization, result persistence, retries, notifications, and any human review workflow.

User-visible job states

Map browser evidence into a small set of product states your users and operators can understand.
StateUse whenUser-facing language
completedThe workflow returned valid output and required evidence.”Finished. Review the result and source links.”
blockedThe site, policy, CAPTCHA, auth wall, or required user input prevented safe completion.”The browser reached a blocker and needs review.”
needs_confirmationThe workflow reached a high-impact action, credential step, or ambiguous submission.”Review and approve the next action.”
failedThe run hit an unrecoverable platform, validation, or workflow error.”The browser job failed. Review evidence and retry if appropriate.”
cancelledThe user or system cancelled the job.”The job was cancelled.”
timed_outThe job exceeded its budget.”The browser job timed out before completion.”
Do not turn blocked, needs_confirmation, policy denial, or CAPTCHA state into completed. Store the evidence and return the next safe action.

What to show after a blocker

When a browser job stops on a blocker, show:
  • The target site or final URL.
  • The blocker category when available.
  • The last safe status.
  • Whether a recording, screenshot, artifact, or download is available for review.
  • A retry or human-review option only when it is safe.
Do not expose signed Debug UI URLs, signed CDP URLs, cookies, provider keys, or raw page observations to end users by default. Reference: policy and proxy, observability, errors and retries, and limits.