Skip to main content

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 one BrowserEngine trait.
  • 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 FastBrowser per 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.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastbrowser 0.1.5
File Size Uploaded
fastbrowser-0.1.5.tar.gz 498.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for fastbrowser 0.1.5
File
fastbrowser-0.1.5-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
fastbrowser-0.1.5-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.5-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64 Details
fastbrowser-0.1.5-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+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64) Details

Total release size: 16.5 MB

Release files / fastbrowser-0.1.5.tar.gz

Download URL fastbrowser-0.1.5.tar.gz
Size 498.9 kB
Tags Source
SHA-256 checksum
How to use checksums
71fc3eee453d9f7b630b7825042a2296d2def6c77b080ead5e9a3ed6b975da6e
BLAKE2b-256 checksum
How to use checksums
e20ec8a3e653b6fda34da30e53e31d79b070f6ae3b0a80a70fa1a77f98d9978a
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.5-cp38-abi3-win_amd64.whl

Download URL fastbrowser-0.1.5-cp38-abi3-win_amd64.whl
Size 2.6 MB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
77f0adbae3cae4aa140ac972aa181739d7394cab3128088e17313d0d33b45975
BLAKE2b-256 checksum
How to use checksums
cdd04dc9ce9b9a411a2dd3e00cd35a5b067788ad5fa3d17797c48e2b444e6ec2
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.5-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fastbrowser-0.1.5-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 4.3 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
ff18d547d08d3701c0b5c2e2d2440ea857a54401fa4a02bf1a89c0e8cfa7a679
BLAKE2b-256 checksum
How to use checksums
ce59a863f1bc7982a599f427932d3124967e5c64ca9d166f579320ad026f57f3
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.5-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fastbrowser-0.1.5-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 4.1 MB
Tags CPython 3.8 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
144e2ba1c2ac7e00f264919c0cd3223bfb19d6bcd193402230b6e33e11c494fe
BLAKE2b-256 checksum
How to use checksums
691c682ebbce51c3e416eb293b2850a120eefc2c02fbd2635c47d15b93d0f30e
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.5-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL fastbrowser-0.1.5-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 5.0 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
37e714335f494b6b65c5c69e46868b87aa9809ad19732a19e15b8c9dd4a595b7
BLAKE2b-256 checksum
How to use checksums
ec0dc4e5ef4fc6464e571d9fc6d5357151a75fe9e33964520c166b3985ae2ce6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.1.9

5 release files

0.1.8

5 release files

0.1.7

5 release files

0.1.6

5 release files

This release

0.1.5 This release

5 release files

0.1.3

5 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page