fastbrowser
Python bindings for fastbrowser — a cross-platform browser-automation kernel for AI agents, written in Rust. This package exposes the kernel through PyO3.
- Engine-agnostic: mock (no deps) /
chromium(CDP) /bundled(Chrome for Testing) /webview/cef, unified behind oneBrowserEnginetrait. - AI-native: 95 LLM-friendly tools (
navigate,click,type,extract_text,wait_for_element,fill_form,screenshot, …), all JSON in/out. - Multi-tab concurrency: per-tab locks — different tabs run in parallel, same tab serialized (mirrors a real browser's per-process / single-main-thread model).
Install
pip install fastbrowser
Prebuilt wheels are published for CPython 3.8+ on macOS (arm64/x86_64), Linux (manylinux x86_64/aarch64) and Windows x64.
Quickstart (mock engine — no browser required)
import fastbrowser as fb
b = fb.FastBrowser()
b.init() # default: mock engine, zero deps
out = b.open("https://example.com")
print(out["title"]) # "Example Page"
print(b.snapshot()["title"]) # interactive-element snapshot for LLMs
print(b.tool_call("get_current_url")) # {"url": "https://example.com"}
w, h, rgba = b.screenshot() # raw RGBA (w, h, w*h*4 bytes)
b.save_screenshot("page.png") # PNG
b.shutdown()
Examples
1. Snapshot-driven interaction (the core agent loop)
snapshot() returns the interactive elements (a/b/c ids) the LLM acts on; click/type
target those ids:
b = fb.FastBrowser(); b.init()
b.open("https://example.com")
snap = b.snapshot()
for el in snap["interactive"]:
print(el["id"], el["tag"], el.get("text"), el.get("href"))
# click a link, type into a field, press Enter
b.tool_call("click", {"id": "c"})
b.tool_call("type", {"id": "e", "text": "hello"})
b.tool_call("press", {"key": "Enter"})
2. Content extraction
b = fb.FastBrowser(); b.init()
b.open("https://example.com")
print(b.tool_call("extract_links")) # {"links": [{"text": "Learn more", "url": "..."}]}
print(b.tool_call("extract_text")) # {"text": "..."}
print(b.tool_call("get_page_text")) # {"text": "..."}
print(b.tool_call("extract_table")) # {"table": [["Name", "Value"], ...]}
print(b.tool_call("get_page_title")) # {"title": "Example Page"}
3. Form filling
b = fb.FastBrowser(); b.init()
b.open("https://example.com")
# fill by snapshot id
b.tool_call("fill_form", {"values": {"e": "alice"}}) # {"filled": ["e"], "ok": true}
# or field-by-field
b.tool_call("type", {"id": "e", "text": "bob", "clear": True})
b.tool_call("checkbox", {"id": "d", "checked": True})
# on a real engine: dropdown / radio / file upload
b.tool_call("select_option", {"id": "e", "value": "pro"})
b.tool_call("radio", {"id": "r"})
4. Multi-tab
Every tool accepts {"tab": N} — cross-tab operations don't depend on the active tab:
b = fb.FastBrowser(); b.init()
t1 = b.open("https://example.com")["tab"]
t2 = b.tool_call("new_tab", {"url": "https://example.com/login"})["tab"]
print(b.tool_call("list_tabs")) # {"tabs": [1, 2]}
print(b.tool_call("get_page_title", {"tab": t1})) # {"title": "Example Page"}
print(b.tool_call("get_page_title", {"tab": t2})) # {"title": "Login"}
b.tool_call("switch_tab", {"tab": t1})
b.tool_call("close_tab", {"tab": t2})
5. Waiting
b.tool_call("wait_for_element", {"selector": "button", "timeout_ms": 5000})
b.tool_call("wait_for_navigation", {"timeout_ms": 10000})
6. Execute JavaScript
print(b.tool_call("execute_js", {"script": "document.title"})) # {"result": "Example Page"}
# on a real engine, any script runs against the real page:
print(b.tool_call("execute_js", {"script": "document.links.length"})) # {"result": <count>}
7. Screenshots
w, h, rgba = b.screenshot() # raw RGBA
png = b.screenshot_png() # PNG bytes (stdlib-encoded, no Pillow)
b.save_screenshot("page.png") # save PNG to disk
b.set_viewport(390, 844) # mobile viewport
8. Event callbacks
import json
events = []
b.register_event_callback(lambda tab, ev: events.append((tab, json.loads(ev))))
b.open("https://example.com")
b.navigate("https://example.com/login")
print(events) # navigation / console / dom events
9. OSR frame streaming
import time, json
frames = []
b.register_frame_callback(lambda tab, f: frames.append((tab, json.loads(f))))
b.open("https://example.com")
b.start_frame_stream(1, fps=10)
time.sleep(0.5)
b.stop_frame_stream(1)
print(frames[0][1]["width"], frames[0][1]["height"]) # frame dims
10. Session state, cookies & storage
b = fb.FastBrowser(); b.init()
b.open("https://example.com")
b.tool_call("cookie_set", {"name": "sid", "value": "abc", "domain": "example.com"})
b.tool_call("storage_set", {"key": "token", "value": "t1"})
b.session_save("/tmp/state.json") # {"tabs": 1}
b.shutdown()
b2 = fb.FastBrowser(); b2.init()
b2.session_load("/tmp/state.json") # {"tabs": 1}
b2.open("https://example.com")
print(b2.tool_call("cookie_get", {"domain": "example.com"})) # {"cookies": [{"value": "abc", ...}]}
print(b2.tool_call("storage_get", {"key": "token"})) # {"value": "t1"}
11. Audit trail
b.tool_call("get_current_url")
print(b.audit()) # [{"tool":..., "ok":..., ...}, ...]
b.clear_audit()
Async (asyncio)
import asyncio
import fastbrowser as fb
async def main():
b = fb.AsyncFastBrowser()
await b.init()
t1 = (await b.open("https://example.com"))["tab"]
t2 = (await b.open("https://example.com/login"))["tab"]
# multi-tab concurrency — the two calls run truly in parallel
r1, r2 = await asyncio.gather(
b.tool_call("get_page_title", {"tab": t1}),
b.tool_call("get_page_title", {"tab": t2}),
)
print(r1["title"], r2["title"])
asyncio.run(main())
Blocking operations (open/tool_call/snapshot/screenshot…) are offloaded to a thread
pool in the async interface, and the kernel releases the GIL, so gather runs concurrent tabs
truly in parallel.
Real browser (Chromium)
Point at your own Chrome via CDP:
b = fb.FastBrowser()
b.init({
"engine": "chromium",
"cdp_url": "ws://127.0.0.1:9222/devtools/browser/<id>", # start Chrome with --remote-debugging-port=9222
})
b.open("https://example.com")
print(b.snapshot()["title"])
Or use the bundled Chrome for Testing (downloads separately, not shipped in the wheel):
b.init({"engine": "bundled"}) # auto-launches vendor/chromium (or CHROME_PATH)
With a real engine, click/type use real coordinate-level input with Playwright-style
actionability, execute_js runs in the real page, screenshot captures real pixels, and
cookies/storage/downloads hit real browser state.
API
| Area | Methods |
|---|---|
| Lifecycle | init(config?), is_initialized, shutdown |
| Navigation | open(url), navigate(url) |
| Tools | tool_call(name, params?), tool_list(), tool_count() |
| Content | snapshot(), screenshot(), screenshot_png(), save_screenshot(path), get_page_* via tools |
| Rendering | set_viewport(w,h), get_view(), set_rendering_mode(mode), start_frame_stream(tab, fps), stop_frame_stream(tab) |
| Callbacks | register_event_callback(cb), register_frame_callback(cb) |
| State | status(), get_info(), audit(), clear_audit() |
| Session | session_save(path), session_load(path), clear_state() |
Notes
- Single-instance semantics: one
FastBrowserper process (the kernel is a process-wide singleton behind a shared runtime). Use one instance and drive tabs concurrently. - Callbacks (
register_event_callback/register_frame_callback) fire on a dedicated dispatcher thread outside the engine lock — safe to re-enter the browser from inside them. - License: Apache-2.0 (matches the kernel).
Test
python -m pytest tests/ -q # mock engine (no browser)
TMPDIR=/tmp python -m pytest tests/test_chromium.py -q # real Chromium (needs vendor/chromium)
Metadata
Release files for fastbrowser 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastbrowser-0.1.3.tar.gz | 312.7 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| fastbrowser-0.1.3-cp38-abi3-win_amd64.whl | CPython 3.8 | abi3 | Windows x86-64 | Details |
| fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.8 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.8 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| fastbrowser-0.1.3-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl | CPython 3.8 | abi3 | macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64 | Details |
Total release size: 6.2 MB
Release files / fastbrowser-0.1.3.tar.gz
| Download URL | fastbrowser-0.1.3.tar.gz |
|---|---|
| Size | 312.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
459c1d2a8e3465176751749d5b36a05fc7f41e09c889559f28b22e248db989d4
|
|
BLAKE2b-256 checksum How to use checksums |
c205988f9e02206e581c4002dd16e39375adc353fa2a62296595030bdf8fe8f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / fastbrowser-0.1.3-cp38-abi3-win_amd64.whl
| Download URL | fastbrowser-0.1.3-cp38-abi3-win_amd64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.8 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
17409544aad92c7102c5dd96ac673dcb27fd4f09592917331a3ec0fb7dc16e9d
|
|
BLAKE2b-256 checksum How to use checksums |
e882a49879928495ec20ffd9d7340c33a71800158fbeaec35e1b6f61f0aecd80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.8 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
910b5a096081fc20753ff6abeb8d2b4238cb0326821c520d2069157edfe1c034
|
|
BLAKE2b-256 checksum How to use checksums |
3dc5f96def9b0e9ec3003613e1c981f849a3c82d5916821487aa9085cdc8a6ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | fastbrowser-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.8 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
cc720115b8dd9bc168255de1025a20935eb1d07e884eb6d0caa764a6a1599c14
|
|
BLAKE2b-256 checksum How to use checksums |
ec53455e2b13d421d325097f0e04ecb7aab6acc1b66d5a6b6367ca4816d34516
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / fastbrowser-0.1.3-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
| Download URL | fastbrowser-0.1.3-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.8 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
65c1da716aa8c192b3670acf02267b81e69a3a37492be43c16732c57d9ded3f6
|
|
BLAKE2b-256 checksum How to use checksums |
0af0564df8d98430c2f14419c81788c4b25f097665649e243328d62ba156f33d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|