Control a dedicated browser in Claude Code using Playwright scripts. Use when the user asks to open web pages, inspect page structure, click/type/press actions, wait for UI state, or take screenshots in a reproducible automation flow.
Use bundled Playwright scripts for deterministic web automation.
pip install playwrightpython -m playwright install chromium.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.pypython3 .claude/skills/browser-control/scripts/open_url.py \
--url "https://example.com" \
--out outputs/browser/open.json
python3 .claude/skills/browser-control/scripts/snapshot_dom.py \
--url "https://example.com" \
--out outputs/browser/snapshot.json
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
python3 .claude/skills/browser-control/scripts/wait_for.py \
--url "https://example.com" \
--selector "h1" \
--timeout-ms 10000 \
--out outputs/browser/wait.json
python3 .claude/skills/browser-control/scripts/screenshot.py \
--url "https://example.com" \
--image outputs/browser/page.png \
--out outputs/browser/screenshot.json
Each script call and its output consumes tokens. Minimize unnecessary steps:
Skip DOM snapshot when URL pattern is known
# 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
jq in Bash instead of using the Read tool.python3 .claude/skills/browser-control/scripts/snapshot_dom.py \
--url "https://example.com" --out /dev/stdout \
| jq '.items[] | select(.tag=="input")'
Combine actions into a single call
act_click_type.py call with multiple actions array instead of calling the script multiple times.Screenshot only when needed
snapshot_dom.py with jq filtering instead of a screenshot.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)Example policy.yaml (JSON-compatible YAML):
{
"write_allowed_hosts": ["docs.openclaw.ai", "github.com"],
"read_blocked_hosts": ["facebook.com", "x.com"]
}
data-testid, explicit ids, role/text) over brittle nth-child selectors.--headed only for debugging; default headless for automation.