Web access for LLM agents. One static binary. No Chrome.
Project description
unbrowser
Web access for LLM agents. One static binary. No Chrome.
Single-file native headless browser optimized for LLM agents. Runs JavaScript via QuickJS, returns a low-token page summary on every navigate, and gives you stable element refs for click/type/submit. Tens of MB RAM per session, no Chrome dependency.
pip install pyunbrowser # PyPI name; the import is `from unbrowser import ...`
The wheel ships the native binary for your platform — there's nothing else to install.
For transparent bot-wall cookie handoff through local Chrome, install the optional solver extra:
pip install 'pyunbrowser[solver]' # includes unchainedsky-cli
unbrowser cookie-service --headless --profile unbrowser-cookie-service
unbrowser router https://example.com/protected
The solver service binds to 127.0.0.1 by default and returns cookies from the user's local Chrome/unchained session. It does not fabricate challenge tokens. Private/reserved/internal hosts are rejected unless explicitly allowed with --allow-host. Non-loopback binds are rejected unless --allow-remote-bind is passed because /solve is unauthenticated and can return browser cookies. Router refuses non-loopback cookie service URLs by default because it sends target URLs and challenge metadata to that service; use --allow-remote-cookie-service only for a trusted remote solver.
Quick start
from unbrowser import Client
with Client() as ub:
r = ub.navigate("https://news.ycombinator.com")
for s in ub.query(".titleline > a")[:3]:
print(s["text"], s["attrs"]["href"])
Why
| curl | This | Playwright / headless Chrome | |
|---|---|---|---|
| Static / SSR pages | ✅ but token-heavy | ✅ low-token BlockMap | overkill |
SPA-shell sites (with exec_scripts) |
❌ | ⚠️ partial | ✅ |
| Bot-walled (cookie handoff) | ❌ | ✅ | ✅ |
| Run in Lambda / Workers / edge | ✅ | ✅ | ❌ Chrome too big |
| Per-page cost at 100K/day | ~free | ~free | $$$ |
| LLM-shaped output | DIY parse | ✅ inline BlockMap | DIY parse |
What it does
navigate(url)— fetch, parse, return{status, url, bytes, headers, blockmap, challenge}. Withexec_scripts=True, runs page JS in QuickJS (bounded by a 30s watchdog so it can't wedge).query(selector)— CSS query →[{ref, tag, attrs, text, text_chars, text_truncated}]. Refs are stable handles for click/type/submit.query_debug(selector)— diagnose selector misses with match counts, samples, DOM summary, and selector hints.extract()— auto-strategy structured data: tries JSON-LD →__NEXT_DATA__→ Nuxt → OpenGraph → microdata → text fallback, returns highest-confidence hit.extract_table(selector)/table_to_json(selector="table")— normalize HTML tables into headers, rows, and row count.click(ref)/type(ref, text)/submit(ref)— interaction. GET andapplication/x-www-form-urlencodedPOST forms supported; multipart is not yet supported. Checked checkbox/radio values are serialized.cookies_set(...)— paste cookies from a real Chrome session to bypass bot detection (Cloudflare, PerimeterX, Datadome). Solve once, replay forever.
Full RPC reference, BlockMap shape, challenge detection, profile system, and architecture: github.com/protostatis/unbrowser.
Honest limits
- Heavy framework SPAs (Ember/React) often don't auto-mount inside QuickJS even with
exec_scripts=True— the watchdog ensures it returns, checkdensity.likely_js_filledto decide whether to escalate. - No screenshots (out of scope by design).
- Hardest-tier anti-bot (FingerprintJS Pro, Kasada, advanced Akamai BMP) needs the cookie handoff path. The binary detects and labels the challenge for you.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyunbrowser-0.0.14-py3-none-manylinux_2_35_aarch64.whl.
File metadata
- Download URL: pyunbrowser-0.0.14-py3-none-manylinux_2_35_aarch64.whl
- Upload date:
- Size: 4.4 MB
- Tags: Python 3, manylinux: glibc 2.35+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5ca6bc4f299bd114b68f5a016b49e106a3c412b4f2aad74ebdd5ee94710dbd0
|
|
| MD5 |
138b3b31dca7c8a14427098c8327c843
|
|
| BLAKE2b-256 |
4dbce13223da68aca733d229e35b67e9fe40fc2e375c175ca7e151fc4012ef52
|
Provenance
The following attestation bundles were made for pyunbrowser-0.0.14-py3-none-manylinux_2_35_aarch64.whl:
Publisher:
release.yml on protostatis/unbrowser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyunbrowser-0.0.14-py3-none-manylinux_2_35_aarch64.whl -
Subject digest:
f5ca6bc4f299bd114b68f5a016b49e106a3c412b4f2aad74ebdd5ee94710dbd0 - Sigstore transparency entry: 1630906408
- Sigstore integration time:
-
Permalink:
protostatis/unbrowser@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Branch / Tag:
refs/tags/v0.0.14 - Owner: https://github.com/protostatis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyunbrowser-0.0.14-py3-none-manylinux_2_31_x86_64.whl.
File metadata
- Download URL: pyunbrowser-0.0.14-py3-none-manylinux_2_31_x86_64.whl
- Upload date:
- Size: 4.6 MB
- Tags: Python 3, manylinux: glibc 2.31+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
068be8f8c6319b3a1c2ee3a71833935eb8419c10e969360bd70d1ac6b8399e49
|
|
| MD5 |
23f23a686f4798b7d0e36aab71747c54
|
|
| BLAKE2b-256 |
d30801f3e312262a68fac4eacede256dab6229104f03485edeeaff6e2c543e54
|
Provenance
The following attestation bundles were made for pyunbrowser-0.0.14-py3-none-manylinux_2_31_x86_64.whl:
Publisher:
release.yml on protostatis/unbrowser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyunbrowser-0.0.14-py3-none-manylinux_2_31_x86_64.whl -
Subject digest:
068be8f8c6319b3a1c2ee3a71833935eb8419c10e969360bd70d1ac6b8399e49 - Sigstore transparency entry: 1630906463
- Sigstore integration time:
-
Permalink:
protostatis/unbrowser@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Branch / Tag:
refs/tags/v0.0.14 - Owner: https://github.com/protostatis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyunbrowser-0.0.14-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: pyunbrowser-0.0.14-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.1 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2cba7c8b1f08e13964491f04e90dafa07500f232e839ab3f89432dafcf07f0c1
|
|
| MD5 |
0ce82b977dfdcade6f54926fc45b5ba7
|
|
| BLAKE2b-256 |
131675ec98a16c99a6898e67feecc2c9693c402cdf2a97bee9afc521b56b4418
|
Provenance
The following attestation bundles were made for pyunbrowser-0.0.14-py3-none-macosx_11_0_arm64.whl:
Publisher:
release.yml on protostatis/unbrowser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyunbrowser-0.0.14-py3-none-macosx_11_0_arm64.whl -
Subject digest:
2cba7c8b1f08e13964491f04e90dafa07500f232e839ab3f89432dafcf07f0c1 - Sigstore transparency entry: 1630906504
- Sigstore integration time:
-
Permalink:
protostatis/unbrowser@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Branch / Tag:
refs/tags/v0.0.14 - Owner: https://github.com/protostatis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyunbrowser-0.0.14-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pyunbrowser-0.0.14-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.4 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b2fb4a381e78a390f28f5193576a6cf8bf72dadce6c11d3903fb83247907a99
|
|
| MD5 |
f4280bca77d08949e3831ceac25eb220
|
|
| BLAKE2b-256 |
9c449308f2390f790874cb80308da5aaa389f68ce6774c20d27c764e40a9d365
|
Provenance
The following attestation bundles were made for pyunbrowser-0.0.14-py3-none-macosx_10_12_x86_64.whl:
Publisher:
release.yml on protostatis/unbrowser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyunbrowser-0.0.14-py3-none-macosx_10_12_x86_64.whl -
Subject digest:
8b2fb4a381e78a390f28f5193576a6cf8bf72dadce6c11d3903fb83247907a99 - Sigstore transparency entry: 1630906437
- Sigstore integration time:
-
Permalink:
protostatis/unbrowser@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Branch / Tag:
refs/tags/v0.0.14 - Owner: https://github.com/protostatis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ae7680b453c6f55522ddcdf564622955f43a7d42 -
Trigger Event:
push
-
Statement type: