# Show HN: Agent-Chrome – Claude Code browses in Chrome without stealing focus

> Source: <https://github.com/rav4nn/agent-chrome>
> Published: 2026-10-02 09:12:32+00:00

agent-chrome lets Claude Code use a copy of your signed-in Chrome. The window opens behind your other apps, so you keep typing while Claude browses as you.

**Website**[Install](#set-it-up-in-five-steps)    [How it works](#why-the-window-stays-behind)    [Watch the 1:26 video](https://agentchrome.hardeep.cv/demo.mp4)

**Same prompt, two setups.** Playwright MCP pulls Chrome to the front on every call, and what you type next lands in the browser.

agent-chrome opens the tabs in a red window behind your terminal. Focus stays where you left it.

```
/plugin marketplace add rav4nn/agent-chrome
```

Free and open source. Needs macOS, Google Chrome, Node 18.3 or later, and Claude Code.

Headless Playwright never takes focus, but you can't see what it's doing. The other tools show you a window, then pull it in front of your work. agent-chrome gives you a window you can watch, and keeps it behind your terminal.

|  | **agent-chrome** | Playwright MCP <sub>headless</sub> | Playwright MCP <sub>extension mode</sub> | Chrome DevTools MCP <sub>default setup</sub> | 
|---|---|---|---|---|
| **You can watch it work**<sub>Open the window any time and see what Claude is doing, then fix your prompt or skill.</sub> | ✅ | ❌ | ✅ | ✅ | 
| **You can take over a login**<sub>When Claude stops at a sign-in, a 2FA code or a CAPTCHA, click in and finish it.</sub> | ✅ | ❌ | ✅ | ✅ | 
| **You keep typing**<sub>The browser never jumps in front of your terminal.</sub> | ✅ | ✅ | ❌ | ❌ | 
| **Uses your Chrome sign-ins**<sub>The accounts you already use in Chrome are there on the first run.</sub> | ✅ | ❌ | ✅ | ❌ <sub>separate profile</sub> | 
| **Looks like a normal browser**<sub>Some sites, like X and LinkedIn, flag headless and automated browsers.</sub> | ✅ | ➖ <sub>often flagged</sub> | ✅ | ➖ <sub>automation flag on</sub> | 
| **Sessions share one browser**<sub>Several Claude Code sessions use the same signed-in window at once.</sub> | ✅ | ❌ <sub>profile lock</sub> | ✅ | ❌ <sub>profile lock</sub> | 

✅ yes   ➖ partly   ❌ no. Default setups on macOS, checked October 2026. Chrome DevTools MCP can attach to your own Chrome with `--autoConnect`.

About two minutes.

Press `⌘` `Q` in Chrome. Closing the window isn't enough.

agent-chrome copies your Chrome profile. If Chrome is running, the copy can lose its sign-ins.

In Claude Code, run these two commands:

```
/plugin marketplace add rav4nn/agent-chrome
/plugin install agent-chrome@agent-chrome
```

The plugin teaches Claude how to set up and use agent-chrome. It doesn't give Claude a browser yet. Step 3 does.

## **Rather not use the plugin?**

Run the setup CLI with npx. No clone needed:

```
npx github:rav4nn/agent-chrome profiles
npx github:rav4nn/agent-chrome add "Work"
```

Or clone the repo:

```
git clone https://github.com/rav4nn/agent-chrome.git
cd agent-chrome
node bin/agent-chrome.mjs profiles
node bin/agent-chrome.mjs add "Work"
```

Then go on with step 4.

Ask Claude:

```
Set up agent-chrome for one of my Chrome profiles.
```

Claude lists your Chrome profiles and asks which one you want. Pick one, say **Work**.

macOS then tells you that `agent-chrome-work` can run in the background. That's the small proxy for this profile. It uses about 25 MB of memory while it waits.

Start a new Claude Code session (or resume one) so the new `chrome-work` tools load. Then ask:

```
Open chrome-work and go to myaccount.google.com. Tell me which Google account is signed in. Don't click or change anything.
```

Keep typing while it runs. The agent window has a red theme and opens behind your terminal.

When Claude is done, quit the red Chrome from the Dock. Then ask:

```
Open chrome-work and go to example.com.
```

The window comes back behind your apps, still signed in. Only you ever close it.

Each profile you add becomes its own MCP server, `chrome-<name>`. Say the name and Claude uses that profile, with whatever accounts it's signed in to. Without a name, Claude asks which one you mean.

```
Open chrome-work and go to reddit.com. Open the first 3 posts and summarise them.
Open chrome-work and check my GitHub notifications. List the ones that need a reply.
Open chrome-personal and find the tracking link for my last Amazon order.
```

On macOS, Chrome jumps to the front each time a tool talks to it over its debug port ([chrome-devtools-mcp#1254](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1254)). The WebSocket transport activates Chrome.app, and no `bringToFront: false` setting helps. A pipe (`--remote-debugging-pipe`) doesn't trigger that, but only the program that launched Chrome can hold the pipe. So two Claude sessions either fight over the profile lock or each start a throwaway Chrome, and you sign in again every session.

agent-chrome runs a small proxy for each profile. The proxy holds the pipe to Chrome, and every Claude session connects to the proxy. Several sessions share one signed-in Chrome, and none of them steals focus.

About 500 lines of Node.js. One dependency (`ws`). Localhost only. No telemetry. MIT.

## **How the multiplexing works**

The proxy launches Chrome with `--remote-debugging-pipe`, which gives a JSON-over-stdio CDP channel to the launching process only. It then serves a localhost HTTP and WebSocket interface in the same format as Chrome's `--remote-debugging-port` discovery (`/json/version`, `/json/list`, a browser-level WebSocket). `chrome-devtools-mcp --browserUrl http://127.0.0.1:9410` connects without knowing it isn't talking to Chrome.

Three patterns let many MCP clients share one pipe:

- **Request-ID remapping.** Each client numbers its requests`1, 2, 3, ...` on its own, and those ids would collide on the pipe. The proxy rewrites every incoming`id` to a unique proxy id, records`proxyId → {client, originalId, method}` , forwards to Chrome, and restores the original id on the response.
- **Cached target state.** The proxy turns on target discovery and auto-attach itself and caches every target and session. When a client asks for discovery or auto-attach, the proxy replays the cache to that client instead of forwarding the call.
- **Shared sessions.** Chrome's events go to every client. Clients ignore events for sessions they don't track.

```
[Claude session A] chrome-devtools-mcp ─┐
[Claude session B] chrome-devtools-mcp ─┼── WebSocket(127.0.0.1:9410) ── proxy ── stdio pipe ── [Chrome, profile copy]
[Claude session C] chrome-devtools-mcp ─┘
```

## **Why not run Playwright headless?**

You can't see a headless browser. With agent-chrome you can open the red window any time, watch what Claude does, and fix your prompt or skill when it goes wrong. If it stops at a login, a 2FA code or a CAPTCHA, you click in and finish that step yourself. Playwright also uses its own profile, so your Chrome sign-ins aren't there, and you can't sign in to a window you can't see. agent-chrome uses a copy of your real, signed-in Chrome.

## **Can websites tell that Claude is driving the browser?**

Sometimes. agent-chrome starts Chrome with `--disable-blink-features=AutomationControlled`, so `navigator.webdriver` is false and the cheapest check fails. But a site can still spot the attached debugger, and it can watch how the page gets used: clicks with no mouse movement, text that appears all at once, actions faster than a person. Your real profile, with its history and cookies, helps a lot. It doesn't make Claude invisible.

## **Can I use stealth Chrome instead?**

For hiding automation, stealth builds like Patchright go further than agent-chrome. They hide debugger traces that agent-chrome doesn't. But they don't fix focus or sharing. The tool that launches the browser owns it. Over a pipe, only that one Claude session can drive it, and a second session hits the profile lock. Over a debug port, several sessions can connect, but that's the path that pulls Chrome to the front on macOS. agent-chrome's proxy holds the pipe and lets every session share it. And point stealth at real Chrome, not Chromium: Chromium can't read the cookies in a copied Chrome profile, so you'd start signed out.

## **What about computer use?**

Computer use moves your real mouse and types with your keyboard, so you can't work while it runs. It reads a screenshot at every step, which makes it slow, and one screen means one agent at a time. agent-chrome works in a window behind yours, and you keep your keyboard.

## **Does Claude use my real Chrome profile?**

No. It uses a copy. Chrome refuses remote debugging on its default data folder (`DevTools remote debugging requires a non-default data directory.`), so agent-chrome copies the profile instead of using it in place. This is separate from the Chrome 136+ port restriction. On APFS the copy takes no extra disk space until the two drift apart. Your own Chrome stays yours.

## **I signed in to a site in my own Chrome. Why is the agent window signed out?**

The copy doesn't pick up new sign-ins. Sign in inside the red window once, or quit Chrome and run `add "Work" --recopy` for a fresh copy.

## **How much memory does it use?**

The proxy uses about 25 MB while it waits, and no CPU. An open agent window is a separate, full Chrome: about 500 MB for one simple page. Heavy sites and long uptime add more: one with Gmail open for a day measured 1.6 GB. Quit the window to free it.

## **What syncs back to my Google account?**

`add` turns off sync in the copy for themes, typed URLs, tabs, tab groups, extensions and apps. The copy is its own sync device. Passwords, bookmarks, autofill and settings still sync, so a password or bookmark that the agent saves reaches your real Google account.

## **Does my password manager work in the agent window?**

No. Extensions are off there. Sign in by hand once, or let Chrome's own password manager fill the form.

## **Can two Claude sessions use the same profile?**

Yes. They share one agent window, and every session can see and drive every tab in it. The proxy doesn't enforce tab ownership. The plugin's skill tells each Claude session to work only in the tabs it opened, which keeps sessions out of each other's way, but it's a convention, not a security boundary. Two sessions that enable Runtime on the same tab at the same moment can race.

## **Can a website connect to the proxy?**

No. Whoever connects controls a signed-in browser, so the proxy refuses any request with an `Origin` header (browsers send one, so a web page can't connect to `127.0.0.1`) and any `Host` other than `127.0.0.1`, `localhost` or `[::1]` (DNS rebinding). Other programs on your Mac can still connect, the same as with Chrome's own debug port.

## **Can I use Playwright through the proxy?**

No. Playwright's `connectOverCDP` doesn't work through the proxy. Use chrome-devtools-mcp, which the setup registers for you.

## **Windows or Linux?**

Not yet. The focus bug is a macOS problem, and the setup CLI is macOS only. The pipe multiplexer itself would work there.

## **How do I remove it?**

Ask Claude to remove agent-chrome for chrome-work, or run `npx github:rav4nn/agent-chrome remove work`. It stops the proxy, removes the login item and unregisters the MCP server. Add `--delete-profile` to delete the copy too.

| Command | What it does | 
|---|---|
| `profiles` | Lists your Chrome profiles (folder, name, email) and the slug of each one you've set up | 
| `add <profile>` | Sets up a profile. `<profile>` is its folder (`"Profile 5"` ), display name or email | 
| `remove <slug>` | Stops the proxy, deletes its LaunchAgent and unregisters the MCP server. Keeps the copy | 
| `status` | One row per installed slug: port, proxy up, agent window open, MCP server registered | 
| `update` | Refreshes the proxy code in the runtime folder and restarts every proxy | 

Options for `add`:

| Option | Default | Meaning | 
|---|---|---|
| `--name <slug>` | the profile's name, lowercased, with hyphens | MCP server is `chrome-<slug>` | 
| `--port <n>` | first free port from 9410 | Proxy port | 
| `--color <#rrggbb>` | `#D50000` | Theme colour of the agent window | 
| `--recopy` | off | Replace an existing copy with a fresh one from your real profile | 
| `--force` | off | Copy while Chrome is running. Live databases may copy in a mixed state, and the copy can lose sign-ins | 
| `--dry-run` | off | Print the plan, change nothing | 

`remove` takes `--delete-profile` to delete the copy too, and `--dry-run`. `update` takes `--dry-run`.

Running `add` again for the same profile is safe. It keeps the existing copy and port, and rewrites the theme, LaunchAgent and MCP server.

1. Copies the profile into `~/Library/Application Support/agent-chrome/profiles/<slug>/` . It uses an APFS clone, so the copy is fast and takes no extra disk space until the two drift apart.
2. Gives the copy a coloured theme (default `#D50000` ), so you can tell the agent window from yours.
3. Turns off sync in the copy for themes, typed URLs, tabs, tab groups, extensions and apps. Synced themes would push the agent colour back into your real profile, and agent history would land in it.
4. Installs the proxy in `~/Library/Application Support/agent-chrome/runtime/` and a LaunchAgent,`io.github.rav4nn.agent-chrome.<slug>` , that starts it at login through a small launcher,`launchers/agent-chrome-<slug>` . Logs go to`~/Library/Logs/agent-chrome/<slug>.log` . Activity Monitor lists the proxy as`node` . You can turn the login item off in System Settings > General > Login Items & Extensions, but then Claude can't open that profile.
5. Registers a user-scope MCP server, `chrome-<slug>` : chrome-devtools-mcp pointed at the proxy's port. It uses your global`chrome-devtools-mcp` if you have one, and`npx chrome-devtools-mcp@latest` if not. Without the`claude` CLI on your PATH, it prints the JSON to paste into`~/.claude.json` .

Add `--dry-run` to see every file write and command without running any of them.

- The tools are `mcp__chrome-<slug>__*` , from chrome-devtools-mcp.
- Open pages with `new_page` and`background: true` . The first new tab starts Chrome.
- Each session works only in the tabs it opened. That's a rule in the plugin's skill, not something the proxy enforces: all sessions share one window and can see and drive every tab in it.
- Only you close the agent window. After you quit it, the tools report no pages. The next `new_page` opens it again.
- When the last agent tab closes (Quit, the window's close button, or the last tab), the proxy exits that Chrome, so no empty Chrome stays in the Dock.
- If a site shows you signed out, sign in inside the agent window.

The plugin's skill tells Claude all of this.

The CLI covers the usual setup. To run the proxy yourself:

```
npm install --omit=dev
node pipe-cdp-proxy.mjs --port 9410 \
  --user-data-dir "$HOME/Library/Application Support/Chrome-Pipe-Proxy" \
  --profile-directory Default
```

| Flag | Default | Description | 
|---|---|---|
| `--port` | `9410` | Port the proxy listens on for MCP clients | 
| `--chrome-path` | `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` | Chrome binary | 
| `--user-data-dir` | `$HOME/Library/Application Support/Chrome-Pipe-Proxy` | Chrome data folder. Must not be Chrome's default | 
| `--profile-directory` | `Default` | Profile folder inside `--user-data-dir` | 

Health check:

```
curl -s http://127.0.0.1:9410/proxy/status
```

It returns `chromeRunning`, `chromePid`, `clients` and cache counts. Set `PROXY_DEBUG=1` to log every CDP message.

```
npm test                          # CLI unit tests, and the proxy's local-tools-only guard
node test/live-check.mjs <port>   # drives a real Chrome through a running proxy with its window closed
```

The live check loads Puppeteer from a global `chrome-devtools-mcp` install.

agent-chrome is a fork of [mimkorn/chrome-pipe-proxy](https://github.com/mimkorn/chrome-pipe-proxy). The proxy is the same idea. This fork adds a setup CLI, a Claude Code plugin and these proxy changes:

- `--profile-directory` picks the Chrome profile inside`--user-data-dir` .
- Chrome starts only when a client opens a tab or browser context. A connect, a discovery call or a page list while Chrome is down gets an empty browser, not a launch.
- No auto-restart. When you quit Chrome, the proxy drops its clients, and a reconnect doesn't bring the window back.
- New tabs open in the background. The proxy opens a new window only when none exists, and answers `Page.bringToFront` itself. Both used to raise the window on macOS, even over the pipe.
- The proxy sends `Runtime.disable` before a client's`Runtime.enable` on a shared tab, so a later session can take over a tab an earlier one left open.
- Each client's messages keep their order across the launch wait, and a malformed message no longer stops the queue.
- Chrome launches with no extensions, no startup window and no throttling of a window that sits behind other apps.
- Local tools only: the `Origin` and`Host` guard described in[Good to know](#good-to-know) . Upstream accepted both.
- The setup CLI, the Claude Code plugin and skill, and tests are new.

The proxy comes from [mimkorn/chrome-pipe-proxy](https://github.com/mimkorn/chrome-pipe-proxy) by Simon Democko. Its multi-client routing (request-ID remapping, session ownership) follows [henu-wang/chrome-mcp-proxy](https://github.com/henu-wang/chrome-mcp-proxy), which solves a different shape of the same problem with a WebSocket-to-WebSocket filter proxy.

MIT. See [LICENSE](https://github.com/rav4nn/agent-chrome/blob/main/LICENSE).
