SuperAPI AI Directory

browser-cdp

Testing & quality

View repository

Updated 10-16 09:30

About this skill

Browser CDP Operation Tool

Control Chrome via the CDP protocol, reuse existing login sessions, and perform browser automation operations.

Prerequisites

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

⚠️ The first launch will kill the user's regular Chrome. User consent must be obtained before launching (see "Launch Flow" below), otherwise the user may lose unsaved tabs/drafts.


Launch Flow (mandatory steps in skill-mode)

Step 1: Probe the current state (no side effects)

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

Output looks like:

CDP_STATUS=ready                        # 已就绪,可直接复用
CDP_URL=http://127.0.0.1:9222/json/version
BROWSER=Chrome/148.0.7778.168

Or:

CDP_STATUS=needs-setup
CHROME_RUNNING=yes                      # 用户有 Chrome 在跑,启动会杀掉
CHROME_PID_COUNT=3

Step 2: Branch based on the probe result

  • CDP_STATUS=ready → use directly agent-browser --cdp 9222 ...,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=yes → First use the AskUserQuestion tool to confirm with the user: inform them that N Chrome processes will be killed and unsaved work may be lost; after the user agrees, launch with --yes ; if the user refuses, abandon this automation.

Why can't we directly --yes: When the script is not in a TTY (i.e., skill mode / Bash tool), if it detects that Chrome is running without --yes, it will exit with code 3 reporting NEEDS_CONSENT: ... and abort,will notsilently kill processes. This is an intentional fallback—but the skill flow should still ask the user first, rather than blindly passing --yes。


Launch Script Options

Option Description
--detect-only Probe only, do not modify any state (used by skill)
--yes Consent already obtained, skip interactive prompt
--reset Clear before launching ~/chrome-debug-profile(use when login has expired)
--profile <name> Use a non-Default Chrome profile (e.g. "Profile 1")
--dry-run Print the steps to be executed without executing them

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


Common Operations

Open a page and wait for it to 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 (containing quotes / $ / backticks)

Shell escaping is error-prone; use one of the following two methods:

# 1) base64 包裹
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 (get element references via snapshot)

agent-browser --cdp 9222 snapshot -i        # 仅交互元素
agent-browser --cdp 9222 click "<CSS or @e1>"
agent-browser --cdp 9222 type "<sel>" "<text>"

Stop / Clean up

  • Just close the debug Chrome window. If the window is unresponsive, first press --user-data-dir to verify the PID of the debug instance and then end only it:
    • macOS / Linux:pgrep -af chrome-debug-profile
    • Windows:wmic process where "name='chrome.exe'" get ProcessId,CommandLine | findstr chrome-debug-profile After getting the PID kill -9 {PID} / taskkill /F /PID {PID}. If ownership cannot be verified, stop;manual cleanup must not batch-kill processes by the Chrome executable name—that would also kill the user's everyday Chrome. Exception:setup-cdp-chrome.js --reset internally does perform a cleanup by executable name; it belongs to this skill's built-in launch flow that requires --yes explicit consent; do not copy this approach for manual troubleshooting.
  • Login session expired:node {SKILL_DIR}/scripts/setup-cdp-chrome.js 9222 --reset --yes(note that --yes also requires asking the user first).

OpenCode Environment Notes

opencode has no tool for executing command lines in the background; long-running CDP operations (such as waiting for page loads or large-scale data scraping) will block the entire session, causing the CLI to become unresponsive.

Timeout wrapper

On Windows, use a PowerShell Job wrapper timeout for CDP commands:

$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 操作超时(30s),请重试或手动打断" }
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 操作超时(30s),请重试或手动打断"

Known limitations

Even with the timeout wrapper, the following scenarios may still have problems:

Scenario Risk Mitigation
Page load timeout The eval command waits and never returns Set a 30s timeout and retry after timeout
Large-scale data scraping Cumulative waiting becomes too long when paging through multiple pages Use an independent timeout per page and continue from the breakpoint after failure
Chrome process hangs The CDP connection is disconnected but the process has not exited First verify the PID corresponding to the debug profile, end only that debug instance, then reconnect; do not affect normal Chrome
Network fluctuations Requests hang with no timeout Automatically retry once after timeout

If you encounter an operation that keeps hanging, press ESC in opencode to interrupt manually.


FAQ

Problem Solution
NEEDS_CONSENT + exit code 3 Use AskUserQuestion to ask the user whether to allow killing Chrome; after consent, add --yes and rerun
CDP port is not listening --detect-only to confirm again; if the port is occupied, switch ports
Page redirects to the login page snapshot -i to find the login button and operate it
eval returns null Check the localStorage key name; for JS containing quotes, use eval -b or --stdin
Login state expired setup-cdp-chrome.js 9222 --reset --yes to copy again
There are multiple Chrome profiles --profile "Profile 1" to specify
Chrome will not start (30s timeout) Try --reset; check for port conflicts; check whether ~/chrome-debug-profile/ is corrupted