--- name: browser description: >- Interactive Chromium sessions for reading and driving real web pages: open a URL, read the page as text, click and type, and read the page's own console and network history. Also scrapes: HTTP and browser fetching, screenshots, persistent sessions, crawling, and CSS/XPath/regex parsing of HTML you already have. Reach for it when a task involves a running web app, especially "why is this page broken", or when pulling data off the web. --- # browser The browser worker does two things. It runs real Chromium sessions on the bus (`browser::*`), and it parses HTML natively without a browser (`browser::*` — CSS/XPath/regex queries, element search, HTML→Markdown, over any HTML string you already have). Start a session, navigate, and the page becomes data: `browser::snapshot` returns an accessibility outline whose `[ref=eN]` handles feed straight into `browser::act`, and everything the page logs (console calls, uncaught exceptions, failed requests) is captured into per-session ring buffers you can query. This is the difference from one-shot fetching: the session stays alive, so you can act, observe the result, and read what the page said about it. Sessions are headless by default and cost a Chromium process each; the configured session cap is small. Stop sessions when a task is done. Refs die on navigation; re-snapshot before acting after any page change. ## When to Use - A web app misbehaves and you need the page's own evidence: read console errors and failed requests with `browser::console::read` / `browser::network::read` instead of guessing from source. - Verifying frontend work end to end: navigate to the dev server, act on the UI, snapshot the result. - Multi-step flows on a real page: forms, logins, anything that needs state to persist between steps. - Reading a page that only renders with JavaScript, when you also need to interact with it afterwards. - Live style experiments: `browser::styles::read` and `browser::styles::write` inspect and change an element's CSS in the running page without touching source files. ## Boundaries - Do not start a browser session just to read a page once. One-shot fetching is `browser::fetch` (no browser) or `browser::dynamic-fetch` (Chromium, when the page needs JS). Sessions are for flows that need state between steps. - Parsing HTML you already have needs neither a session nor a fetch: use the `browser::*` parse function below. Starting Chromium to run a CSS selector over a string you are already holding is pure waste. - `solve_cloudflare` is available on `browser::stealthy-fetch` and stealthy Scrapling sessions. Use `browser::handoff` for challenges in an interactive session or when automated solving does not clear the page. - Attach mode reaches the user's real browser profile with its logged-in sessions. It is disabled unless `allow_attach` is set, and adoption is exclusive (one session per tab) so two sessions never fight over a tab. Reach for a launched session when you do not specifically need the user's existing logins. - `browser::styles::write` edits are visual experiments only: they die on the next navigation and never touch source files. Use them to find the right value, then edit the codebase. - `browser::pick::*`, `browser::screencast::*`, and `browser::frame` are console-UI plumbing, not agent surface. - The ghost cursor and session-status badge are in-page overlays for a human watching the streamed viewport; they appear only while screencast is active and never affect page content or the accessibility snapshot. - Navigation is limited to the configured URL schemes (http/https by default). ## Functions - `browser::sessions::start` — open a browser tab; returns the session_id every other function needs. Tabs share one browser profile (cookies, logins) and stay open until stopped: an unused tab sleeps after a while and wakes on the next call, so keep using the same session_id instead of opening new ones. `read_only: true` opens an inspection-only tab. `ttl_ms` gives the tab a lifetime. `incognito: true` opens a PRIVATE tab: its own browser context, no shared logins, nothing saved to disk, no history, and inactivity closes it for good — use it when a login must not be kept. - `browser::sessions::list` — every tab, live or asleep (`active`), with its current URL and whether it is incognito. - `browser::sessions::stop` — close a tab for good; idempotent. An attached session closes only a tab it opened and releases an adopted user tab untouched. - `browser::sessions::attach` — bind a session to an already-running browser over CDP (start Chrome with `--remote-debugging-port`): open a fresh tab the session owns, or adopt an existing logged-in tab by URL substring. Off unless `allow_attach` is set in config. - `browser::tabs::list` — open tabs of a running browser at a CDP endpoint, with which are already adopted; read-only. - `browser::doctor` — read-only environment report: which Chromium would launch, its version, capacity, whether attach and recording are available, and anything degraded with how to enable it. - `browser::chromium::status` — read-only: whether a Chromium is found, its path, version and source, and whether a download is available here. - `browser::chromium::install` — download Chromium (~200 MB) when the machine has none; returns a `job_id` at once, progress on `browser::chromium-install-progress`. A session error starting with `chromium_missing:` means exactly this: tell the user, and offer the ADE's Set up the harness → Browser step or this call (it needs their approval). - `browser::recording::start` / `browser::recording::stop` — capture a session's live viewport to a webm or mp4 file via ffmpeg; stop returns the path, duration, and frame count. Requires ffmpeg on PATH. - `browser::navigate` — go to a URL and wait for the load. Like a browser, a network failure or an empty HTTP error response leaves Chromium's error page in the tab: the call returns `ok: false` with `error` set instead of failing, and the tab stays usable. - `browser::snapshot` — the page as an accessibility outline with `[ref=eN]` handles; the default way to read a page. `diff: true` returns only what changed since the previous snapshot. - `browser::elements` — the visible, enabled controls in the viewport as a flat table (`n` ref, role, label, current value, checked/expanded state, which `act` operations apply, `` option, press, or scroll, addressed by ref or viewport coordinates. A ref is scrolled into view, and a click/type/select on a disabled, hidden or covered element is refused (the error names what covers it) instead of landing on the overlay. Typing into an input or textarea by ref replaces its value. - `browser::run` — reach a goal on the current page in one call: the judge worker picks each step (click, type, select, scroll, wait) from the element table and the worker executes it, until done, blocked, a field needs text you did not pass in `inputs` (`needs_text`), no progress, or the budget runs out. Returns the steps and the final page table. Without a judge worker it returns `judge_unavailable` plus the table, and changes nothing. - `browser::screenshot` — viewable JPEG of the viewport, for when layout or rendering matters. - `browser::evaluate` — run a JavaScript expression in the page and get the completion value. - `browser::execute` — run a multi-step async script in the page: top-level await and return, `log(...)`, `sleep(ms)`, `waitFor(selector)`, and a `state` object persisted across execute calls for the session. One call replaces a chain of act/evaluate round-trips. - `browser::handoff` — pause the session for a human-only step (CAPTCHA, 2FA, payment): show an in-page continue banner and block until the human clicks it, a `browser::handoff::confirm` call resolves it, or the timeout elapses. Verify the expected page state after it returns. - `browser::handoff::confirm` — resolve a paused handoff from outside the page (by handoff_id, or the one pending handoff for a session_id). - `browser::console::read` — captured console entries; filter with pattern/level and page with since_seq. - `browser::network::read` — captured requests; failed_only=true is the fast path for what broke. - `browser::history` — back, forward, or reload; the tab's history survives it sleeping and the worker restarting. - `browser::clear-data` — clear the cookies, storage and cache of the site the tab is on; other sites stay signed in. `browser::clear-browser-data` wipes the whole profile (every tab signed out). - `browser::dom::read` — DOM tag outline with refs, for structure the accessibility tree hides. - `browser::styles::read` / `browser::styles::write` — computed styles and live inline CSS edits on one element. ### Fetching, sessions and crawl These reach the network, so they need approval. All return one envelope — `{status, url, headers, cookies, encoding}` — and can extract or render inline via `selectors` / `format: markdown|text` / `include_html`, so you rarely need a second call to parse what you fetched. Each takes a single `url` or a bulk `urls` list. - `browser::fetch` — plain HTTP, no browser. The default choice: fastest, cheapest. Safe mode uses bounded native HTTP; certified compat mode uses the frozen curl-impersonate wire behavior. - `browser::dynamic-fetch` — real Chromium over CDP, for pages that need JavaScript. Supports `wait_selector` (+ `wait_selector_state`), `network_idle`, and a plain `wait`. - `browser::stealthy-fetch` — same, plus masking of the automation tells a page can read. Escalate here only when `dynamic-fetch` is detected. - `browser::screenshot-url` — page as image tiles (≤1024px wide, ≤6 tiles); says so in the caption when a page is taller than the budget. - `browser::session-open` / `session-fetch` / `session-close` / `session-list` — keep cookies and browser state across fetches. HTTP, dynamic and stealthy types are private FIFO sessions with UUID4 hex ids; they never appear in `browser::sessions::list` and reject interactive ids (`session-close` on a tab id fails: tabs close with `browser::sessions::stop`). Close sessions when done. - `browser::crawl` — breadth-first from `start_urls`, same-domain by default, capped by `max_pages` (20) and `max_depth` (2). The response holds only a ≤10-item sample; read the rest from the stream it names. Safe mode refuses private, loopback and cloud-metadata addresses on every one of these connections (including redirects and crawl hops). To scrape a local dev server the operator must set `browser.scrapling.allow_loopback` in worker config. Compat mode reproduces the Python wrapper's unrestricted network behavior and is for trusted calls. ### HTML parsing — no session, no browser, no network These take an `html` string and never touch Chromium. Use them on HTML from any source (a fetch body, a file, a page you already read). - `browser::extract` — declarative selector list in one call: each entry names a `css`/`xpath`/`regex` plus optional `attr`/`html`/`all`, and the response is a `{name: value}` map. The right default when pulling several fields off one document. - `browser::css` / `browser::xpath` — one query; `first: true` returns a scalar, otherwise an array. `attr` pulls an attribute instead of text. - `browser::regex` — regex over the document's visible text. - `browser::find` — element search by tag/attribute filters (+ optional text regex), BeautifulSoup-style. - `browser::find-by-text` / `browser::find-by-regex` — find elements by their visible text. Responses carry generated css/xpath selectors for each hit, so you can feed one straight back into a query. - `browser::find-similar` — give one example element, get its structural siblings. The fast path for "extract every card/row on this page" without hand-writing a selector. - `browser::describe` — inspect the first match: attributes, class list, generated selectors, parent/child/sibling counts. - `browser::to-markdown` — HTML → compact Markdown (or text), with an optional CSS scope and a main-content cleaner. Use it to shrink a page before putting it in context. `adaptive: true` persists element identities in the configured SQLite file. Parse calls are auto-allowed, so do not assume parsing is side-effect-free when adaptive tracking is enabled. Safe mode enforces the configured database quota; compat mode preserves the Python wrapper's unbounded behavior. ### Safe and compat modes `browser.scrapling.security_mode` defaults to `safe`. Safe mode keeps SSRF, TLS, proxy, response-size, timeout, and adaptive-database policy checks; an option the safe backend cannot enforce is refused with an actionable error. Compat is eligible only on certified Linux x86_64/aarch64 builds containing the frozen curl-impersonate and Chromium artifacts. Other targets reject it, and a Tier-1 build missing an artifact reports a capability error instead of silently using the safe transport. Every id is `browser::`. `browser::screenshot-url` screenshots a url, while `browser::screenshot` is the interactive-session function. Crawl's default stream is `browser::crawl`. ## Workflow: inspect before acting 1. Read first; act on refs from the latest read, never from memory of an earlier one. For forms and controls, `browser::elements` is the cheap read; `browser::snapshot` shows the whole structure. Refs die on navigation, so a stale ref fails with an error instead of clicking the wrong element. 2. After an action that changes the page, re-read with `browser::elements` (or `browser::snapshot { diff: true }`, which returns only added and removed lines). Set a native `