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.6

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.6
File Size Uploaded
fastbrowser-0.1.6.tar.gz 504.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for fastbrowser 0.1.6
File
fastbrowser-0.1.6-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
fastbrowser-0.1.6-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.6-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64 Details
fastbrowser-0.1.6-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: 16.6 MB

Release files / fastbrowser-0.1.6.tar.gz

Download URL fastbrowser-0.1.6.tar.gz
Size 504.8 kB
Tags Source
SHA-256 checksum
How to use checksums
091314f1c92ff99c590d36cac4085cced7f8824ebd403b5ae6eaa3d695901502
BLAKE2b-256 checksum
How to use checksums
0c0eaf433d5f336998e750e9b7e4f1f529713bcff48932cc450a1c8090493894
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.6-cp38-abi3-win_amd64.whl

Download URL fastbrowser-0.1.6-cp38-abi3-win_amd64.whl
Size 2.6 MB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f69600e7d7a574dd49227eb56a356eea3138c1a3ab2aed124011ac0b186541f7
BLAKE2b-256 checksum
How to use checksums
3d9af8d9063d47dcab3604a468640ab38c74bf0a34a4026cd0a1b1a5ecf149a5
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.6-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fastbrowser-0.1.6-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
7e9135d32946e8206e7e2cb3a29a82102c42aacc35ac2bfd31276b37bafcfeba
BLAKE2b-256 checksum
How to use checksums
b6400ff84000c19bceeec72d7e11e9ac12957953607fc5fb6f8942f2f0af2cf7
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.6-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fastbrowser-0.1.6-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
a2aa48866bf0e06ee4393c4fa900a21b865079fe02fdd4744ac051cce04b9605
BLAKE2b-256 checksum
How to use checksums
389566567588c826aa771b777b589a9d476a9a75815443b46e409ba13414d75f
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.6-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL fastbrowser-0.1.6-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
ca5870866cab31f02a24a59cc700a88c4d1480a2e19768c398a06194f234a046
BLAKE2b-256 checksum
How to use checksums
435eed15f9069845a04b3bd78962ee656d06350465fa76a112195311edefe5a5
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

This release

0.1.6 This release

5 release files

0.1.5

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