> ## Documentation Index
> Fetch the complete documentation index at: https://docs-preview.webcompute.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Production architecture

> Design agentic web workflows as inspectable jobs with managed browsers, policy, validation, retries, artifacts, and recovery paths.

Treat an agentic web workflow as an inspectable job. A production workflow should create or reuse a managed browser, run the agent inside a clear policy boundary, store the result and evidence, then decide whether the browser should close or continue.

## Recommended shape

<Steps>
  <Step title="Create a job">
    Store the user request, target URLs, policy boundary, timeout, and output shape in your application.
  </Step>

  <Step title="Run browser work">
    Use `web.agent()` for the agent-driven browser work. Use SDK resources around it for setup, validation, downloads, recordings, retries, and recovery.
  </Step>

  <Step title="Capture evidence">
    Store the final result, browser ID, status, artifacts, downloads, recordings, events, and redacted errors that matter for review.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Clean up">
    Close browsers your application creates unless the workflow intentionally needs continuity.
  </Step>
</Steps>

## Browser-agent job

```ts theme={null}
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,
});
```

## Browser-agent job with deterministic resources

```ts theme={null}
const workflowAgent = web.agent({
  model,
  approval: "ask",
});

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

try {
  const result = await workflowAgent.run({
    browserId: browser.id,
    startUrl: "https://vendor.example/dashboard",
    goal: "Find the latest paid invoice and download the PDF.",
  });

  const downloads = await browser.downloads.list();

  await saveJobResult({
    status: result.status,
    text: result.text,
    browserId: result.browserId,
    downloads: downloads.data,
  });
} finally {
  await browser.close();
}
```

For existing-browser runs, configure browser policy on `web.browser.create(...)`, not on the agent. Agent-level browser policy applies when the agent creates the browser.

## Deterministic browser job

Use exact browser-code execution when a specific step must be deterministic or an existing browser framework owns the task.

```ts theme={null}
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.

| State                | Use when                                                                                | User-facing language                                                |
| -------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `completed`          | The workflow returned valid output and required evidence.                               | "Finished. Review the result and source links."                     |
| `blocked`            | The site, policy, CAPTCHA, auth wall, or required user input prevented safe completion. | "The browser reached a blocker and needs review."                   |
| `needs_confirmation` | The workflow reached a high-impact action, credential step, or ambiguous submission.    | "Review and approve the next action."                               |
| `failed`             | The run hit an unrecoverable platform, validation, or workflow error.                   | "The browser job failed. Review evidence and retry if appropriate." |
| `cancelled`          | The user or system cancelled the job.                                                   | "The job was cancelled."                                            |
| `timed_out`          | The 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](/production/policy-and-proxy), [observability](/production/observability), [errors and retries](/production/errors-and-retries), and [limits](/reference/limits).
