headless-browser
Browser automation with two efficiency tiers. Tier 1: headless-check.js for quick health checks, screenshots, error detection (JSON output). Tier 2: Playwright CLI (@playwright/cli via npx) for intera...
File Structure
headless- browser/
├── SKILL. md
└── scripts/
├── headless- check. js
└── pw- cli. shHeadless Browser Skill
Browser automation with two efficiency tiers for optimal token usage.
Decision Tree
Need browser automation?
|
+- - Just checking page health/ errors/ screenshot?
| - - > Tier 1: headless- check. js (fastest, lowest tokens)
|
+- - Need to interact (click, fill, navigate, inspect elements)?
| - - > Tier 2: Playwright CLI (YAML snapshots + element refs, 4x more efficient than MCP)
|
+- - Need persistent context, rich introspection, or very complex scenarios?
- - > Tier 3: MCP Playwright (highest capability, higher tokens)Tier 1: Lightweight Checks (headless-check.js)
Best for: Quick health checks, screenshot capture, error detection
Script: $HOME/
Commands
Basic check (recommended for error detection):
node $HOME/.claude/skills/headless-browser/scripts/headless-check.js --url <URL> --no-block-resourcesQuick check (faster, but may miss font/image errors):
node $HOME/.claude/skills/headless-browser/scripts/headless-check.js --url <URL>With screenshot:
node $HOME/.claude/skills/headless-browser/scripts/headless-check.js --url <URL> --screenshot viewport --no-block-resources
node $HOME/.claude/skills/headless-browser/scripts/headless-check.js --url <URL> --screenshot full --no-block-resourcesOptions:
--timeout <ms>- Timeout (default: 15000)--wait-until load|networkidle|domcontentloaded- Wait strategy--no-javascript- Disable JavaScript--no-block-resources- Load all resources (recommended for accurate error detection)--user-agent "..."- Custom user agent
Important: Always use --no-block-resources when checking for errors. Without it, fonts and images are blocked for speed, which can cause false net::ERR_FAILED errors or miss real resource loading failures.
Output
JSON with:
title,statusCode,finalUrl,durationMshasErrors- Boolean error indicatorconsole- Console messages (truncated, collapsed)pageErrors- JavaScript errorsnetworkErrors- Failed requestsmetrics- Performance timingscreenshot- File path if captured
Example Output
{
"url": "https: / / example. com",
"title": "Example Domain",
"statusCode": 200,
"durationMs": 1234,
"hasErrors": false,
"console": { "entries": [], "total": 0 },
"pageErrors": [],
"screenshot": { "path": "/ Users/ you/ cclogs/ my- project/ headless- screenshots/ screenshot- 2025- 01- 28. png" }
}Tier 2: Playwright CLI (Interactive Browser Automation)
Best for: Clicking, form filling, navigation, page inspection, multi-step automation
Playwright CLI (@playwright/cli) is Microsoft's CLI built specifically for coding agents. It outputs YAML snapshots with element refs (e.g., e3, e15) that you use to interact -- 4x more token-efficient than MCP Playwright.
Run via npx (no local install needed -- reuses existing Chromium browsers):
# Mac/local: normal cache present — use npx directly
npx @playwright/cli@latest <command>
# web/WSL: cache absent — use the wrapper that wires the pre-installed Chromium
$HOME/.claude/skills/headless-browser/scripts/pw-cli.sh <command>web/WSL note: bind your dev server to 127.0.0.1 (e.g. pnpm dev --host 127.0.0.1). *.localhost hostnames do not resolve in-container, but http: always works.
Core Workflow
# 1. Open a page
# Mac/local:
npx @playwright/cli@latest open http://localhost:4321/some/page
# web/WSL:
$HOME/.claude/skills/headless-browser/scripts/pw-cli.sh open http://127.0.0.1:4321/some/page
# 2. Take snapshot to see page structure and element refs
npx @playwright/cli@latest snapshot
# Output YAML with refs like:
# - heading "Welcome" [level=1] [ref=e3]
# - button "Submit" [ref=e15]
# - textbox [ref=e21]
# 3. Interact using element refs from snapshot
npx @playwright/cli@latest fill e21 "test@example.com"
npx @playwright/cli@latest click e15
# 4. Snapshot again to verify the result
npx @playwright/cli@latest snapshot
# 5. Screenshot for visual verification
npx @playwright/cli@latest screenshot --filename $HOME/cclogs/REPO/headless-screenshots/result.png
# 6. Close the browser when done
npx @playwright/cli@latest closeCommand Reference
Core:
open [url]-- Launch browser and navigateclose-- Close current sessionsnapshot-- Get page structure with element refs (YAML)screenshot-- Capture visual screenshot (--filename path,--full-page)eval <js>-- Evaluate JavaScript in the page
Interaction:
click <ref>-- Click an element by refdblclick <ref>-- Double-clickfill <ref> <text>-- Fill a form fieldtype <text>-- Type into focused elementselect <ref> <value>-- Choose dropdown optioncheck <ref>/uncheck <ref>-- Toggle checkboxeshover <ref>-- Hover over elementdrag <startRef> <endRef>-- Drag and dropupload <file>-- Upload a file
Navigation:
goto <url>-- Navigate to URLgo-back/go-forward-- Browser navigationreload-- Refresh page
Keyboard:
press <key>-- Press a key (e.g.,Enter,Tab,Escape)
Tabs:
tab-new [url]-- Open new tabtab-list-- List open tabstab-select <index>-- Switch to tabtab-close-- Close current tab
Network:
route <url-pattern> <json-body>-- Mock network responsesnetwork-- View recent network requests
DevTools:
console-- View console messagestracing-start/tracing-stop-- Record tracesvideo-start/video-stop-- Record video
Common Patterns
Page inspection (no interaction needed):
npx @playwright/cli@latest open http://localhost:4321/page
npx @playwright/cli@latest snapshot
npx @playwright/cli@latest console
npx @playwright/cli@latest closeVisual verification screenshot:
npx @playwright/cli@latest open http://localhost:4321/page
npx @playwright/cli@latest screenshot --filename $HOME/cclogs/REPO/headless-screenshots/check.png --full-page
npx @playwright/cli@latest closeForm interaction:
npx @playwright/cli@latest open http://localhost:4321/form
npx @playwright/cli@latest snapshot # Find form element refs
npx @playwright/cli@latest fill e12 "user@example.com"
npx @playwright/cli@latest fill e15 "password123"
npx @playwright/cli@latest click e20 # Submit button ref
npx @playwright/cli@latest snapshot # Verify result
npx @playwright/cli@latest closeCheck computed style via eval:
npx @playwright/cli@latest open http://localhost:4321/page
npx @playwright/cli@latest eval "window.getComputedStyle(document.querySelector('.panel')).zIndex"
npx @playwright/cli@latest closeMock network response:
npx @playwright/cli@latest open http://localhost:4321/page
npx @playwright/cli@latest route "**/api/users" '{"users": []}'
npx @playwright/cli@latest reload
npx @playwright/cli@latest snapshot
npx @playwright/cli@latest closeSession Management
The browser stays running between commands (persistent session). Always close when done:
close-- Close current sessionclose-all-- Close all sessionslist-- See active sessions
Artifacts
Playwright CLI creates a .playwright-cli/ directory at the current working directory containing snapshot YAML files and console logs. This directory is gitignored.
Notes
Always use
npx @playwright/cli@latest(NOT theplaywrightCLI from the playwright npm package -- they are different)The
--rawflag strips metadata, outputting only the result valueElement refs (e3, e15, etc.) come from
snapshotoutput -- use them in click/fill/selectFor color scheme testing (light/dark), use Tier 1's headless-check.js which supports Playwright's
colorSchemecontext option. Playwright CLI does not have a--color-schemeflagIf browsers are missing on a fresh machine, run:
npx playwright install chromium
When to Use What
| Task | Recommended |
|---|---|
| Check if page loads | Tier 1 |
| Capture screenshot (no interaction) | Tier 1 |
| Check for console errors | Tier 1 + --no-block-resources |
| Check network failures | Tier 1 + --no-block-resources |
| Color scheme screenshots (light/dark) | Tier 1 (supports colorScheme) |
| Inspect page structure / element tree | Tier 2 (snapshot) |
| Click a button | Tier 2 (click) |
| Fill a form | Tier 2 (fill) |
| Navigate through pages | Tier 2 (goto / go-back) |
| Test login flow | Tier 2 |
| Extract text after interaction | Tier 2 (eval) |
| Check computed CSS styles | Tier 2 (eval) |
| Multi-tab workflows | Tier 2 (tab-*) |
| Mock network responses | Tier 2 (route) |
| Complex stateful automation | Tier 3: MCP Playwright |
| Deep debugging with tracing | Tier 2 (tracing-*) or MCP Playwright |
CSS/Style Verification Guidelines
For CSS/style verification, prefer / which provides deterministic computed style checks before visual analysis. The guidelines below apply when using / directly for CSS checks.
Theme Awareness
The target website may support light/dark themes. When checking CSS/style-related changes, capture screenshots in both color schemes. Use Playwright's colorScheme option:
// Capture in both themes
for (const scheme of ['light', 'dark']) {
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
colorScheme: scheme,
});
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({ path: `${ssDir}/check-${scheme}.png` });
await page.close();
}Responsive Width Variations
When checking layout or fluid design, capture at multiple viewport widths to cover the design's breakpoints. The number and values of widths depend on the project — check the project's CSS/config for actual breakpoints (e.g., @theme breakpoints, Tailwind config, media queries) and capture at widths that test each transition point. For example, a project with sm: 640px, lg: 1024px, xl: 1280px breakpoints needs captures at widths like 400px, 700px, 1100px, and 1300px to verify behavior on each side of each breakpoint.
If the project's breakpoints are unclear, ask the user which width variations matter for the layout being checked.
Mandatory Visual Verification
CRITICAL: After capturing screenshots, you MUST read and carefully examine every captured PNG file using the Read tool. Do NOT report success without visually verifying the screenshots show the expected result.
Workflow:
Capture screenshots
Read each screenshot with the Read tool
Carefully inspect — check borders, spacing, alignment, color, contrast
Compare against what was requested
Only then report the result
Screenshots that are captured but not visually inspected are worthless. If you skip verification, you will miss problems and the user will have to point them out repeatedly.
Best Practices
Start with Tier 1 -- If you just need to check if a page works, use headless-check.js
Escalate to Tier 2 -- When interactions or page inspection are needed, use Playwright CLI
Always close sessions -- Run
npx @playwright/cli@latest closewhen done to free resourcesUse snapshots, not raw HTML -- Playwright CLI snapshots are structured YAML with element refs, far more token-efficient than page source
Capture both themes -- For theme testing, use Tier 1's
colorSchemesupportCapture at project breakpoints -- When checking layout, read the project's breakpoint config and capture widths that cover each transition
Always visually verify -- Read every captured PNG with the Read tool before reporting
Technical Notes
Tier 1 uses Playwright API via Node.js (installed in
$HOME/). Includes a browser-resolver that falls back to a pre-installed Chromium (. claude/ skills/ headless- browser/ node_ modules/ /oropt/ pw- browsers/ */ chrome- linux/ chrome PLAYWRIGHT_EXECUTABLE_PATH) when~/.cache/ms-playwright/is absent (web/WSL). On Linux (WSL, native, web container) the resolver passes--no-sandbox --disable-gpu --disable-dev-shm-usageon every branch — including the default cache — so a browser in~/.cache/ms-playwright/launches without the "No usable sandbox!" error. Mac/local behavior is unchanged (no flags; default-cache branch returns{}).WSL prerequisite: a fresh WSL2 Ubuntu is missing Chromium's shared libraries (
libnss3,libgbm,libasound2, …). The flags above silence the sandbox error, but if the libs are absent the launch still fails with "Host system is missing dependencies to run browsers". Runnpx playwright install-depsonce (it usessudo) to install them.Tier 2 uses
@playwright/clivia npx (isolated from the local playwright install, no conflicts). On web/WSL usepw-cli.shinstead of npx directly — it wires the pre-installed Chromium viaPLAYWRIGHT_BROWSERS_PATHso the CLI finds it without a download.Both tiers share the same Chromium browsers from
$HOME/.cache/ms-playwright/on Mac/local. On web/WSL they use the pre-installed binary.Resource blocking: By default, Tier 1 blocks images/fonts for speed. Use
--no-block-resourcesfor accurate error detectionScreenshots saved to
$HOME/cclogs/{repo-name}/headless-screenshots/Playwright CLI creates a
.playwright-cli/directory at CWD for snapshot artifacts (gitignored)All tiers are more token-efficient than MCP Playwright (Tier 2 is ~4x more efficient)