The Problem That Started It

I wanted Claude to control my Brave browser. Not a headless zombie browser that gets blocked everywhere — my real browser, with my real sessions, real cookies, real logged-in accounts.

Every existing tool uses Chrome DevTools Protocol (CDP). CDP sets navigator.webdriver = true. LinkedIn detects it and locks your account. X throws captchas. Gmail flags you as suspicious. Your "automation" gets blocked before it does anything useful.

The Wall. CDP and headless browsers are external tools controlling a browser. Sites detect them because they're supposed to. Extensions are part of the browser itself — same APIs that 1Password and Grammarly use. No site blocks those.

So I built BraveBridge — a Manifest V3 Chrome extension that connects to Claude Code via MCP through a WebSocket bridge. The idea was simple: let AI agents use your real browser sessions without detection.

What I Built

BraveBridge had three components:

AI Agent (Claude Code)
   →  MCP Server
   →  WebSocket (localhost)
   →  BraveBridge Extension
   →  Your Browser (Real Sessions)

I exposed 13 MCP tools: navigate, click, type, read_page, screenshot, scroll, key, select_all, read_elements, switch_tab, get_tabs, wait_for, and execute_script.

It worked. Claude could navigate to sites, read pages, click buttons, take screenshots, and type into inputs. I used it to browse X, read LinkedIn feeds, and interact with web apps.

The Hard Lessons

1. Manifest V3 kills your service worker

Chrome's Manifest V3 terminates service workers after 30 seconds of inactivity. Your WebSocket connection just dies. I had to add keepalive hacks: setInterval pings every 20 seconds plus chrome.alarms as a backup. It felt like duct tape.

2. CSS selectors are the wrong abstraction

LinkedIn's post composer? No standard selectors. X's tweet box? React contentEditable wrapped in proprietary components. I couldn't even find the text input on LinkedIn — their editor is completely invisible to CSS selector queries.

I tried every approach: [contenteditable], [role='textbox'], .ql-editor, [data-placeholder]. Nothing worked on modern React SPAs.

3. React contentEditable is a nightmare

On X, typing into the tweet composer garbled text. Hashtags duplicated, words jumbled. React doesn't handle dispatchEvent('input') properly on contentEditable elements. I ended up using a clipboard paste hack with DataTransfer and ClipboardEvent. It worked, but barely.

4. CSP blocks eval on major sites

My execute_script tool used eval() internally. X's Content Security Policy blocks it. I had to refactor to pre-compiled named functions passed to chrome.scripting.executeScript. Every "simple" feature had edge cases.


The Discovery

While debugging LinkedIn's impenetrable composer, I wondered: how does Anthropic's own Chrome extension handle this? They must have solved the same problems.

So I reverse-engineered it.

Key Finding. Claude's "Claude in Chrome" extension uses an accessibility tree instead of CSS selectors. It maps every interactive element to semantic roles (button, link, textbox) with ref IDs. No fragile selectors. No shadow DOM issues. No LinkedIn composer mystery.

Here's what I found when I dug into the extension files:

BraveBridge (mine) Claude in Chrome
Transport WebSocket (keepalive hacks) Native Messaging (stdio)
Element targeting CSS selectors (breaks on SPAs) Accessibility tree + ref IDs
Tools 13 primitives 22 tools + GIF recording
Page reading DOM-based (fragile) Semantic roles (robust)
Service worker sleep Manual keepalive Native messaging keeps alive
Setup Manual MCP config + server claude --chrome

The kill shot

I checked Brave's native messaging directory:

# Brave already has Claude's native messaging config
~/Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts/
  com.anthropic.claude_browser_extension.json

The Claude Chrome extension installs in Brave. The native messaging host is already configured. It just works.

Anthropic's docs say "not yet supported on Brave" — but that's just cautious messaging. The config is there. The extension installs. The connection works.

Verdict. I spent days building something that already exists and works better. Classic solo builder mistake: building before researching deeply enough.


Use Cases for AI Browser Automation

