Drive your real, already-running Chrome — your actual tabs, logins, cookies, and extensions — from the command line. Built for humans and AI agents alike: every command speaks one JSON envelope and one stable exit-code contract.
chrome-cdp open https://example.com # open a tab, get its id
chrome-cdp snap --role button # see what's clickable — by accessible name
chrome-cdp click --by name "Sign in" # act by meaning, not a brittle CSS idBecause it attaches to the browser you're already using, an app you're signed into loads authenticated — no headless browser, no second login, no credential ever typed.
-
Install — macOS via Homebrew, or Go:
brew install --cask sanketsudake/tap/chrome-cdp # or: go install github.com/sanketsudake/chrome-cdp-cli/cmd/chrome-cdp@latestRecent Homebrew may print a tap-trust notice for third-party taps on first install. The install still proceeds; to acknowledge it explicitly, run
brew trust --cask sanketsudake/tap/chrome-cdpfirst. -
Let Chrome accept a debugger — open
chrome://inspect/#remote-debuggingand toggle it on (a one-time consent;chrome-cdpnever suppresses it). -
Check the connection —
chrome-cdp doctorconfirms it's ready, or prints the exact fix. -
Drive it:
chrome-cdp use url:github # pick a tab; later commands need no --target chrome-cdp snap # read the page as an accessibility tree chrome-cdp click --by name "New" --role button
That's the whole loop: list → use → snap → act → verify.
The logged-in web app guide walks it end to end.
- Your real session. It drives the Chrome you're logged into — real cookies, SSO, extensions — so there's nothing to authenticate and no secret to store.
- Address by meaning. Target controls by ARIA accessible name, visible label, or grid cell — not CSS ids that change every session. Reads and writes survive the app's cosmetic churn.
- Made for automation. One JSON envelope, one exit-code contract; a background daemon holds the connection so the consent prompt appears once per session, not per command.
- Drives the hard widgets.
Portal menus, multi-level cascade prompts, and native
<select>s that a synthetic click can't open — theselectverb opens them. - Works on modern Chrome.
It reads Chrome's
DevToolsActivePortand connects directly, so it keeps working where the classic--remote-debugging-portflag stopped (default profile, Chrome M136+).
chrome-cdp list --url outlook # list tabs (--url/--title filter)
chrome-cdp snap --role button --grep "[AP]M" # filter the a11y tree server-side
chrome-cdp grid # read a table as {headers, rows}
chrome-cdp fill --by cell "Mon, 7/13" "8" # a grid input by its column header
chrome-cdp fill --by label "Notes" "hi" # a form control by its visible label
chrome-cdp select "Time Type" "Projects > Acme: Platform > Project > Time Entry" --role textbox
chrome-cdp click --by name "Approve" --role button --wait-text "Success" # act, then confirm
chrome-cdp wait --idle # settle an SPA (network, not a fixed sleep)
chrome-cdp raw Network.setCacheDisabled '{"cacheDisabled":true}' # any CDP methodFull command, flag, and exit-code tables live in the CLI reference.
chrome-cdp is meant to be a tool an agent calls: snap returns the page's actionable structure as text (roles, names, states, refs) instead of pixels, every result is one parseable envelope, and failures classify by exit code so the agent branches on a number, not on prose.
See Using chrome-cdp from an AI agent.
An Agent Skill that teaches the whole loop ships in skills/drive-chrome-cdp — point your harness at it.
Persist flags you'd otherwise retype in ~/.config/chrome-cdp/config.toml — see config.example.toml.
json = true # default to machine-readable output
timeout = "10s"
target = "url:github" # default tab when neither --target nor `use` is setPrecedence, highest first: command-line flag > CHROME_CDP_* env var > config file > built-in default.
Shell completion is built in: chrome-cdp completion bash|zsh|fish|powershell.
A live debug endpoint is full control of whatever your Chrome is signed into — treat enabling chrome://inspect like opening a local root shell into your browser's sessions, and only do it when you intend to automate.
- Loopback only.
It connects to
127.0.0.1and never binds the debug port to a non-loopback interface. It never suppresses Chrome's "Allow debugging?" consent or the automation banner. - Don't pass secrets as arguments.
type <selector> <text>takes text as a positional argument, visible inpsand shell history — don't type passwords through it on a shared machine. - Managed-launch fallback uses your system Chrome with a dedicated profile and does not disable the sandbox.
- CLI reference — commands, flags, exit codes, output contract.
- Automating a logged-in web app — the core loop.
- Forms and grids — label / cell addressing and batched fills.
- Driving widgets with
select— menus, cascades, native selects. - Using chrome-cdp from an AI agent — the agent-tool design.
go build -o chrome-cdp ./cmd/chrome-cdp
go test ./... # spawns a headless Chrome for the integration tests
go test -short ./... # skip the live-Chrome testsArchitecture: internal/result (envelope + exit codes), internal/target (target grammar), internal/browser (connection logic), internal/chrome (chromedp-backed driver), internal/daemon (the held-connection RPC), internal/cli (the cobra command tree).
Released under the MIT License.