browser-cdp

browser-cdp

Popular

Use this skill when you need to control a Chrome browser via CDP (Chrome DevTools Protocol) to reuse existing login sessions. Covers: launching Chrome in debug mode, opening URLs, waiting for page load, evaluating JavaScript, taking snapshots, and extracting auth tokens. Trigger phrases: browser automation, CDP, agent-browser, 浏览器操作, 操作浏览器, Chrome CDP, 复用登录态, extract token from browser.

4.1Kstars
638forks
Updated 7/14/2026
SKILL.md
readonlyread-only
name
browser-cdp
description

Use this skill when you need to control a Chrome browser via CDP (Chrome DevTools Protocol) to reuse existing login sessions. Covers: launching Chrome in debug mode, opening URLs, waiting for page load, evaluating JavaScript, taking snapshots, and extracting auth tokens. Trigger phrases: browser automation, CDP, agent-browser, 浏览器操作, 操作浏览器, Chrome CDP, 复用登录态, extract token from browser.

Browser CDP Tool

Control Chrome via CDP to reuse existing login sessions and perform browser automation.

Prerequisites

  • macOS / Linux / Windows (experimental), Google Chrome installed
  • Node.js 12+
  • agent-browser installed: npm install -g agent-browser

⚠️ First launch will kill the user's regular Chrome. You must ask for user consent before starting (see "Launch Flow" below), otherwise the user may lose unsaved tabs/drafts.


Launch Flow (skill-mode mandatory steps)

Step 1: Detect current state (no side effects)

node {SKILL_DIR}/scripts/setup-cdp-chrome.js 9222 --detect-only

Output example:

CDP_STATUS=ready                        # Ready, can reuse directly
CDP_URL=http://127.0.0.1:9222/json/version
BROWSER=Chrome/148.0.7778.168

Or:

CDP_STATUS=needs-setup
CHROME_RUNNING=yes                      # User has Chrome running, launch will kill it
CHROME_PID_COUNT=3

Step 2: Branch based on detection result

  • CDP_STATUS=ready → Use agent-browser --cdp 9222 ... directly, do not run setup.
  • CDP_STATUS=needs-setup and CHROME_RUNNING=no → Safe launch:
    node {SKILL_DIR}/scripts/setup-cdp-chrome.js 9222 --yes
    
  • CDP_STATUS=needs-setup and CHROME_RUNNING=yesFirst ask user with AskUserQuestion: inform that N Chrome processes will be killed, may lose unsaved work; if user agrees, launch with --yes; if user refuses, abort automation.

Why not just --yes: In non-TTY (skill mode / Bash tool), if the script detects Chrome running without --yes, it exits with code 3 and NEEDS_CONSENT: ..., without silently killing processes. This is a safety net—but the skill flow should still ask the user first, not blindly pass --yes on seeing code 3.


Setup Script Options

Option Description
--detect-only Only detect, no state changes (for skill use)
--yes Consent obtained, skip interactive prompts
--reset Clear ~/chrome-debug-profile before launch (use when login expires)
--profile <name> Use a non-Default Chrome profile (e.g., "Profile 1")
--dry-run Print steps to execute without running

Exit codes: 0 success / 1 general error / 2 user refused (TTY) / 3 consent needed but --yes missing.


Common Operations

Open page and wait for load

agent-browser --cdp 9222 open "<URL>"
agent-browser --cdp 9222 wait 3000

Extract page text

agent-browser --cdp 9222 eval 'document.body.innerText.substring(0, 8000)'

Extract Auth Token

agent-browser --cdp 9222 eval 'localStorage.getItem("token") || document.cookie'

Complex JS (with quotes / $ / backticks)

Shell escaping is error-prone; use one of these methods:

# 1) base64 wrap
agent-browser --cdp 9222 eval -b "$(echo -n "document.querySelectorAll('a').length" | base64)"

# 2) heredoc + --stdin
cat <<'EOF' | agent-browser --cdp 9222 eval --stdin
const links = document.querySelectorAll('a');
links.length;
EOF

Page interaction (snapshot for element references)

agent-browser --cdp 9222 snapshot -i        # Only interactive elements
agent-browser --cdp 9222 click "<CSS or @e1>"
agent-browser --cdp 9222 type "<sel>" "<text>"

Stop / Cleanup

  • Close the debug Chrome window (or pkill -9 -x 'Google Chrome' / taskkill /F /IM chrome.exe).
  • Login expired: node {SKILL_DIR}/scripts/setup-cdp-chrome.js 9222 --reset --yes (note: --yes still requires user consent first).

OpenCode Environment Notes

OpenCode lacks a background command execution tool; long CDP operations (e.g., waiting for page load, bulk data scraping) block the entire session, causing CLI unresponsiveness.

Timeout Wrapper

On Windows, use PowerShell Job to wrap CDP commands with timeout:

$job = Start-Job { agent-browser --cdp 9222 eval "window.location.replace('https://www.qidian.com/rank/')" }
Wait-Job $job -Timeout 30 | Out-Null
if ($job.State -eq 'Running') { Stop-Job $job; Write-Output "⏱ CDP operation timed out (30s), please retry or interrupt manually" }
else { Receive-Job $job }
Remove-Job $job -Force

On macOS / Linux, use the timeout command:

timeout 30 agent-browser --cdp 9222 eval "window.location.replace('https://www.qidian.com/rank/')" || echo "⏱ CDP operation timed out (30s), please retry or interrupt manually"

Known Limitations

Even with timeout wrappers, the following scenarios may still cause issues:

Scenario Risk Mitigation
Page load timeout eval command hangs indefinitely Set 30s timeout, retry on timeout
Bulk data scraping Cumulative wait too long across pages Independent timeout per page, resume from breakpoint on failure
Chrome process stuck CDP connection lost but process not exited Clean up with pkill / taskkill then reconnect
Network fluctuation Request hangs without timeout Auto-retry once on timeout

If an operation hangs persistently, press ESC in opencode to interrupt manually.


FAQ

Problem Solution
NEEDS_CONSENT + exit code 3 Ask user with AskUserQuestion if they allow killing Chrome; if yes, rerun with --yes
CDP port not listening Recheck with --detect-only; if port occupied, change port
Page redirects to login Use snapshot -i to find login button and interact
eval returns null Check localStorage key name; for JS with quotes, use eval -b or --stdin
Login expired Run setup-cdp-chrome.js 9222 --reset --yes to recopy
Multiple Chrome profiles Specify with --profile "Profile 1"
Chrome won't start (30s timeout) Try --reset; check port conflicts; inspect ~/chrome-debug-profile/ for corruption