Lets any local AI (Claude Code, curl, scripts) drive your real Chrome tabs — click, type, fill forms, read page content, screenshot, navigate.
https://fitzyracing1.github.io/nexus-ai/sandbox/ — a browser inside the webpage, with the bridge "extension" built in. Nothing to install: the window has an address bar, tabs, back/forward, and a set of real demo sites, and an AI console drives them for real — clicking buttons, filling forms, reading text, navigating, screenshotting. There's also an autonomous-task runner that chains commands ("buy the headphones", "fill & submit the sign-in form").
It works because the sandbox pages are served from the same origin, so
in-page JavaScript can script them directly. The agent (sandbox/agent.js) is
the same action logic that ships in extension/content.js — the same
text= / text~= / CSS selector engine, the same synthetic mouse/keyboard
events, the same controlled-input setter. The real extension does the identical
thing to any tab; it just reaches it through the local bridge instead of an
iframe. Use the sandbox to see exactly what the bridge can do before installing.
https://fitzyracing1.github.io/nexus-ai/ — a real, working demo (not a mock). Open it in an extensions-capable Chromium browser (Chrome, Edge, Brave) and it drives that very page through your local bridge:
- Start
bridge.pyand install the extension (see setup). - Open the demo page and paste your bridge auth token (from
http://127.0.0.1:17777/setup) into the token box. - The three status boxes should turn green (browser ✓, extension ✓, bridge ✓).
- Click Read URL, Type into the box, Click the counter, or
Screenshot — each POSTs a genuine command to
127.0.0.1:17777, which the extension executes on the active tab (the demo page itself).
The page talks to the bridge directly over localhost: Chromium exempts
http://127.0.0.1 from mixed-content blocking, and the bridge already sends
permissive CORS headers, so an HTTPS GitHub Pages site can reach it. The
extension only exposes a presence handshake to pages (so the demo can show
"extension installed") — all real actions still go through the token-protected
bridge, so a random website can't drive your browser.
- From the site: nexus-ai-bridge-extension.zip
- From GitHub: the source lives in
extension/; the packaged zip is atdocs/nexus-ai-bridge-extension.zip("Download raw file").
Load it: Chrome/Edge — unzip, open chrome://extensions, enable Developer
mode, "Load unpacked". Kiwi Browser (Android) — ⋮ → Extensions → load the
.zip directly.
bridge.py tiny stdlib HTTP server on 127.0.0.1:17777
extension/ Chrome MV3 extension (background + content script)
docs/ the GitHub Pages site (landing, sandbox, extension zip)
cloud-browser/ hosted-browser alternative you drive from a phone
- Start the bridge (leave running):
python C:\Users\EC\ai-browser\bridge.py - Install the extension:
- Open
chrome://extensions - Toggle Developer mode on (top-right)
- Click Load unpacked
- Pick
C:\Users\EC\ai-browser\extension
- Open
- Connect: click the extension's puzzle-piece icon → pin "AI Browser Bridge" → click its icon → press Connect. Status should turn green ("Connected to bridge").
Anything that can POST JSON to http://127.0.0.1:17777/command can drive it.
# Click an element by CSS selector
curl -X POST http://127.0.0.1:17777/command \
-H "Content-Type: application/json" \
-d '{"action":"click","args":{"selector":"#submit-btn"}}'
# Click by visible text
curl -X POST http://127.0.0.1:17777/command \
-H "Content-Type: application/json" \
-d '{"action":"click","args":{"selector":"text=Sign In"}}'
# Type into an input
curl -X POST http://127.0.0.1:17777/command \
-H "Content-Type: application/json" \
-d '{"action":"type","args":{"selector":"input[name=q]","text":"hello","submit":true}}'
# Get current page URL/title
curl http://127.0.0.1:17777/command -X POST \
-H "Content-Type: application/json" \
-d '{"action":"get_url"}'| action | args | returns |
|---|---|---|
click |
{selector} or {x,y} |
element descriptor |
type/fill |
{selector?, text, append?, submit?} |
typed-into element + final value |
get_url |
— | {url, title} |
get_text |
{selector?, max_chars?} |
{text, length, truncated} |
get_html |
{selector?, max_chars?} |
{html, length, truncated} |
query |
{selector, limit?} |
matching elements descriptors |
scroll_to |
{selector} or {x,y} |
{scrolled_to} |
wait_for |
{selector, timeout_ms?, state?} |
{found} |
press |
{key, selector?} |
{pressed} |
screenshot |
{format?, quality?} |
{data_url} (base64 PNG/JPEG) |
navigate |
{url} |
{url} |
list_tabs |
— | [{id,title,url,active,windowId}] |
switch_tab |
{tab_id} |
{id, url} |
- CSS selectors:
#id,.class,button[type=submit] - Text match:
text=Sign In(exact or substring, deepest match wins) - Fuzzy text:
text~=sign(substring, case-insensitive)
GET http://127.0.0.1:17777/health
GET http://127.0.0.1:17777/status
- The bridge binds to 127.0.0.1 only — not reachable from other machines.
- The extension cannot inject into
chrome://, the Chrome Web Store, or other internal pages. Open a normal http(s) tab first. - Service worker keepalive uses
chrome.alarms. The long-poll itself also counts as active work, so the SW stays alive while a poll is in flight. - Commands without an active tab error out fast — you'll see "no active tab".
This project is free, and its license stays as is. Support it through GitHub Sponsors:
- Free: use the code, community support.
- Pro ($49/month): priority issues and support.
- Team ($199/month): priority support for your team plus early access.