Browser Bridge server and CLI for controlling a Chrome extension over WebSocket
Project description
Browser-Agent Bridge - Ultra-Fast Browser Control for Agents
WebSocket-only HTML-first browser bridge for remotely controlling a local Chrome extension, built as a super fast alternative to traditional vision-based browser control systems.
Why This Exists
Traditional browser relays often rely on LLM vision to understand web pages at each step. In practice, that approach is:
- Expensive: it consumes many tokens to repeatedly analyze visual page state.
- Slow: repeated visual analysis adds latency at every interaction step.
- Error-prone: visual perception includes noise that is less relevant than structured HTML for deterministic control.
This project exists as an HTML-first relay: the browser-side extension exposes structured observations and preprocessed HTML, so remote agents can interact with websites with lower cost, lower latency, and more reliable control.
Architecture (WS-only)
Operator CLI (remote/local)
|
| ws(s)://.../ws/operator (auth)
v
Bridge Server
^
| ws(s)://.../ws/client (auth)
|
Chrome Extension (local browser)
|
+-- content script commands: observe/click/type/get_html/ping_tab/etc.
The extension connects outbound to server. Operator sends commands through server to a specific (instance_id, client_id).
Protocol
Client -> Server
auth:{kind, instance_id, client_id, token}result:{kind, command_id, ok, result|error}ping
Server -> Client
auth_ok/auth_errorcommand:{kind, command_id, type, payload, request_id, sent_at}pong
Operator -> Server
auth:{kind, token}list_clientsconnect_status:{kind, instance_id, client_id}send_command:{kind, instance_id, client_id, type, payload, timeout_s, request_id}ping
Server -> Operator
auth_ok/auth_errorclientsconnect_statuscommand_resultpong
Auth Modes
Set BRIDGE_AUTH_MODE:
static(default): compare token againstBRIDGE_SHARED_TOKEN(for clients) andBRIDGE_OPERATOR_TOKEN(for operator; defaults to shared token).BRIDGE_OPERATOR_TOKENmust be at least 16 chars and include lowercase, uppercase, digit, and symbol.
jwt: validate JWT withBRIDGE_JWT_SECRET/BRIDGE_JWT_ALG.- Client JWT should include matching
instance_idandclient_idclaims. - Operator JWT should include
role=operator.
- Client JWT should include matching
Production safety
BRIDGE_ENV=productionenforces strong auth config:- static mode:
BRIDGE_SHARED_TOKENmust not be empty/dev default. - jwt mode:
BRIDGE_JWT_SECRETmust not be default.
- static mode:
Install (pipx recommended)
python3 -m pip install --user pipx
python3 -m pipx ensurepath
pipx install browser-agent-bridge
Quick Start
1) (Optional) Generate local JWT secret file
browser-bridge setup-secret
If BRIDGE_AUTH_MODE=jwt and BRIDGE_JWT_SECRET is still default, server startup auto-loads/creates local secret file (~/.browser_bridge/jwt_secret or BRIDGE_JWT_SECRET_FILE).
2) Start server
# static mode example
export BRIDGE_AUTH_MODE=static
export BRIDGE_SHARED_TOKEN='change-me-strong-token'
export BRIDGE_OPERATOR_TOKEN='Str0ng!Operator#42'
browser-bridge-server
3) Load extension
- Open
chrome://extensions - Enable Developer mode
- Load unpacked
extension/ - In popup fill:
Bridge Server WS URL:ws://127.0.0.1:8765/ws/client(orwss://.../ws/client)Instance ID: e.g.local-instanceClient ID: e.g.chrome-mainAuth Token / JWT: client token
- Save + Connect
Connected tab preview:
4) Operator CLI usage
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token 'Str0ng!Operator#42' list-clients
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token 'Str0ng!Operator#42' connect-status --instance-id local-instance --client-id chrome-main
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token 'Str0ng!Operator#42' ping-tab --instance-id local-instance --client-id chrome-main
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token 'Str0ng!Operator#42' observe --instance-id local-instance --client-id chrome-main
observe now returns stable references per node:
ref: stable element reference for follow-up actionsclick_ref: reference biased toward a clickable ancestor (row/link/button)clickable_selector: selector for the chosen clickable ancestor
You can pass these back to click via send-command payload using ref/click_ref and optional guardrails:
prefer:control(default),row, orlinkavoid_roles: e.g.["checkbox", "menuitem"]avoid_tags: e.g.["input"]avoid_input_types: e.g.["checkbox", "radio"]
Raw command:
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token '...' \
send-command --instance-id local-instance --client-id chrome-main \
--type get_html --payload '{"max_chars":40000}'
You can also avoid shell JSON escaping with --payload-file:
cat > /tmp/cmd.json <<'JSON'
{"selector":"input[name=\"q\"]","text":"openclaw"}
JSON
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token '...' \
send-command --instance-id local-instance --client-id chrome-main \
--type type --payload-file /tmp/cmd.json
get_html result includes:
html: captured DOM text (possibly truncated)truncated: whether output was cut topayload.max_charsnotes: actionable recommendations (for example, increasemax_charswhen truncated, or setpreprocess=falsefor rawer DOM)preprocessandremoved_nodes: preprocessing mode and removed-node count
Adaptive load wait (navigate, click, type):
- Extension now waits for tab load completion before replying, but only up to 10s (adaptive: returns immediately if tab is already
complete). - Override per command payload:
wait_for_load(defaulttrue)wait_for_load_ms(default10000, capped at10000)
- Command result includes
load_waitdiagnostics:waited_ms,completed,timed_out,final_status,enabled,max_wait_ms.
Example:
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token '...' \
send-command --instance-id local-instance --client-id chrome-main \
--type navigate --payload '{"url":"https://example.com","wait_for_load_ms":4000}'
Human-like typing (type):
typenow simulates typing character-by-character by default to better match human input behavior.- Optional payload fields:
human_like(defaulttrue)clear_first(defaulttrue)keystroke_delay_ms(default45)keystroke_jitter_ms(default30)
Example:
browser-bridge --server-ws-url ws://127.0.0.1:8765/ws/operator --token '...' \
send-command --instance-id local-instance --client-id chrome-main \
--type type --payload '{"selector":"input[name=\"q\"]","text":"hello world","keystroke_delay_ms":70,"keystroke_jitter_ms":45}'
Security Hardening
- Use TLS in non-local deployments (
wss://). - Use strong static tokens or JWT secret. Operator static token must include mixed-case letters, digits, symbols, and be 16+ chars.
- Optional command allowlist:
BRIDGE_COMMAND_ALLOWLIST=observe,ping_tab,get_html. - Optional allowed clients allowlist in static mode:
BRIDGE_ALLOWED_CLIENTS=instance1:client1,instance2:client2. - Request idempotency/replay guard is enforced by
request_iddedup window. - Max payload limit is enforced by
BRIDGE_MAX_MESSAGE_BYTES.
Testing
pytest -v
Coverage includes WS auth success/failure, command routing, disconnect handling, wrong target routing, CLI failure paths, and reconnect replacement behavior.
Contributing
Contributions are very welcome.
If you want to help, great places to start are:
- bug fixes and reliability improvements
- new command handlers and protocol hardening
- better docs and examples
- tests for real-world edge cases
Quick contributor workflow:
- Fork the repo and create a focused branch.
- Run tests locally (
pytest -v). - Open a PR with a clear description, motivation, and test notes.
For detailed guidelines, see CONTRIBUTING.md.
If you have ideas but no patch yet, opening an issue/discussion is also appreciated.
License
MIT (see LICENSE).
Created by the creator of openclaw-setup.me.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 browser_agent_bridge-0.2.4.tar.gz.
File metadata
- Download URL: browser_agent_bridge-0.2.4.tar.gz
- Upload date:
- Size: 16.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b6da81768ee4dc91f73d1156d9f37d9e7beea618624a0fc38f3d0bb384ac00e
|
|
| MD5 |
ad940f3821421cdb74caca89da77102a
|
|
| BLAKE2b-256 |
bd76692ad15025ac2077eb0c3c15265b3bd7ea374b431eb278f19e7c30f26c22
|
Provenance
The following attestation bundles were made for browser_agent_bridge-0.2.4.tar.gz:
Publisher:
publish.yml on NmadeleiDev/browser_agent_bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
browser_agent_bridge-0.2.4.tar.gz -
Subject digest:
5b6da81768ee4dc91f73d1156d9f37d9e7beea618624a0fc38f3d0bb384ac00e - Sigstore transparency entry: 1088823845
- Sigstore integration time:
-
Permalink:
NmadeleiDev/browser_agent_bridge@04637cce6c564f86b9b798b5e38ddd7d4f0ddd16 -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/NmadeleiDev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04637cce6c564f86b9b798b5e38ddd7d4f0ddd16 -
Trigger Event:
push
-
Statement type:
File details
Details for the file browser_agent_bridge-0.2.4-py3-none-any.whl.
File metadata
- Download URL: browser_agent_bridge-0.2.4-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ccd966e1e877b1e3f094c45455b8fd4e7c67dc1581c4db5f4629db9db52a3e2
|
|
| MD5 |
f8f351487678cc5ff5b70b8d2d29f9cc
|
|
| BLAKE2b-256 |
888f6406ca4bd565d559bb5b5c0f1d3fb4bf27fea545b497a3ac5dbff2da56db
|
Provenance
The following attestation bundles were made for browser_agent_bridge-0.2.4-py3-none-any.whl:
Publisher:
publish.yml on NmadeleiDev/browser_agent_bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
browser_agent_bridge-0.2.4-py3-none-any.whl -
Subject digest:
1ccd966e1e877b1e3f094c45455b8fd4e7c67dc1581c4db5f4629db9db52a3e2 - Sigstore transparency entry: 1088823874
- Sigstore integration time:
-
Permalink:
NmadeleiDev/browser_agent_bridge@04637cce6c564f86b9b798b5e38ddd7d4f0ddd16 -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/NmadeleiDev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04637cce6c564f86b9b798b5e38ddd7d4f0ddd16 -
Trigger Event:
push
-
Statement type: