Documentation · VulpineOS · Issues
foxbridge translates Chrome DevTools Protocol (CDP) into Firefox's Juggler and WebDriver BiDi protocols. Any tool built for Chrome — Puppeteer, OpenClaw, browser-use, Playwright CDP mode — can control Firefox-based browsers without modification.
CDP Client (Puppeteer, OpenClaw, etc.)
│
▼ WebSocket (ws://localhost:9222)
┌────────────────────────────────────┐
│ foxbridge │
│ CDP Server + HTTP Discovery │
│ Bridge Layer (method translation) │
│ ├── Juggler Backend (pipe FD 3/4) │
│ └── BiDi Backend (WebSocket) │
└────────────────────────────────────┘
│
▼
Firefox / Camoufox
- Anti-detect browsers like Camoufox are Firefox-based, but most AI agent tools only speak CDP
- No existing tool bridges CDP to Firefox's automation protocols
- Dual backend: Juggler (Playwright's protocol, production-ready) and WebDriver BiDi (W3C standard, future-proof)
- Part of VulpineOS — integrates automatically so OpenClaw agents use Camoufox instead of Chrome
go install github.com/VulpineOS/foxbridge/cmd/foxbridge@latest
# Juggler backend (default)
foxbridge --binary /path/to/camoufox --port 9222
# BiDi backend
foxbridge --backend bidi --binary /path/to/firefox --port 9222
# Connect to existing BiDi endpoint
foxbridge --backend bidi --bidi-url ws://localhost:9223/session
# Serve CDP over a Unix domain socket
foxbridge --binary /path/to/camoufox --socket /tmp/foxbridge.sock
# Enable deterministic runtime shims for low-flake tests
foxbridge --binary /path/to/camoufox --deterministic-time 1700000000000 --deterministic-seed 42
# Record a live CDP session to JSONL
foxbridge --binary /path/to/camoufox --record ./trace.jsonl
# Replay a captured CDP session without launching Firefox
foxbridge replay --recording ./trace.jsonl
# Print a protocol coverage report
foxbridge doctor
# Now connect any CDP tool:
# Puppeteer: puppeteer.connect({ browserWSEndpoint: 'ws://localhost:9222' })Full documentation is available at foxbridge.vulpineos.com — covering setup, CDP domain coverage, backend configuration, and VulpineOS integration.
If you are using foxbridge with VulpineOS-specific Page.* extensions,
see the passthrough guide in the docs: VulpineOS Methods.
foxbridge doctor is now the source of truth for protocol coverage:
foxbridge doctor
foxbridge doctor --format jsonCurrent snapshot on main from foxbridge doctor:
662upstream CDP methods in the bundled protocol snapshot89implemented methods203stubbed compatibility methods370missing methods8foxbridge-only extensions
The strongest covered areas today are DOM, Page, Target, Network, Fetch, Runtime, Input, Emulation, IO, and Performance. Stubbed domains still exist for compatibility, but foxbridge should no longer be described as “13 fully implemented CDP domains”.
| Firefox Event | CDP Event |
|---|---|
Browser.attachedToTarget |
Target.attachedToTarget (tab + page dual session) |
Browser.detachedFromTarget |
Target.targetDestroyed |
Page.navigationCommitted |
Page.frameNavigated + lifecycle events |
Page.eventFired(load) |
Page.loadEventFired + Page.frameStoppedLoading |
Page.eventFired(DOMContentLoaded) |
Page.domContentEventFired |
Runtime.executionContextCreated |
Runtime.executionContextCreated |
Runtime.console |
Runtime.consoleAPICalled |
Page.dialogOpened |
Page.javascriptDialogOpening |
Network.requestWillBeSent |
Network.requestWillBeSent |
Network.responseReceived |
Network.responseReceived |
Browser.requestIntercepted |
Fetch.requestPaused |
# Browser info
curl http://localhost:9222/json/version
# Active page targets
curl http://localhost:9222/json/listfoxbridge implements the Backend interface — swap between Juggler and BiDi without changing the bridge layer:
type Backend interface {
Call(sessionID, method string, params json.RawMessage) (json.RawMessage, error)
Subscribe(event string, handler func(sessionID string, params json.RawMessage))
Close() error
}- Juggler (
--backend juggler): Pipe FD 3/4 transport, null-byte JSON framing. Direct protocol match with Playwright. Default and most battle-tested. - BiDi (
--backend bidi): WebSocket transport, W3C standard. The BiDi client internally translates Juggler-style calls to BiDi equivalents so the bridge layer works unchanged.
When used inside VulpineOS, foxbridge runs as an embedded CDP server sharing a single Camoufox instance:
Kernel -> Camoufox (single process) -> Juggler pipe -> juggler.Client
├── TUI (direct Juggler calls)
├── MCP server (Juggler calls for browser tools)
└── Embedded foxbridge CDP server on :9222
└── OpenClaw connects via cdpUrl -> same Camoufox contexts
No separate process needed — VulpineOS imports foxbridge as a Go library and starts the CDP server in-process. OpenClaw agents automatically connect to Camoufox through the embedded bridge. Graceful fallback: if the foxbridge binary is not found, OpenClaw uses its built-in Chrome.
| Flag | Default | Description |
|---|---|---|
--port |
9222 | CDP WebSocket port |
--socket |
— | Unix-domain socket path for the CDP HTTP/WebSocket server |
--binary |
auto-detect | Firefox/Camoufox binary path |
--headless |
false | Run headless |
--profile |
— | Firefox profile directory |
--backend |
juggler | Backend: juggler or bidi |
--bidi-url |
— | Connect to existing BiDi endpoint |
--bidi-port |
9223 | BiDi port when auto-launching Firefox |
--record |
— | Path to write a JSONL CDP wire capture |
--deterministic-time |
0 | Base epoch in milliseconds for deterministic Date.now / performance.now injection |
--deterministic-seed |
0 | Seed for deterministic Math.random / crypto.getRandomValues injection |
When --socket is set, foxbridge listens on a Unix domain socket instead of binding a TCP port. Discovery endpoints are still available over HTTP, and the browser-level WebSocket URL remains /devtools/browser/foxbridge; clients must dial that URL using their library's Unix-socket transport or socketPath option.
When either deterministic flag is set, foxbridge injects a deterministic runtime prelude into page sessions so Date.now, performance.now, Math.random, and crypto.getRandomValues become repeatable across runs.
When --record is set, foxbridge writes every inbound and outbound CDP frame for the active session to JSONL. The resulting file can be replayed later with foxbridge replay --recording /path/to/trace.jsonl to reproduce client traffic without launching a browser.
foxbridge has comprehensive test coverage across three layers:
- 379 Go unit tests — all passing with race detector (
go test -race ./...) - 74/74 Puppeteer Juggler tests — full Puppeteer test suite against the Juggler backend
- 62/62 Puppeteer BiDi tests — full Puppeteer test suite against the BiDi backend
go test -race ./...CI runs on every push via GitHub Actions (build + vet + race-detected tests).
MIT
