Clients

Agent integrations

BrowserView is deliberately protocol-boring: if your agent framework can hold a Playwright or Puppeteer browser, it can hold a BrowserView session. These are the patterns that work well.

pilot — natural-language driving

pilot is BrowserView's own Python agent: four verbs over a Playwright page that lives in a cloud session. It runs on your machine, uses your own model key (ANTHROPIC_API_KEY or OPENAI_API_KEY; default model claude-sonnet-5, override with PILOT_MODEL), and reads BROWSERVIEW_API_KEY like the SDKs. It is not on PyPI yet — install from the pilot repository checkout with pip install -r requirements.txt (Python 3.10+, no local Chromium needed).

pilot.py
import pilotfrom pydantic import BaseModel class Story(BaseModel):    title: str    points: int async with pilot.launch(start_url="https://news.ycombinator.com") as page:    print(page.viewer_url)                        # watch the agent live     await page.act("click the 'new' link")        # exactly one action    story = await page.extract("the top story", schema=Story)    options = await page.observe("ways to sort the list")   # plan, don't execute    result = await page.run(        "open the comments of the top story and report the top comment",        max_steps=20,    )    print(result.success, result.answer)    # page.pw is the underlying Playwright page for anything else
  • launch(start_url, api, width, height, model, keep, api_key, vision, allowed_domains) creates a session and destroys it on exit (unless keep=True); attach(session_id, …) drives an existing session — for example one a human already has open — and never destroys it.
  • act performs one action and raises ActError if it fails; extract returns JSON or a validated pydantic instance; observe returns candidate actions you can pass to perform; run loops up to max_steps and returns a RunResult with the step transcript.
  • allowed_domains refuses model-chosen navigation outside the list; vision=False runs text-only for cheaper, non-multimodal models.

Claude / Anthropic

Give Claude browsing tools implemented on a Playwright page that lives in a BrowserView session. The human watches the viewer while Claude works, and can take over with a control token when the agent needs help (logins, CAPTCHAs, judgment calls).

claude-agent.ts
import Anthropic from "@anthropic-ai/sdk";import { BrowserView } from "@browserview/typescript";import { chromium } from "playwright"; const bv = new BrowserView();const session = await bv.sessions.create();console.log("watch:", session.viewer_url); const browser = await chromium.connectOverCDP(session.cdp_url, {  headers: { "x-session-token": session.cdp_token },});const page = browser.contexts()[0].pages()[0]; // Expose navigate/click/type/screenshot tools over `page` to Claude// with client.beta.messages.toolRunner — the human sees every action// live in the viewer.

If you use Claude Code or another MCP-capable agent, the MCP server gives it session management without any glue code.

OpenAI

The same shape works with the OpenAI Agents SDK or a raw tool loop: keep the Playwright page as shared state, implement browsing actions as function tools, and surface viewer_url in your product UI.

openai-agent.py
from browserview import BrowserViewfrom playwright.sync_api import sync_playwright bv = BrowserView()session = bv.create_session()print("watch:", session.viewer_url) with sync_playwright() as p:    browser = p.chromium.connect_over_cdp(        session.cdp_url,        headers={"x-session-token": session.cdp_token})    page = browser.contexts[0].pages[0]    # Register navigate/click/type/screenshot as function tools    # for the OpenAI Agents SDK, all operating on `page`.

Human handoff

The highest-leverage pattern BrowserView enables: when the agent gets stuck, don't fail the run — ask a person.

  • Embed viewer_url (control scope) in an iframe in your product, or send it in Slack.
  • The person completes the login / CAPTCHA / ambiguous step in the live browser.
  • The agent resumes on the same page — cookies, storage, and state intact, because it never left the browser.

For read-only observers (support, audits, demos), share watch_url instead: view-scope tokens have their input stripped server-side, so spectators cannot interfere.

Session hygiene

  • Create one session per task and destroy it when the task ends — sessions are cheap and disposable by design.
  • Treat 429 with Retry-After as backpressure, not failure.
  • Don't ship your API key to browsers or agents running on user machines — mint scoped session tokens server-side and hand those out instead.