chrome-cdp
Let your AI agent see and interact with your live Chrome session — the tabs you already have open, your logged-in accounts, your current page state. No browser automation framework, no separate browser instance, no re-login.
Works out of the box with any Chrome installation. One toggle to enable, nothing else to install.
Why this matters
Most browser automation tools launch a fresh, isolated browser. This one connects to the Chrome you're already running, so your agent can:
- Read pages you're logged into (Gmail, GitHub, internal tools, ...)
- Interact with tabs you're actively working in
- See the actual state of a page mid-workflow, not a clean reload
Installation
As a pi skill
pi install git:github.com/pasky/[email protected]
For other agents (Amp, Claude Code, Cursor, etc.)
Clone or copy the skills/chrome-cdp/ directory wherever your agent loads skills or context from. The only runtime dependency is Node.js 22+ — no npm install needed.
Enable remote debugging in Chrome
Navigate to chrome://inspect/#remote-debugging and toggle the switch. That's it.
The CLI auto-detects Chrome, Chromium, Brave, Edge, and Vivaldi on macOS, Linux, and Windows. If your browser stores DevToolsActivePort in a non-standard location, set the CDP_PORT_FILE environment variable to the full path.
Chrome-family auto-detection remains the default. Set CDP_BROWSER=chrome|chromium|brave|edge|vivaldi only when you want to pin a specific browser.
Optional: use Lightpanda as the primary backend
Lightpanda support is opt-in and attach-only. chrome-cdp does not start Lightpanda for you; start it yourself first:
lightpanda serve --host 127.0.0.1 --port 9222
CDP_BROWSER=lightpanda scripts/cdp.mjs list
Lightpanda endpoint selection uses this precedence:
CDP_LIGHTPANDA_WS_URL=ws://...
CDP_LIGHTPANDA_URL=http://127.0.0.1:9222
CDP_LIGHTPANDA_HOST=127.0.0.1 plus CDP_LIGHTPANDA_PORT=9222
chrome-cdp validates that /json/version reports Browser or User-Agent beginning with Lightpanda/. Use CDP_LIGHTPANDA_ALLOW_NON_LIGHTPANDA=1 only for deliberate test/proxy setups.
Lightpanda unsupported operations and fallback approval
[tag:lightpanda_fallback_consent] If Lightpanda reports an unsupported CDP method, chrome-cdp stops and prints LIGHTPANDA_UNSUPPORTED_FALLBACK_REQUIRED. It does not launch, connect to, clone into, map targets to, or run commands in a fallback browser automatically.
Fallback browser configuration is suggestion-only:
CDP_FALLBACK_BROWSER=chrome|chromium|brave|edge|vivaldi|none
CDP_FALLBACK_PORT_FILE=/path/to/fallback/DevToolsActivePort
CDP_FALLBACK_HOST=127.0.0.1
For example, CDP_FALLBACK_BROWSER=brave changes the prompt to suggest Brave; it does not contact Brave. CDP_FALLBACK_BROWSER=none suppresses the browser suggestion.
A fallback browser has separate state. It may lack cookies, login, localStorage, DOM mutations, typed text, JS heap, and current workflow state. If fallback is approved by the user, enable remote debugging in the chosen fallback browser, run CDP_BROWSER=<browser> scripts/cdp.mjs list or open in that browser, select a target from that fallback list, then rerun the original command with CDP_BROWSER=<browser> against that approved fallback target.
Usage
scripts/cdp.mjs list # list open tabs
scripts/cdp.mjs shot <target> # screenshot → runtime dir
scripts/cdp.mjs snap <target> # accessibility tree (compact, semantic)
scripts/cdp.mjs html <target> [".selector"] # full HTML or scoped to CSS selector
scripts/cdp.mjs eval <target> "expression" # evaluate JS in page context
scripts/cdp.mjs nav <target> https://... # navigate and wait for load
scripts/cdp.mjs net <target> # network resource timing
scripts/cdp.mjs click <target> "selector" # click element by CSS selector
scripts/cdp.mjs clickxy <target> <x> <y> # click at CSS pixel coordinates
scripts/cdp.mjs type <target> "text" # type at focused element (works in cross-origin iframes)
scripts/cdp.mjs loadall <target> "selector" # click "load more" until gone
scripts/cdp.mjs evalraw <target> <method> [json] # raw CDP command passthrough
scripts/cdp.mjs open [url] # open new tab (triggers Allow prompt)
scripts/cdp.mjs stop [target] # stop daemon(s)
<target> is a unique prefix of the targetId shown by list.
Why not chrome-devtools-mcp?
chrome-devtools-mcp reconnects on every command, so Chrome's "Allow debugging" modal can re-appear repeatedly and target enumeration times out with many tabs open. chrome-cdp holds one persistent daemon per tab — the modal fires once, and it handles 100+ tabs reliably.
How it works