Default navigation is a fast static pass; `exec_scripts: true` opts into bounded QuickJS, which can materialise light hydration but is not V8 and will still leave a heavy React or Vue app as an empty shell. What makes that workable is honesty in the output — `density.likely_js_filled`, `thin_shell` and `challenge.provider` say which case you are in, so an agent stops or escalates rather than reporting an empty page as the answer. Script evaluation is bounded by UNBROWSER_SCRIPT_EVAL_BUDGET_MS, default 5000.
A non-visual web runtime for agents. It keeps cookies and DOM state across calls, returns queryable element references, follows links and submits HTML forms, and tells the caller when a page genuinely needs Chrome instead of pretending it can handle it.
- `navigate` fetches a page and returns a BlockMap — title, landmarks, headings, interactives, density signals and an ASCII outline — plus status, headers and challenge detection
- `query` and `query_debug` run CSS selectors and return stable refs like `e:142`, with sample matches and hints when a selector misses
- `click`, `type` and `submit` act on those refs; GET and URL-encoded POST forms are supported, multipart is not
- `text` and `text_main` read a node or the likely article subtree; `extract_cards`, `extract_table` and `table_to_json` normalise repeated listings and tables
- `discover` finds DOM, form and network routes and ranks them against an information goal
- `eval` runs JavaScript in the embedded QuickJS runtime; `cookies_set`, `cookies_get` and `cookies_clear` manage the jar
- Every result carries routing aids: `micro_hint` for the single next step, `next_tools` ranked, `avoid` for tools with nothing to act on
- Selectors cover tags, IDs, classes, attribute operators, all four combinators, `:not()` and `:has()`
One binary, no Chrome. Install the PyPI wheel pyunbrowser 0.0.21 with pipx (Python 3.10+), `cargo install unbrowser`, a release archive, or the distroless Docker image ghcr.io/protostatis/unbrowser — a roughly 13 MiB pull that runs as non-root. Start it with `--mcp`. No account or key.
One command — pipx install pyunbrowser
