# cdpilot > Zero-dependency browser automation from your terminal. One command, full control. [![npm version](https://img.shields.io/npm/v/cdpilot.svg)](https://www.npmjs.com/package/cdpilot) [![npm downloads](https://img.shields.io/npm/dm/cdpilot.svg)](https://www.npmjs.com/package/cdpilot) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) [![Node.js](https://img.shields.io/badge/Node.js-18%2B-339933)](https://nodejs.org) [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-blue)](https://modelcontextprotocol.io) [![cdpilot MCP server](https://glama.ai/mcp/servers/mehmetnadir/cdpilot/badge)](https://glama.ai/mcp/servers/mehmetnadir/cdpilot)
cdpilot demo
## Quick Start ```bash npx cdpilot launch # Start browser with CDP npx cdpilot go https://example.com npx cdpilot shot # Take screenshot ``` No config files. No boilerplate. Just `npx` and go. ## Why cdpilot? AI agents and developers need browser control that **just works**: - **Zero config** — `npx cdpilot launch` starts an isolated browser session - **Zero dependency** — No Puppeteer, no Playwright, no Selenium. Pure CDP over HTTP - **70+ commands** — Navigate, click, type, screenshot, network, console, accessibility, video understanding, progressive anti-bot resilience, and more - **AI-agent friendly** — Designed for Claude, GPT, Gemini, and any LLM tool-use workflow - **Isolated sessions** — Your personal browser stays untouched. cdpilot runs in its own profile - **Visual feedback** — Green glow overlay, cursor visualization, click ripples, and keystroke display keep you informed during automation - **Multi-project isolation** — Each project gets its own browser instance and port automatically, no conflicts - **AI control warning** — Red toast notification appears when you hover during active automation - **Privacy-first** — Everything runs locally. No data leaves your machine ### Browser Selection (Workload-Aware Auto-Pick) cdpilot picks the right browser for what you're doing. `auto` (default) is a two-axis policy — extension workload × platform stability: | Your workload | Auto-pick order | |---|---| | Has extensions registered (`ext-install`) | vivaldi → brave → edge → chromium → chrome (→ Chrome for Testing, if installed) | | No extensions (pure automation) | chrome → vivaldi → edge → chromium → brave | Override anytime: ```bash cdpilot browser # show current pick + reason cdpilot browser vivaldi # pin to Vivaldi cdpilot browser chrome-for-testing # pin to Chrome for Testing (after installing it, below) cdpilot browser auto # restore smart default ``` **Why the split?** - **Chrome 137+ silently drops `--load-extension`** for unpacked extensions (no error, no warning) — Google removed it from branded Chrome builds ([PSA](https://groups.google.com/a/chromium.org/g/chromium-extensions/c/1-g8EFx2BBY/m/S0ET5wPjCAAJ)). Verified — `chrome://extensions` shows 0 items. - **Vivaldi, Brave, Edge, Chromium and Chrome for Testing** honor `--load-extension` (tested). - On **macOS 26 (Tahoe)** Brave 1.89 crashes deterministically at ~7min uptime (SIGTRAP in ThreadPoolForegroundWorker). cdpilot detects the OS and demotes Brave automatically until a fixed Brave release ships. Each browser gets its own isolated profile (`~/.cdpilot/.../profile-vivaldi` etc.) so switching never causes prefs corruption. ### Extension development: Chrome for Testing If you develop an extension against Chrome itself, install [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing) (CfT) — the Chrome team's versioned, non-auto-updating Chrome build for automation, which still loads unpacked extensions: ```bash cdpilot browser install chrome-for-testing # latest Stable cdpilot browser install chrome-for-testing --channel beta # stable | beta | dev | canary cdpilot browser install chrome-for-testing --version 154 # a milestone, or a full version (154.0.8037.57) cdpilot ext-install ./my-extension/ # register your unpacked extension cdpilot browser status # shows the CfT version and path ``` - **Download only on that command.** It is a one-time ~150-190 MB zip (mac-arm64 at 154.0.8037.57: 191,429,663 bytes); cdpilot never fetches it by itself. The build comes from the official [CfT JSON endpoints](https://googlechromelabs.github.io/chrome-for-testing/) (`last-known-good-versions-with-downloads.json`, per-version and per-milestone files). Those list URLs only, no hash, so the download is checked against the server's `Content-Length` and its `x-goog-hash` md5; the zip's SHA-256 is recorded. - It is extracted to `$CDPILOT_HOME/browsers/chrome-for-testing//` (on macOS the quarantine attribute is cleared on that directory only) and recorded in `installed.json`. - **Used automatically for extension work:** while dev extensions are registered, a branded Chrome pick (`cdpilot browser chrome`, or `auto` with Chrome the only extension-capable choice) becomes Chrome for Testing, with one stderr line saying so. Without CfT installed, `ext-install` on Chrome prints the install command and keeps Vivaldi/Brave as the alternative. `cdpilot browser chrome-for-testing` selects it always. An explicit `CHROME_BIN` is never replaced. - It runs with cdpilot's usual per-project isolated profile (`profile-cft`). - **It is for extension development and testing — not a stealth browser.** cdpilot makes no anti-bot claims for it; use your regular browser setup for that. - **Linux (Ubuntu 23.10+):** AppArmor blocks unprivileged user namespaces, and CfT (unlike the distro's Chrome package) has no profile allowing them, so it exits at start. cdpilot prints this hint; allow them with `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0`. ## Installation ```bash # Use directly (no install needed) npx cdpilot # Or install globally npm i -g cdpilot ``` **Requirements:** Node.js 18+, Python 3.10+, and one of: Brave Browser, Google Chrome, or Chromium. (The Python `websockets` module is auto-installed by the pre-flight wizard on first launch.) ### First-time setup ```bash npx cdpilot setup # Auto-detect browser, create isolated profile npx cdpilot launch # Start browser with CDP enabled npx cdpilot status # Check connection ``` ### Claude Code plugin marketplace Install cdpilot's MCP server and its skill straight into Claude Code, no `.mcp.json` editing required: ```bash /plugin marketplace add mehmetnadir/cdpilot /plugin install cdpilot@cdpilot ``` This registers the `cdpilot` MCP server (`npx cdpilot mcp`) and a short skill that teaches Claude Code when and how to reach for cdpilot's commands. See [`.claude-plugin/marketplace.json`](.claude-plugin/marketplace.json) and [`plugins/cdpilot/`](plugins/cdpilot/). ### MCP Bundle (.mcpb) For MCP clients that support one-click local server installation (Claude Desktop and others), download the `.mcpb` file attached to the [latest release](https://github.com/mehmetnadir/cdpilot/releases/latest) and open it, or build it yourself: ```bash npm run build:mcpb # writes cdpilot.mcpb at the repo root ``` The bundle still needs the same runtime on the machine that runs it: Node.js 18+, Python 3.10+, and Brave/Chrome/Chromium installed. See [`manifest.json`](manifest.json) for the bundle's MCP Bundle manifest ([spec](https://github.com/modelcontextprotocol/mcpb)). ### Upgrading from 0.4.x → 0.5.0 — read this first **One breaking change**, the rest is additive. **Breaking — Visual feedback default flipped to OFF.** The green glow border, animated fake cursor, click ripples, and keystroke display made cdpilot feel like an amateur typing on every page. They are now opt-in: ```bash cdpilot show on # restore the old visual feedback layer cdpilot show off # default since 0.5.0 ``` The MCP server's persistent-glow flow (`CDPILOT_MCP_SESSION=1`) is **unchanged** — AI agents that rely on visible feedback during a session still see it automatically. Only direct-CLI users see the difference. **New in 0.5.0** (no migration needed): - `cdpilot dismiss` — heuristic auto-click for "Stay signed out / No thanks" buttons on LLM chat sign-up walls. - `cdpilot adaptive on` — auto-escalate to stealth on CAPTCHA-protected hosts, with persistent per-host memory. - `cdpilot cookies save/load` — export/import cookies as JSON to replay CF/DataDome clearance across runs. - `cdpilot context create/list/close` + `CDPILOT_TARGET` — isolated browser contexts for true parallel automation inside a single browser. - `cdpilot fast` / `cdpilot show` — bundled timing + visual toggles. - Pure performance: post-load sleep 1500ms → 300ms, `scrollIntoView` instant, WebSocket connection pool, `/json` TTL cache. See [CHANGELOG.md](CHANGELOG.md) for the full list with rationale. ## Commands ### Navigation & Content ```bash cdpilot go # Navigate to URL (alias: open ) cdpilot content # Get page text content cdpilot html # Get page HTML cdpilot shot [file] # Take screenshot (PNG) cdpilot pdf [file] # Save page as PDF ``` ### Interaction ```bash cdpilot click # Click element cdpilot type # Type into input cdpilot fill # Set input value (React-compatible) cdpilot submit
# Submit form cdpilot hover # Hover element cdpilot keys # Keyboard shortcut (ctrl+a, enter, etc.) cdpilot scroll-to # Scroll element into view cdpilot drag # Drag and drop ``` A real mouse click (inside a frame, or `--entropy=on`) whose target moves or gets covered while the button is held is not clicked again by script: `click` prints `Pressed (released elsewhere, not clicked): …` and ends with **exit 3** (pressed, release missed the target, not clicked; `1` stays "error"). A target the page replaced or navigated away from on mousedown prints `Pressed (the page replaced or left it, not clicked): …` and exits 0. MCP (`browser_click`, `browser_smart_click`) returns `isError: false` with a first line `{"clicked": false, "reason": "moved"|"gone"|"unknown"}`. `batch` and `run` finish every step, then exit 1 if a step failed, else 3 if a click was not clicked, else 0. ### Element targeting inside iframes Card forms (Stripe/iyzico-style), embedded login widgets and the reCAPTCHA checkbox live inside `