| name | chrome-devtools-cli |
| description | Chrome DevTools Protocol CLI that auto-connects to existing Chrome for browser automation without heavyweight runtime overhead |
| triggers | ["automate Chrome browser","control Chrome DevTools","navigate browser and take screenshot","interact with web page using Chrome","click element in Chrome","run JavaScript in browser","inspect page accessibility tree","fill form in Chrome browser"] |
Chrome DevTools CLI
Skill by ara.so — Devtools Skills collection.
Chrome DevTools CLI is a lightweight Rust binary that connects directly to an existing Chrome browser via the DevTools Protocol. It auto-connects to your Chrome instance, requires no separate browser process, and provides a minimal-context alternative to MCP-based browser automation.
Why Use This
- Zero context overhead: One command in, one result out. No MCP layer, no large protocol payloads
- Uses your Chrome: Works with your existing browser session, credentials, and extensions
- Persistent connection: Background daemon keeps WebSocket open, browser prompts for access only once
- Deterministic targeting: Friendly target names (
[target:red-snake]) for reliable multi-page workflows
Installation
brew install aeroxy/tap/chrome-devtools
cargo install chrome-devtools-cli
The binary is named chrome-devtools.
Prerequisites
Enable Chrome remote debugging:
- Open Chrome
- Navigate to
chrome://inspect/#remote-debugging
- Enable the remote debugging server
Auto-Connect Behavior
The CLI automatically discovers Chrome's WebSocket endpoint by reading DevToolsActivePort from:
- macOS:
~/Library/Application Support/Google/Chrome/
- Linux:
~/.config/google-chrome/
- Windows:
%LOCALAPPDATA%\Google\Chrome\User Data\
Override with environment variables or flags:
export CHROME_WS_ENDPOINT=ws://localhost:9222/devtools/browser/abc123
export CHROME_USER_DATA_DIR=~/custom-chrome-profile
export CHROME_CHANNEL=beta
chrome-devtools --ws-endpoint ws://localhost:9222/... navigate https://example.com
chrome-devtools --user-data-dir ~/custom-profile navigate https://example.com
chrome-devtools --channel canary navigate https://example.com
Daemon Architecture
First command spawns a background daemon that:
- Connects to Chrome WebSocket (one-time approval prompt)
- Listens on Unix socket:
/tmp/chrome-devtools-daemon.sock
- Auto-exits after 5 minutes of inactivity
- All subsequent commands reuse the persistent connection
Kill manually: pkill -f __daemon__ or delete the socket file.
Page Targeting Pattern
CRITICAL: Always capture and reuse the [target:name] from navigation commands.
chrome-devtools navigate https://github.com
chrome-devtools --target green-dog screenshot --output /tmp/gh.png
chrome-devtools --target green-dog evaluate "document.title"
chrome-devtools --target green-dog click "a[href='/login']"
Without --target, commands default to page index 0, which may change as Chrome reorders tabs.
List All Pages
chrome-devtools list-pages
You can also use --page <index> for quick one-offs:
chrome-devtools --page 1 evaluate "window.location.href"
Core Commands
Navigation
chrome-devtools navigate https://example.com
chrome-devtools --target red-snake navigate --back
chrome-devtools --target red-snake navigate --forward
chrome-devtools --target red-snake navigate --reload
chrome-devtools new-page https://github.com
chrome-devtools close-page 2
chrome-devtools select-page 0
Inspection
chrome-devtools --target green-dog screenshot --output /tmp/page.png
chrome-devtools --target green-dog screenshot --full-page --output /tmp/full.png
chrome-devtools --target green-dog evaluate "document.title"
chrome-devtools --target green-dog evaluate "Array.from(document.querySelectorAll('h1')).map(h => h.textContent)"
chrome-devtools --target green-dog evaluate "confirm('Proceed?')" --dialog-action accept
chrome-devtools --target green-dog evaluate "prompt('Name?')" --dialog-action "John Doe"
chrome-devtools --target green-dog snapshot
Interaction
chrome-devtools --target green-dog click "#submit-button"
chrome-devtools --target green-dog click "a[href='/login']"
chrome-devtools --target green-dog click-at 100 200
chrome-devtools --target green-dog fill "#email" "user@example.com"
chrome-devtools --target green-dog fill "#password" "secret123"
chrome-devtools --target green-dog fill "#country" "United States"
chrome-devtools --target green-dog fill "#terms" "true"
chrome-devtools --target green-dog fill "#newsletter" "false"
chrome-devtools --target green-dog type-text "Hello World"
chrome-devtools --target green-dog type-text "Search query" --submit-key Enter
chrome-devtools --target green-dog press-key Enter
chrome-devtools --target green-dog press-key "Control+A"
chrome-devtools --target green-dog press-key Escape
chrome-devtools --target green-dog hover ".dropdown-menu"
Viewport & Waiting
chrome-devtools --target green-dog resize 1920 1080
chrome-devtools --target green-dog wait-for "Login successful"
chrome-devtools --target green-dog wait-for "Dashboard" --timeout 60000
Third-Party Developer Tools
For pages that inject custom DevTools via window.__dtmcp:
chrome-devtools --target green-dog list-3p-tools
chrome-devtools --target green-dog execute-3p-tool "myTool" '{"param": "value"}'
JSON Output Mode
Add --json to any command for machine-readable output:
chrome-devtools --json --target green-dog evaluate "document.title"
chrome-devtools --json list-pages
Real-World Workflows
Automated Form Submission
#!/bin/bash
set -e
TARGET=$(chrome-devtools navigate https://example.com/form | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET" fill "#name" "Alice Smith"
chrome-devtools --target "$TARGET" fill "#email" "alice@example.com"
chrome-devtools --target "$TARGET" fill "#country" "Canada"
chrome-devtools --target "$TARGET" fill "#terms" "true"
chrome-devtools --target "$TARGET" click "#submit"
chrome-devtools --target "$TARGET" wait-for "Thank you" --timeout 10000
chrome-devtools --target "$TARGET" screenshot --output /tmp/confirmation.png
Data Extraction
#!/bin/bash
TARGET=$(chrome-devtools navigate https://news.ycombinator.com | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET" evaluate "
Array.from(document.querySelectorAll('.athing')).slice(0, 5).map(item => ({
title: item.querySelector('.titleline > a').textContent,
url: item.querySelector('.titleline > a').href
}))
" --json > /tmp/hn-stories.json
cat /tmp/hn-stories.json
Multi-Page Session
#!/bin/bash
TARGET_HOME=$(chrome-devtools navigate https://github.com | grep -oP '(?<=target:)[a-z-]+')
TARGET_REPO=$(chrome-devtools new-page https://github.com/torvalds/linux | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET_HOME" click "a[href='/login']"
chrome-devtools --target "$TARGET_REPO" evaluate "document.querySelector('.repository-content').textContent.includes('Linux kernel')"
chrome-devtools --target "$TARGET_HOME" screenshot --output /tmp/home.png
chrome-devtools --target "$TARGET_REPO" screenshot --output /tmp/repo.png
Accessibility Audit
#!/bin/bash
TARGET=$(chrome-devtools navigate https://example.com | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET" snapshot > /tmp/a11y-tree.txt
chrome-devtools --target "$TARGET" evaluate "
document.querySelectorAll('[role=\"button\"]').length
"
chrome-devtools --target "$TARGET" evaluate "
Array.from(document.querySelectorAll('img:not([alt])')).map(img => img.src)
"
Common Patterns for AI Agents
1. Always Capture Target Names
chrome-devtools navigate https://example.com
chrome-devtools screenshot --output /tmp/page.png
TARGET=$(chrome-devtools navigate https://example.com | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET" screenshot --output /tmp/page.png
2. Understand the Page First
chrome-devtools --target "$TARGET" snapshot
chrome-devtools --target "$TARGET" screenshot --output /tmp/context.png
chrome-devtools --target "$TARGET" evaluate "document.body.innerText"
3. Wait for Dynamic Content
chrome-devtools --target "$TARGET" click "#load-more"
chrome-devtools --target "$TARGET" wait-for "Showing 20 results" --timeout 5000
chrome-devtools --target "$TARGET" evaluate "document.querySelectorAll('.result-item').length"
4. Handle Errors Gracefully
HAS_BUTTON=$(chrome-devtools --target "$TARGET" evaluate "!!document.querySelector('#submit')" --json | jq -r '.result')
if [ "$HAS_BUTTON" = "true" ]; then
chrome-devtools --target "$TARGET" click "#submit"
else
echo "Submit button not found"
fi
Troubleshooting
"Could not connect to Chrome"
- Ensure Chrome is running
- Verify remote debugging is enabled at
chrome://inspect/#remote-debugging
- Check
DevToolsActivePort exists in user data directory
- Try explicit WebSocket:
chrome-devtools --ws-endpoint ws://localhost:9222/... navigate https://example.com
"Daemon connection failed"
pkill -f __daemon__
rm /tmp/chrome-devtools-daemon.sock
chrome-devtools navigate https://example.com
"Element not found" on click/fill
chrome-devtools --target "$TARGET" evaluate "!!document.querySelector('#my-button')"
chrome-devtools --target "$TARGET" evaluate "document.querySelectorAll('#my-button').length"
chrome-devtools --target "$TARGET" wait-for "Submit" --timeout 10000
chrome-devtools --target "$TARGET" click "#submit"
Target name confusion
chrome-devtools list-pages
chrome-devtools --page 0 evaluate "document.title"
chrome-devtools --target "E4F5A6B7C8D9" evaluate "document.title"
Best Practices for AI Agents
- Always use
--target after initial navigation
- Capture screenshots before and after interactions for debugging
- Use
snapshot to understand page structure before clicking
- Wait for content instead of assuming instant load
- Verify elements exist before interaction
- Use JSON output (
--json) for programmatic parsing
- Check
list-pages when multi-page workflows get confusing
- Kill daemon between unrelated sessions to avoid stale connections
Integration with AI Coding Agents
When helping a user automate Chrome:
- Install
chrome-devtools-cli if not present
- Verify Chrome remote debugging is enabled
- Start with
navigate and capture the target name
- Use
snapshot or screenshot to understand the page
- Perform interactions with explicit
--target
- Extract results with
evaluate and --json
- Clean up with
close-page if needed
Example agent workflow:
TARGET=$(chrome-devtools navigate https://example.com/login | grep -oP '(?<=target:)[a-z-]+')
chrome-devtools --target "$TARGET" snapshot | head -50
chrome-devtools --target "$TARGET" fill "#username" "$EXAMPLE_USERNAME"
chrome-devtools --target "$TARGET" fill "#password" "$EXAMPLE_PASSWORD"
chrome-devtools --target "$TARGET" click "#login-button"
chrome-devtools --target "$TARGET" wait-for "Dashboard" --timeout 10000
chrome-devtools --target "$TARGET" screenshot --output /tmp/logged-in.png
This skill enables zero-context browser automation directly from your existing Chrome session.