| name | faster-chrome-devtools-skill |
| description | Control Chrome directly via DevTools Protocol with snapshots, clicks, waits, and screenshots |
| triggers | ["automate chrome browser tasks","take a screenshot of this webpage","click on an element in the browser","read the accessibility tree from chrome","navigate to a url and wait for it to load","inspect console errors in chrome","fill out a form in the browser","connect to a remote chrome instance"] |
faster-chrome-devtools-skill
Skill by ara.so — Devtools Skills collection.
An agent skill and CLI for controlling Chrome directly through the Chrome DevTools Protocol (CDP). Provides fast accessibility snapshots, element interaction, navigation with explicit timeouts, screenshot capture, and console/network inspection without heavy dependencies like Puppeteer or Playwright.
Installation
Install globally for all agents:
npx skills add zeke/faster-chrome-devtools-skill --global --all --yes
Requires Node.js installed. No additional dependencies needed.
Core Concepts
The tool uses a lightweight background daemon that holds the CDP WebSocket connection open for 20 minutes, avoiding repeated Chrome access prompts. Connection details are stored in an owner-readable temp file with a random auth token.
Three connection modes:
- Logged-in Chrome: Connect to your existing Chrome instance (requires enabling remote debugging at
chrome://inspect/#remote-debugging)
- Anonymous Chromium: Launch a fresh temporary instance with
--launch
- Remote/Cloud: Connect to Cloudflare Browser Run or other remote endpoints
CLI Commands
All commands use node scripts/cdp.mjs <command> format.
Navigation & Page Control
node scripts/cdp.mjs navigate https://example.com --timeout 10000
node scripts/cdp.mjs navigate https://github.com --wait-text "Pull requests"
node scripts/cdp.mjs navigate https://example.com --wait-selector "#main-content"
node scripts/cdp.mjs list-tabs
node scripts/cdp.mjs open-tab https://news.ycombinator.com
node scripts/cdp.mjs switch-tab <tab-id>
node scripts/cdp.mjs close-tab
Reading Page Content
node scripts/cdp.mjs snapshot
node scripts/cdp.mjs get-text
node scripts/cdp.mjs screenshot --path screenshot.jpg
node scripts/cdp.mjs screenshot --path screenshot.webp --format webp
node scripts/cdp.mjs screenshot --path screenshot.png --format png
node scripts/cdp.mjs screenshot --path full.jpg --full-page
Element Interaction
node scripts/cdp.mjs click --ref "button-login-123"
node scripts/cdp.mjs click --selector "button.submit"
node scripts/cdp.mjs fill --ref "input-email-456" --value "user@example.com"
node scripts/cdp.mjs fill --selector "#email" --value "user@example.com"
node scripts/cdp.mjs type "Hello world" --delay 50
Wait Operations
node scripts/cdp.mjs wait-text "Success" --timeout 15000
node scripts/cdp.mjs wait-selector ".results-loaded"
node scripts/cdp.mjs wait --duration 2000
Debugging & Inspection
node scripts/cdp.mjs get-console
node scripts/cdp.mjs get-failed-loads
node scripts/cdp.mjs eval "document.title"
node scripts/cdp.mjs eval "
const links = Array.from(document.querySelectorAll('a'));
return links.map(a => ({ text: a.textContent, href: a.href }));
"
node scripts/cdp.mjs raw Runtime.evaluate '{"expression": "navigator.userAgent"}'
Connection Management
node scripts/cdp.mjs snapshot --launch
node scripts/cdp.mjs snapshot --ws-endpoint ws://localhost:9222/devtools/browser/xyz
node scripts/cdp.mjs snapshot --http-endpoint http://localhost:9222
node scripts/cdp.mjs stop
node scripts/cdp.mjs stop --id <daemon-id>
node scripts/cdp.mjs stop --all
node scripts/cdp.mjs stop --ws-endpoint ws://localhost:9222/devtools/browser/xyz
Configuration
Using Your Logged-in Chrome
- Open Chrome and navigate to
chrome://inspect/#remote-debugging
- Check "Discover network targets"
- Click "Configure" and ensure
localhost:9222 is listed
- Launch Chrome with remote debugging:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
google-chrome --remote-debugging-port=9222
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
Cloudflare Browser Run Setup
Set these environment variables:
export CLOUDFLARE_ACCOUNT_ID="your-account-id"
export CLOUDFLARE_API_TOKEN="your-api-token"
Then use:
node scripts/cdp.mjs snapshot --http-endpoint https://browser.run.cloudflare.com
The CLI automatically adds the required authentication headers.
Common Patterns
Scrape Structured Data
const stories = Array.from(document.querySelectorAll('.athing')).slice(0, 5);
return stories.map(story => ({
title: story.querySelector('.titleline > a')?.textContent,
url: story.querySelector('.titleline > a')?.href
}));
Login Flow
node scripts/cdp.mjs navigate https://example.com/login --wait-selector "#username"
node scripts/cdp.mjs fill --selector "#username" --value "$USERNAME"
node scripts/cdp.mjs fill --selector "#password" --value "$PASSWORD"
node scripts/cdp.mjs click --selector "button[type=submit]"
node scripts/cdp.mjs wait-text "Dashboard" --timeout 10000
node scripts/cdp.mjs screenshot --path logged-in.jpg
Multi-tab Workflow
node scripts/cdp.mjs list-tabs
node scripts/cdp.mjs open-tab https://github.com
node scripts/cdp.mjs snapshot
node scripts/cdp.mjs switch-tab <first-tab-id>
node scripts/cdp.mjs close-tab
Monitor Page for Changes
node scripts/cdp.mjs navigate https://example.com/status
node scripts/cdp.mjs snapshot > before.txt
node scripts/cdp.mjs wait --duration 5000
node scripts/cdp.mjs snapshot > after.txt
diff before.txt after.txt
Debugging Failed Loads
node scripts/cdp.mjs navigate https://example.com
node scripts/cdp.mjs get-failed-loads
node scripts/cdp.mjs get-console
node scripts/cdp.mjs screenshot --path debug.jpg
Accessibility Snapshot Format
The snapshot command returns a compact tree with stable references:
{
"role": "WebArea",
"name": "Example Page",
"ref": "page-1",
"children": [
{
"role": "button",
"name": "Submit",
"ref": "button-submit-42",
"focusable": true
},
{
"role": "textbox",
"name": "Email",
"ref": "input-email-43",
"focusable": true,
"value": ""
}
]
}
Use the ref values with --ref flags in click and fill commands for reliable element targeting.
Troubleshooting
"Connection refused" when connecting to Chrome
- Ensure Chrome is running with
--remote-debugging-port=9222
- Check that no firewall is blocking localhost:9222
- Verify
chrome://inspect/#remote-debugging shows the debugging port
"Target closed" or connection drops
- The daemon times out after 20 minutes of inactivity
- Restart with any command that reconnects
- Use
node scripts/cdp.mjs stop to clean up stale daemons
Screenshots are empty or broken
- Wait for page to fully load before capturing
- Use
--wait-selector or --wait-text with navigate
- Try
--full-page flag if content is below fold
- Check console/failed loads for rendering errors
Elements not found by selector
- Use
snapshot first to get stable accessibility references
- Prefer
--ref over --selector for reliability
- Use
wait-selector before clicking/filling
- Check that selector syntax is correct for the page's structure
Cloudflare Browser Run authentication fails
- Verify
CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN are set
- Check token has Browser Rendering permissions
- Ensure endpoint URL is
https://browser.run.cloudflare.com
Commands hang or timeout
- Increase
--timeout values for slow pages
- Check network connectivity to target site
- Use
get-console and get-failed-loads to diagnose page errors
- Try navigating to simpler test page first to verify connection