Skip to content
Registry

browser

v0.2.32

A browser on the iii bus - shared Chromium with persistent, restorable tabs and incognito tabs. Navigate, act, read the page console, pick elements. Also parses HTML natively without a browser (browser::* - css/xpath/regex, element search, markdown).

license: Apache-2.0automationbrowsercdpchromiumextractionparsingscrapingweb

Install

bash
iii trigger compose::add worker=browser@next

Run in your project with the iii engine running. Exact versions are immutable and digest-pinned.

skill doc

SKILL.md

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; page through every item with browser::crawl::items { crawl_id: , after?, limit? } (retained in memory for 1 h, last 32 crawls). For items live while it runs, bind browser::crawl-item with { crawl_id } first, then call browser::crawl { crawl_id }; missed or dropped events (seq gaps, dropped_events) are read back with browser::crawl::items. stream_name is deprecated and ignored (a warnings entry says so).

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.

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