Even though BraveBridge is dead, the use cases are very much alive. Here's what AI + real browser access enables:

How to Set It Up (The Right Way)

Don't build what I built. Use Claude's official Chrome integration — and yes, it works on Brave.

The Brave Trick. Anthropic's docs say "not yet supported on Brave." But here's what actually works: install the Claude extension in Brave, close Chrome completely, then run claude --chrome. It connects to Brave instead. Your real Brave sessions, your real logins, fully working. I tested it — posted on LinkedIn with an image, all through natural language.

# 1. Install "Claude" extension from Chrome Web Store into Brave
# 2. Close Chrome completely (important!)
# 3. Launch Claude Code with Chrome flag
claude --chrome

# 4. Ask Claude to do anything in your browser
"Open LinkedIn and post about my latest project"
"Go to localhost:3000 and check for console errors"
"Extract all product prices from this page into a CSV"

That's it. No MCP server setup, no WebSocket bridges, no keepalive hacks. It uses native messaging (rock solid), accessibility trees (works on any site), and your real browser sessions (no detection).


What I Actually Learned

  1. Research before building. I could have found Claude's Chrome extension in 10 minutes. Instead I spent days building an inferior version. Always check if the problem is already solved.
  2. Accessibility trees beat CSS selectors. For any kind of browser automation, semantic element targeting is more robust than CSS selectors. LinkedIn's composer is invisible to CSS queries but fully visible in the accessibility tree.
  3. Native messaging beats WebSocket for extensions. No keepalive hacks, no service worker sleep issues, no port conflicts. Stdio transport is the right choice for extension-to-host communication.
  4. Kill your darlings fast. The moment I realized Claude's extension works on Brave, I killed BraveBridge. No sunk cost fallacy. The code taught me things; shipping it would teach me nothing new.
  5. Building "useless" things isn't useless. I now deeply understand Manifest V3, Chrome extension APIs, MCP protocol, WebSocket bridges, content script injection, and accessibility trees. That knowledge compounds.

Sometimes the best outcome of a project is knowing you don't need to build it.


Update: BraveBridge Is Back (April 17, 2026)

Plot twist. Two weeks after killing BraveBridge, I brought it back.

Here's what happened: I actually tried using Chrome DevTools MCP for real work. Logging into sites. Testing my own projects. Checking dashboards. And every session hit the same wall — the browser it opens is sandboxed. No saved cookies. No logged-in sessions. Cloudflare challenges on every major site.

The "Claude in Chrome" extension works on Brave, yes. But Chrome DevTools MCP — the tool that actually controls browser tabs — launches its own environment. That environment doesn't have your cookies. You're not logged in anywhere. Every Cloudflare-protected site throws a captcha. It's a clean room when you need a workshop.

The Comeback. BraveBridge's core advantage was always real: it connects to your actual browser. Same cookies, same sessions, same fingerprint. I just needed to close the feature gap. So I did.

What changed in v0.3.0

I took every capability that made Chrome DevTools MCP superior and built it into BraveBridge:

BraveBridge went from 13 tools to 29 tools. Every Chrome DevTools MCP capability that's possible without the debugger permission is now in BraveBridge.

BraveBridge v0.3.0 Chrome DevTools MCP
Browser context Real browser (cookies, sessions) Sandboxed (no saved state)
Cloudflare/captchas Rarely triggered Frequently triggered
Element targeting A11y tree + UIDs + CSS selectors A11y tree + UIDs
Tools 29 tools 25 tools
Performance tracing Not yet (needs debugger API) Full CDP access
Setup Extension + MCP config claude --chrome

Lesson Updated. "Kill your darlings fast" is still right. But so is "revive them when the landscape changes." The sandbox limitation of Chrome DevTools MCP wasn't obvious until I hit it in real workflows. BraveBridge's core bet — real browser, real sessions — turned out to matter more than I thought.

BraveBridge is now open source on GitHub. MIT licensed. If you want AI agents controlling your actual browser with your actual sessions, it's ready.

← All writing Get in touch →