chrome-cdp-controller
/install chrome-cdp-controller
Chrome CDP Controller (Puppeteer)
Control and automate a Chrome browser that's already running with CDP enabled, using Puppeteer.
Key Features
- Non-intrusive: Connects to your existing Chrome, opens a new tab, operates, then closes only that tab
- Your browser stays open: Never closes your existing tabs or browser
- Clean automation: Each task runs in its own tab, which is automatically closed when done
1. Chrome with CDP Enabled
Chrome must be running with remote debugging enabled. If not already started:
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 &
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222 &
2. Get WebSocket URL
Visit http://localhost:9222/json/version to get the webSocketDebuggerUrl, for example:
ws://127.0.0.1:9222/devtools/browser/FFA7276F8E8E51645BD2AC9BE6B79607
Or use this one-liner:
curl -s http://localhost:9222/json/version | grep -o '"webSocketDebuggerUrl":"[^"]*"' | cut -d'"' -f4
3. Install Dependencies
cd chrome-cdp-controller
npm install
This installs puppeteer-core which is lightweight (doesn't download Chromium).
Usage
Command-Based Execution
Create a JSON file with commands:
commands.json:
[
{"type": "navigate", "url": "https://www.baidu.com"},
{"type": "wait", "seconds": 2},
{"type": "screenshot", "path": "/tmp/screenshot.png"},
{"type": "evaluate", "script": "document.title"}
]
Execute:
node scripts/cdp_controller.js --ws "ws://127.0.0.1:9222/devtools/browser/..." --commands commands.json
Node.js API
const { CDPController } = require('./scripts/cdp_controller.js');
(async () => {
const controller = new CDPController('ws://127.0.0.1:9222/devtools/browser/...');
await controller.connect();
// Navigate
await controller.navigate('https://www.taobao.com');
// Fill form
await controller.fill('#q', 'iPhone');
await controller.press('Enter');
await controller.wait(3);
// Extract data
const result = await controller.evaluate(`
Array.from(document.querySelectorAll('.item'))
.slice(0, 10)
.map(item => ({
title: item.querySelector('.title')?.textContent.trim(),
price: item.querySelector('.price')?.textContent.trim()
}))
`);
console.log(result.result);
// Intercept network
await controller.startIntercept('*api*');
// ... perform actions ...
const responses = controller.getInterceptedResponses();
await controller.close();
})();
Available Commands
Navigation
- navigate - Go to URL
url: Target URLwaitUntil: "load", "domcontentloaded", or "networkidle2" (default)
Interaction
-
click - Click an element
selector: CSS selectortimeout: Timeout in milliseconds (default: 5000)
-
fill - Fill a form field (selects all, then types)
selector: CSS selectortext: Text to filltimeout: Timeout in milliseconds (default: 5000)
-
type - Type text character by character
selector: CSS selectortext: Text to typedelay: Delay between characters in ms (default: 50)timeout: Timeout in milliseconds (default: 5000)
-
press - Press a key
key: Key name (Enter, Tab, Escape, etc.)
Data Extraction
-
get_text - Get text content of a single element
selector: CSS selector
-
get_all_text - Get text content of all matching elements
selector: CSS selector
-
evaluate - Execute JavaScript and return result
script: JavaScript code
Network Interception
-
start_intercept - Start intercepting network responses
url_pattern: URL pattern to match (substring match, e.g., "api")
-
get_intercepted - Get all intercepted responses
-
clear_intercepted - Clear intercepted responses list
Utilities
-
screenshot - Take a screenshot
path: Output file pathfullPage: Capture full page (default: false)
-
wait_for_selector - Wait for element to appear
selector: CSS selectortimeout: Timeout in milliseconds (default: 5000)
-
wait - Sleep for a duration
seconds: Number of seconds to wait
Common Workflows
Example 1: Search Taobao for iPhone Prices
taobao-search.json:
[
{"type": "navigate", "url": "https://www.taobao.com"},
{"type": "wait", "seconds": 2},
{"type": "fill", "selector": "#q", "text": "iPhone"},
{"type": "press", "key": "Enter"},
{"type": "wait", "seconds": 5},
{"type": "evaluate", "script": "Array.from(document.querySelectorAll('.item, [class*=\"Item\"]')).slice(0, 10).map(item => ({ title: item.querySelector('.title, [class*=\"title\"]')?.textContent.trim().substring(0, 80), price: item.querySelector('.price, [class*=\"price\"]')?.textContent.trim() }))"}
]
Run:
WS_URL=$(curl -s http://localhost:9222/json/version | grep -o '"webSocketDebuggerUrl":"[^"]*"' | cut -d'"' -f4)
node scripts/cdp_controller.js --ws "$WS_URL" --commands taobao-search.json
Note: Selectors may vary. Use browser DevTools (F12) to inspect elements.
Example 2: Ask ChatGPT a Question
chatgpt-ask.json:
[
{"type": "navigate", "url": "https://chat.openai.com"},
{"type": "wait_for_selector", "selector": "textarea", "timeout": 10000},
{"type": "type", "selector": "textarea", "text": "What is artificial intelligence?"},
{"type": "press", "key": "Enter"},
{"type": "wait", "seconds": 10},
{"type": "get_text", "selector": "[data-message-author-role='assistant']:last-of-type"}
]
Example 3: Intercept API Responses
intercept-api.json:
[
{"type": "start_intercept", "url_pattern": "graphql"},
{"type": "navigate", "url": "https://example.com"},
{"type": "wait", "seconds": 3},
{"type": "get_intercepted"}
]
For more examples, see references/examples.md.
Workflow
When automating browser tasks:
-
Get WebSocket URL:
- If you already have it (e.g.,
ws://127.0.0.1:9222/devtools/browser/...), use it directly - Otherwise, fetch from
http://localhost:9222/json/version
- If you already have it (e.g.,
-
Determine selectors:
- For known sites (Taobao, ChatGPT, etc.), check references/examples.md
- For unknown sites, navigate first and use
evaluatewithdocument.querySelectorto test selectors - Use browser DevTools (F12) to inspect elements
-
Build command sequence:
- Start with
navigate - Add
waitorwait_for_selectorbetween steps - Use
fillfor form inputs,clickfor buttons - Use
evaluatefor complex data extraction - Add
start_interceptbefore navigation if monitoring network traffic
- Start with
-
Execute:
- Save commands to JSON file
- Run:
node scripts/cdp_controller.js --ws "\x3Cwebsocket-url>" --commands \x3Cfile> - Parse JSON output
-
Handle failures:
- If selectors fail, inspect with DevTools
- If timing issues occur, increase wait times or use
wait_for_selector - If connection fails, verify Chrome is running with CDP enabled
Tips
- Wait times: Use
wait_for_selectorinstead of fixedwaitwhen possible - Selectors: Prefer ID (
#id) > class (.class) > attribute ([attr='value']) - Network interception: Start intercepting BEFORE navigating
- JavaScript: Use
evaluatefor complex data extraction - Screenshots: Useful for debugging
Troubleshooting
Connection Failed
- Ensure Chrome is running with
--remote-debugging-port=9222 - Verify WebSocket URL is correct
- Check Chrome version compatibility with puppeteer-core
Element Not Found
- Verify selector with DevTools (F12)
- Add
wait_for_selectorbefore interaction - Check if element is in an iframe
Module Not Found
cd chrome-cdp-controller
npm install
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install chrome-cdp-controller - 安装完成后,直接呼叫该 Skill 的名称或使用
/chrome-cdp-controller触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
chrome-cdp-controller 是什么?
Control local Chrome browser via Chrome DevTools Protocol (CDP) using Puppeteer. Use when you need to automate browser tasks like navigating pages, clicking... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 131 次。
如何安装 chrome-cdp-controller?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install chrome-cdp-controller」即可一键安装,无需额外配置。
chrome-cdp-controller 是免费的吗?
是的,chrome-cdp-controller 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
chrome-cdp-controller 支持哪些平台?
chrome-cdp-controller 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 chrome-cdp-controller?
由 xiaoxiaoxi(@hanxiaolin)开发并维护,当前版本 v1.0.0。