Browser Control (Claude Code)
Use bundled Playwright scripts for deterministic web automation.
Prerequisites
- •Python 3.10+
- •
pip install playwright - •
python -m playwright install chromium
Scripts
- •
.claude/skills/browser-control/scripts/open_url.py - •
.claude/skills/browser-control/scripts/snapshot_dom.py - •
.claude/skills/browser-control/scripts/act_click_type.py - •
.claude/skills/browser-control/scripts/wait_for.py - •
.claude/skills/browser-control/scripts/screenshot.py
Recommended flow
- •Open target URL
- •Snapshot DOM candidates
- •Run click/type/press actions
- •Wait for selector/text state
- •Capture screenshot and report
Commands
Open URL
bash
python3 .claude/skills/browser-control/scripts/open_url.py \ --url "https://example.com" \ --out outputs/browser/open.json
Snapshot candidates
bash
python3 .claude/skills/browser-control/scripts/snapshot_dom.py \ --url "https://example.com" \ --out outputs/browser/snapshot.json
Actions (click/type/press)
bash
python3 .claude/skills/browser-control/scripts/act_click_type.py \
--url "https://example.com" \
--actions '[{"type":"click","selector":"text=More information"}]' \
--out outputs/browser/act.json
Wait for UI state
bash
python3 .claude/skills/browser-control/scripts/wait_for.py \ --url "https://example.com" \ --selector "h1" \ --timeout-ms 10000 \ --out outputs/browser/wait.json
Screenshot
bash
python3 .claude/skills/browser-control/scripts/screenshot.py \ --url "https://example.com" \ --image outputs/browser/page.png \ --out outputs/browser/screenshot.json
Token optimization tips
Each script call and its output consumes tokens. Minimize unnecessary steps:
- •
Skip DOM snapshot when URL pattern is known
- •Search engines (Naver, Google) have predictable URL patterns. Build the URL directly instead of snapshotting + typing + pressing Enter.
bash# BAD: 3 steps (snapshot → type/click/press → screenshot) = high token cost python3 .claude/skills/browser-control/scripts/snapshot_dom.py --url "https://www.naver.com" ... python3 .claude/skills/browser-control/scripts/act_click_type.py --url "https://www.naver.com" --actions '[...]' ... python3 .claude/skills/browser-control/scripts/screenshot.py --url "https://search.naver.com/..." ... # GOOD: 1 step = low token cost python3 .claude/skills/browser-control/scripts/screenshot.py \ --url "https://search.naver.com/search.naver?query=%EC%98%A4%ED%94%88%ED%81%B4%EB%A1%9C" \ --image outputs/browser/result.png \ --out outputs/browser/screenshot.json
- •
Never Read the full snapshot JSON into context
- •Snapshot JSON can be hundreds of lines. Filter with
jqin Bash instead of using the Read tool.
bashpython3 .claude/skills/browser-control/scripts/snapshot_dom.py \ --url "https://example.com" --out /dev/stdout \ | jq '.items[] | select(.tag=="input")'
- •Snapshot JSON can be hundreds of lines. Filter with
- •
Combine actions into a single call
- •Use one
act_click_type.pycall with multiple actions array instead of calling the script multiple times.
- •Use one
- •
Screenshot only when needed
- •If you only need text data (e.g. link URLs, page title), use
snapshot_dom.pywithjqfiltering instead of a screenshot.
- •If you only need text data (e.g. link URLs, page title), use
Policy (read/write access control)
browser-control/policy.yaml controls domain access.
- •
write_allowed_hosts: only these hosts/subdomains are writable (deny by default for write) - •
read_blocked_hosts: only these hosts/subdomains are blocked for read (all others readable) - •Conflict rule: deny wins
- •Redirect rule: policy is checked for both requested URL and final redirected URL
Example policy.yaml (JSON-compatible YAML):
json
{
"write_allowed_hosts": ["docs.openclaw.ai", "github.com"],
"read_blocked_hosts": ["facebook.com", "x.com"]
}
Rules
- •Prefer stable selectors (
data-testid, explicit ids, role/text) over brittle nth-child selectors. - •Save every step output JSON for reproducibility.
- •If an action fails, return the failing selector/action index clearly.
- •Use
--headedonly for debugging; default headless for automation.