chrome-cdp-manager
v1.2.3
Published
Set up and drive a Chrome DevTools Protocol (CDP) instance on macOS or Windows through a dedicated launcher (consistent Dock/taskbar icon). Works with any Chromium-based browser — Chrome, Edge, Brave, Chromium, Vivaldi, Opera, Arc.
Maintainers
Readme
chrome-cdp-manager
Set up and drive a Chrome DevTools Protocol (CDP) instance on macOS or Windows through a dedicated launcher, so launches always go through the same entry point and the Dock/taskbar icon stays consistent. Works with any Chromium-based browser — Chrome, Edge, Brave, Chromium, Vivaldi, Opera, Arc.
- macOS: builds a real
.appbundle (/Applications/ChromeCDP.app) with a properInfo.plistand the browser's own icon — launched viaopenso LaunchServices attaches a consistent Dock icon. - Windows: creates a Start Menu
.lnkshortcut with the CDP flags baked in and a custom icon — headed launches go through the shortcut for a consistent taskbar entry. - Connects over CDP with zero heavy dependencies — uses Node's built-in
fetchandWebSocket(no Playwright/Puppeteer, no browser download).
Requires Node.js ≥ 22 and a Chromium-based browser installed. On macOS, Apple Silicon (the launcher uses
arch -arm64).Non-Chromium browsers (Firefox, Safari) are not supported — they don't speak the same CDP this tool drives.
Usage
The package is published as chrome-cdp-manager; the command it installs is
chrome-cdp.
# Run without installing — invoke via the package name
npx chrome-cdp-manager setup
# Or install once, then use the `chrome-cdp` command
npm install -g chrome-cdp-manager# Create / repair the launcher and save defaults (port 9222, profile ~/.chrome_cdp_profile)
chrome-cdp setup
# Use a specific browser
chrome-cdp setup --browser edge
# See which browsers are installed
chrome-cdp browsers
# Launch ChromeCDP and open a page
chrome-cdp open https://example.com
# Same, headless (no window/Dock/taskbar)
chrome-cdp open https://example.com --headless
# Fetch a page's rendered HTML over CDP (headless by default)
chrome-cdp html example.com -o page.html
# Inspect state
chrome-cdp status
# Quit the running instance
chrome-cdp stopTip: with
npx, run it by package name —npx chrome-cdp-manager <command>— sincenpx chrome-cdpwould try to fetch an unrelatedchrome-cdppackage.
Commands
| Command | Description |
| ------------------ | ----------------------------------------------------------------- |
| setup | Create or repair the launcher (icon + CDP flags) |
| open [url] | Launch via the launcher, optionally open a URL; leaves it running |
| html <url> | Navigate and print/save the page's serialized HTML |
| status | Show launcher presence and CDP connection state |
| stop | Ask the running ChromeCDP instance to quit |
| browsers | List supported browsers and which are installed |
Programmatic API
Beyond the CLI, the package exposes a small ES-module API (Node ≥ 22).
import { launch, CdpClient } from "chrome-cdp-manager";
// Ensure ChromeCDP is running (launches it if needed) and get its endpoint.
const { endpoint, config, launched } = await launch({ headless: false });
// Drive it with the built-in zero-dependency raw-CDP client...
const cdp = await CdpClient.connect(config.cdpPort);Also exported: loadConfig, getLauncher, ensureBrowserRunning, probeCdp,
waitForCdp, openUrl, getPageHtml, closeBrowser.
Playwright bridge (optional)
If you want Playwright's high-level page API, opt into the separate entry point.
playwright is an optional peer dependency — the core stays dependency-free.
import { connect } from "chrome-cdp-manager/playwright";
await using session = await connect({ headless: false, match: u => u.includes("bing.com") });
await session.page.goto("https://www.bing.com");
// `await using` detaches the CDP channel on scope exit; the browser keeps running.connect() resolves config, ensures the launcher + a running browser, connects
Playwright over CDP, and returns { browser, context, page, config }. In
zero-install (npx) setups where Playwright can't be resolved automatically,
inject it: connect({ chromium }).
Common options
| Option | Description |
| ----------------------- | ------------------------------------------------------------- |
| --port <port> | CDP port (default 9222) |
| -p, --profile <dir> | Browser user-data-dir (default ~/.chrome_cdp_profile) |
| -b, --browser <name> | Browser: chrome, edge, brave, chromium, vivaldi, opera, arc |
| --path <path> | Explicit browser executable (overrides --browser) |
| --target <path> | Launcher location (.app on macOS, .lnk on Windows) |
| -t, --timeout <secs> | Startup / load timeout (open, html) |
-c, --chrome and --bundle remain as aliases for --path and --target.
Browser, port, profile and launcher path are baked into the launcher and
persisted (~/.config/chrome-cdp-manager/config.json) at setup time so every
command agrees on the same environment. Re-run setup --force after changing
them.
How the icon stays consistent
macOS — the bundle's executable is a small bash launcher:
exec arch -arm64 "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.chrome_cdp_profile" \
"$@"Headed launches go through open /Applications/ChromeCDP.app, so LaunchServices
runs the browser under the ChromeCDP bundle identity — a consistent Dock icon
every time instead of a generic/duplicated entry.
Windows — a Start Menu .lnk shortcut (ChromeCDP.lnk) is created with the
browser as its target, the CDP flags as its arguments, and the browser's icon.
Because the dedicated --user-data-dir gives the browser its own
AppUserModelID, the ChromeCDP window gets its own pinnable taskbar entry,
separate from your everyday browser windows.
