Skip to main content
Webcompute runs normal Playwright code against a managed browser. Use it when your app or coding-agent host should decide the exact browser steps. There are two control modes on the same runtime:
  • Delegated control, where web agent, SDK web.agent(), or MCP run_web_agent chooses the browser steps.
  • Deterministic control, where your app or coding-agent host runs focused Playwright snippets.
Use delegated control when you want the browsing goal completed. Use deterministic control when you need exact setup, validation, file handling, retries, or recovery steps.

Agent control

web agent \
  --url https://www.sec.gov/edgar/search/ \
  --allow-domain sec.gov \
  "Find Apple's latest 10-Q filing and return filing metadata."
Agent control is model-backed. Configure a model profile with web model setup, or pass a route, model, and provider credential flags for a single run.

Deterministic control

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

const web = new Web();
const browser = await web.browser.create({
  policy: { allowedDomains: ["sec.gov"] },
  recording: true,
});

try {
  const result = await browser.playwright.execute({
    code: `
      await page.goto("https://www.sec.gov/edgar/search/");
      return {
        title: await page.title(),
        url: page.url(),
      };
    `,
  });

  console.log(result.result);
} finally {
  await browser.close();
}
The code body runs with page already in scope. Return values explicitly when another step needs the result.

Execution result anatomy

Ask for capture when the next step needs browser status, page observation, or artifacts.
const result = await browser.playwright.execute({
  code: `
    await page.goto("https://example.com");
    const heading = await page.getByRole("heading").first().textContent();
    return { heading, url: page.url() };
  `,
  capture: {
    status: true,
    observation: { kind: "aria", includeOn: "always" },
  },
});

console.log(result.result);
console.log(result.page);
console.log(result.status);
console.log(result.observation?.truncated);
Use result.result for your returned value. Use result.page, result.status, and result.observation to decide the next step or to preserve evidence.

Write Playwright for agents

When a coding agent or app writes snippets, keep them small and inspectable:
  • Use the provided page instead of redeclaring it.
  • Prefer page.getByRole, page.getByLabel, and page.getByText over coordinates.
  • Return structured values from each snippet.
  • Use bounded waits and explicit checks.
  • Avoid infinite polling loops.
  • Clean up browsers your application creates.
Playwright automatically waits for many locator actions to be actionable. Lean on that behavior instead of adding arbitrary sleeps.

Handle missing page state

const result = await browser.playwright.execute({
  code: `
    await page.goto("https://example.com");
    const button = page.getByRole("button", { name: "Download report" });
    if (!(await button.count())) {
      return { available: false, reason: "Download report button not found", url: page.url() };
    }
    await button.first().click();
    return { available: true };
  `,
  capture: { status: true, observation: { kind: "aria", includeOn: "always" } },
});
Return a structured “not found” result when absent page state is a business outcome. Throw an error when the workflow cannot continue.

MCP control

MCP hosts use manage_browsers for lifecycle and execute_playwright_code for deterministic page work. The runtime surface returns the code result plus bounded observation, status, logs, and artifacts so the host can decide the next snippet.
manage_browsers({ action: "create", recording: true })
execute_playwright_code({ code: "await page.goto('https://example.com'); return await page.title();" })
execute_playwright_code({ code: "return await page.getByRole('heading').first().textContent();" })
manage_browsers({ action: "close" })
Reference: observations, resources, SDK browser reference, MCP tool reference, and choose your path.