Dead simple Chrome automation from the command line.
No Puppeteer. No Playwright. No framework. Just a CLI that talks to Chrome via CDP (Chrome DevTools Protocol).
Puppeteer and Playwright are libraries — you write code. chrome-ctl is a tool — you run commands. Perfect for shell scripts, CI pipelines, AI agents, or anyone who just wants to automate something without writing a Node.js program.
npm install -g chrome-ctlOr clone and link:
git clone https://github.com/polishfreak/chrome-ctl.git
cd chrome-ctl
npm install
npm linkchrome-ctl launchThis opens a visible Chrome window with remote debugging enabled. Log into whatever sites you need (Gmail, LinkedIn, etc.), then close Chrome. Your session is saved to ~/.chrome-ctl-data/.
Next time you run chrome-ctl launch, you're already logged in. Now you can automate — or run headless:
chrome-ctl launch --headlessPoint to your existing profile instead:
# Linux (Chrome)
chrome-ctl launch ~/.config/google-chrome
# Linux (Chromium snap)
chrome-ctl launch ~/snap/chromium/common/chromium
# macOS
chrome-ctl launch "$HOME/Library/Application Support/Google/Chrome"Note: You can't use your main Chrome profile while Chrome is already running. Either close Chrome first, or use the default
~/.chrome-ctl-data/profile and log in there.
# Launch Chrome with remote debugging
chrome-ctl launch
# Navigate somewhere
chrome-ctl navigate "https://example.com"
# See what's on the page
chrome-ctl snapshot | head -50
# Click a button
chrome-ctl click '#submit-btn'
# Type into a field
chrome-ctl type 'input[name="email"]' "me@example.com"
# Run JavaScript
chrome-ctl evaluate "document.title"
# Take a screenshot
chrome-ctl screenshot page.png| Command | Description |
|---|---|
launch [data-dir] |
Launch Chrome with remote debugging |
tabs |
List open tabs |
navigate <url> |
Navigate to a URL |
snapshot |
Get the accessibility tree (JSON) |
click <selector> |
Click an element (CSS selector) |
type <selector> <text> |
Type text into an element |
evaluate <js> |
Run JavaScript in the page |
screenshot [path] |
Take a PNG screenshot |
wait <ms> |
Wait N milliseconds |
| Flag | Description |
|---|---|
--port <n> |
Chrome debugging port (default: 9222) |
--headless |
Launch in headless mode |
| Variable | Default | Description |
|---|---|---|
CHROME_CTL_PORT |
9222 |
Debugging port |
CHROME_CTL_BINARY |
auto-detected | Path to Chrome/Chromium |
CHROME_CTL_TYPE_DELAY |
50 |
Typing delay per character (ms) |
All commands output JSON. Pipe it, parse it, script it:
# Get current page URL
chrome-ctl evaluate "window.location.href" | jq -r '.result'
# List all tab URLs
chrome-ctl tabs | jq '.[].url'
# Check if element exists
chrome-ctl evaluate "!!document.querySelector('.login-btn')" | jq '.result'Exit code 0 on success, 1 on error.
chrome-ctl launch
chrome-ctl navigate "https://myapp.com/login"
chrome-ctl wait 2000
chrome-ctl type '#username' "admin"
chrome-ctl type '#password' "hunter2"
chrome-ctl click 'button[type="submit"]'
chrome-ctl wait 3000
chrome-ctl screenshot logged-in.pngchrome-ctl navigate "https://news.ycombinator.com"
chrome-ctl evaluate "Array.from(document.querySelectorAll('.titleline a')).slice(0,10).map(a => ({title: a.textContent, url: a.href}))"If Chrome is already running with --remote-debugging-port:
# Connect to Chrome on a custom port
chrome-ctl --port 9333 tabs
chrome-ctl --port 9333 navigate "https://example.com"chrome-ctl launch --headless
chrome-ctl navigate "https://example.com"
chrome-ctl screenshot result.png# Linux (Chromium snap)
chrome-ctl launch ~/snap/chromium/common/chromium
# macOS
chrome-ctl launch "$HOME/Library/Application Support/Google/Chrome"This preserves your logged-in sessions, cookies, and extensions.
chrome-ctl launchstarts Chrome/Chromium with--remote-debugging-port- All other commands connect via WebSocket to Chrome's DevTools Protocol
- Commands use CDP domains:
Page,Runtime,Input,Accessibility,DOM - Output is JSON, errors go to stderr
That's it. No daemon, no server, no framework. Just a CLI and a WebSocket.
| chrome-ctl | Puppeteer | Playwright | |
|---|---|---|---|
| Interface | CLI | Node.js API | Node.js/Python/etc API |
| Setup | npm i -g |
npm i puppeteer + code |
npm i playwright + code |
| Use case | Shell scripts, quick automation | Full test suites | Cross-browser testing |
| Learning curve | 5 minutes | Hours | Hours |
| Dependencies | 1 (chrome-remote-interface) | Bundled Chromium + libs | Bundled browsers + libs |
| Size | ~50KB | ~400MB | ~600MB |
chrome-ctl is not a replacement for Puppeteer/Playwright in complex test suites. It's for when you just want to automate something right now without writing a program.
- Node.js 16+
- Chrome or Chromium installed
MIT