.agents/skills/headless-web-navigation/SKILL.md
Headless browser automation using Playwright CLI. Use when you need headless browsing, parallel browser sessions, UI testing, screenshots, web scraping, or browser automation that can run in the background. Keywords - playwright, headless, browser, test, screenshot, scrape, parallel.
npx skillsauth add em-jones/staccato-toolkit playwright-browserInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Automate browsers using playwright-cli — a token-efficient CLI for Playwright. Runs headless by default, supports parallel sessions via named sessions (-s=), and doesn't load tool schemas into context.
--headed to open to see the browser-s=<name> to run multiple independent browser instancesPLAYWRIGHT_MCP_CAPS=vision to receive screenshots as image responses in context instead of just saving to diskAlways use a named session. Derive a short, descriptive kebab-case name from the user's prompt. This gives each task a persistent browser profile (cookies, localStorage, history) that accumulates across calls.
# Derive session name from prompt context:
# "test the checkout flow on mystore.com" → -s=mystore-checkout
# "scrape pricing from competitor.com" → -s=competitor-pricing
# "UI test the login page" → -s=login-ui-test
playwright-cli -s=mystore-checkout open https://mystore.com --persistent
playwright-cli -s=mystore-checkout snapshot
playwright-cli -s=mystore-checkout click e12
Managing sessions:
playwright-cli list # list all sessions
playwright-cli close-all # close all sessions
playwright-cli -s=<name> close # close specific session
playwright-cli -s=<name> delete-data # wipe session profile
Core: open [url], goto <url>, click <ref>, fill <ref> <text>, type <text>, snapshot, screenshot [ref], close
Navigate: go-back, go-forward, reload
Keyboard: press <key>, keydown <key>, keyup <key>
Mouse: mousemove <x> <y>, mousedown, mouseup, mousewheel <dx> <dy>
Tabs: tab-list, tab-new [url], tab-close [index], tab-select <index>
Save: screenshot [ref], pdf, screenshot --filename=f
Storage: state-save, state-load, cookie-*, localstorage-*, sessionstorage-*
Network: route <pattern>, route-list, unroute, network
DevTools: console, run-code <code>, tracing-start/stop, video-start/stop
Sessions: -s=<name> <cmd>, list, close-all, kill-all
Config: open --headed, open --browser=chrome, resize <w> <h>
--persistent to preserve cookies/state. Always set the viewport via env var at launch:PLAYWRIGHT_MCP_VIEWPORT_SIZE=1440x900 playwright-cli -s=<session-name> open <url> --persistent
# or headed:
PLAYWRIGHT_MCP_VIEWPORT_SIZE=1440x900 playwright-cli -s=<session-name> open <url> --persistent --headed
# or with vision (screenshots returned as image responses in context):
PLAYWRIGHT_MCP_VIEWPORT_SIZE=1440x900 PLAYWRIGHT_MCP_CAPS=vision playwright-cli -s=<session-name> open <url> --persistent
Stealth sessions: If
.playwright-cli-init.tsexists in the project root, activate it by settingPLAYWRIGHT_MCP_INIT_PAGEbefore the firstopen. Kill any existing sessions first so the daemon picks up the new env var:playwright-cli kill-all PLAYWRIGHT_MCP_INIT_PAGE="$(pwd)/.playwright-cli-init.ts" PLAYWRIGHT_MCP_VIEWPORT_SIZE=1440x900 playwright-cli -s=<session-name> open <url> --persistent
playwright-cli snapshot
playwright-cli click <ref>
playwright-cli fill <ref> "text"
playwright-cli type "text"
playwright-cli press Enter
playwright-cli screenshot
playwright-cli screenshot --filename=output.png
playwright-cli -s=<session-name> close
If a playwright-cli.json exists in the working directory, use it automatically. If the user provides a path to a config file, use --config path/to/config.json. Otherwise, skip configuration — the env var and CLI defaults are sufficient.
{
"browser": {
"browserName": "chromium",
"launchOptions": { "headless": true },
"contextOptions": { "viewport": { "width": 1440, "height": 900 } }
},
"outputDir": "./screenshots"
}
Run playwright-cli --help or playwright-cli --help <command> for detailed command usage.
See docs/playwright-cli.md for full documentation.
Use these techniques when automating sites with bot-detection systems (fingerprinting, IP reputation checks, behavioral analysis). Apply in priority order: stealth plugin → human-like behavior → fingerprint randomization.
Scope: This section covers automation-level techniques. Always ensure your use case complies with the target site's terms of service.
Preferred CLI approach — PLAYWRIGHT_MCP_INIT_PAGE:
Use the project-root .playwright-cli-init.ts init page. It is loaded per-tab by the daemon and applies
all evasions before any page scripts run — covering navigator.webdriver, plugins, languages,
hardwareConcurrency, deviceMemory, the chrome runtime object, permissions query patching, and
iframe propagation.
playwright-cli kill-all # restart daemon so it picks up the env var
PLAYWRIGHT_MCP_INIT_PAGE="$(pwd)/.playwright-cli-init.ts" \
playwright-cli -s=<session> open <url> --persistent
Why
kill-allfirst: The daemon inherits env vars at spawn time. Existing sessions won't pick up a newly setPLAYWRIGHT_MCP_INIT_PAGEwithout a restart.
Last-resort fallback (no init file available):
Suppress the webdriver flag post-navigation via run-code. This runs after page scripts so it is
less reliable, but covers the most obvious signal:
playwright-cli -s=<session> open <url> --persistent
playwright-cli -s=<session> run-code "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
playwright-cli -s=<session> run-code "delete window.__playwright; delete window.__pw_manual;"
Note:
run-codesuppression covers only the most obvious signals and runs post-load..playwright-cli-init.ts+PLAYWRIGHT_MCP_INIT_PAGEis the correct approach for this project.
Bot detectors analyze interaction timing and mouse movement patterns. Mimic human behavior with three techniques:
# Between each interaction, add a random sleep (500–2500ms)
playwright-cli -s=<session> click e12
sleep 1.3 # vary this: 0.5–2.5s
playwright-cli -s=<session> fill e15 "search term"
sleep 0.8
playwright-cli -s=<session> press Enter
sleep 2.1
Avoid uniform delays (e.g., always 1000ms) — detectors flag rhythmic patterns.
Move the cursor to a natural intermediate position before clicking a target element:
# Get element coordinates via snapshot first, then arc the mouse
playwright-cli -s=<session> snapshot # identify target ref and coordinates
playwright-cli -s=<session> mousemove 500 400 # intermediate point (not the target)
playwright-cli -s=<session> mousemove 612 318 # approach the target
playwright-cli -s=<session> click e12 # now click
type not fillfill sets the input value instantly (machine-like). type sends key events character by character:
# ✗ Machine-like — sets value atomically
playwright-cli -s=<session> fill e15 "search query"
# ✓ Human-like — sends key events with natural cadence
playwright-cli -s=<session> type "search query"
Add delays between words for longer text entries:
playwright-cli -s=<session> type "search "
sleep 0.3
playwright-cli -s=<session> type "query"
Fingerprinting scripts build device profiles from browser properties. Randomize these at session launch to prevent consistent identification.
A mismatched User-Agent (e.g., Windows UA on a Linux host) is an immediate detection signal.
# Linux host — use a Linux Chrome UA
UA="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
playwright-cli -s=<session> run-code "Object.defineProperty(navigator, 'userAgent', {get: () => '$UA'})"
Match the OS, browser, and a realistic (not bleeding-edge) version number.
Avoid the default 1440x900 for every session — detectors recognize uniform viewports.
# Randomize within realistic desktop ranges (width: 1280–1920, height: 768–1080)
PLAYWRIGHT_MCP_VIEWPORT_SIZE=1366x768 playwright-cli -s=<session> open <url> --persistent
# or
PLAYWRIGHT_MCP_VIEWPORT_SIZE=1920x1080 playwright-cli -s=<session> open <url> --persistent
Set locale and timezone to match the target region:
playwright-cli -s=<session> run-code "
Intl.DateTimeFormat = new Proxy(Intl.DateTimeFormat, {
construct(target, args) {
args[1] = {...(args[1] || {}), timeZone: 'America/New_York'};
return new target(...args);
}
})
"
playwright-extra-plugin-stealth automatically injects subtle noise into canvas toDataURL() and WebGL renderer strings, preventing cross-session fingerprint matching. In CLI-only environments:
playwright-cli -s=<session> run-code "
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function(type) {
const dataURL = origToDataURL.call(this, type);
return dataURL.replace(/.$/, String.fromCharCode(dataURL.charCodeAt(dataURL.length-1) ^ 1));
};
"
Note: This is a minimal noise approach. For highly fingerprint-aware sites, the stealth plugin is the more reliable solution.
Before running automation against a bot-protected site:
type used instead of fill for text inputmousemove used before click on critical elementstools
<!--VITE PLUS START--> # Using Vite+, the Unified Toolchain for the Web This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`. ## Vite+ Workflow `vp` is a global binary that handles the full development lifecycle. Run `vp help` to pr
development
Guide for building performant data tables. Uses tanstack-table for table logic (sorting, filtering, pagination) and tanstack-virtual for rendering large datasets efficiently.
development
Expert guidance for building observable, expressive, and fault-tolerant TypeScript applications using the effect-ts/effect ecosystem. Covers Effect<A, E, R> type, error management, dependency injection via Layers, observability (logging, metrics, tracing), concurrency with Fibers, retry/scheduling, Schema validation, Streams, and Sinks.
tools
Complete E2E (end-to-end) and integration testing skill for TypeScript/NestJS projects using Jest, real infrastructure via Docker, and GWT pattern. ALWAYS use this skill when user needs to: **SETUP** - Initialize or configure E2E testing infrastructure: - Set up E2E testing for a new project - Configure docker-compose for testing (Kafka, PostgreSQL, MongoDB, Redis) - Create jest-e2e.config.ts or E2E Jest configuration - Set up test helpers for database, Kafka, or Redis - Configure .env.e2e environment variables - Create test/e2e directory structure **WRITE** - Create or add E2E/integration tests: - Write, create, add, or generate e2e tests or integration tests - Test API endpoints, workflows, or complete features end-to-end - Test with real databases, message brokers, or external services - Test Kafka consumers/producers, event-driven workflows - Working on any file ending in .e2e-spec.ts or in test/e2e/ directory - Use GWT (Given-When-Then) pattern for tests **REVIEW** - Audit or evaluate E2E tests: - Review existing E2E tests for quality - Check test isolation and cleanup patterns - Audit GWT pattern compliance - Evaluate assertion quality and specificity - Check for anti-patterns (multiple WHEN actions, conditional assertions) **RUN** - Execute or analyze E2E test results: - Run E2E tests - Start/stop Docker infrastructure for testing - Analyze E2E test results - Verify Docker services are healthy - Interpret test output and failures **DEBUG** - Fix failing or flaky E2E tests: - Fix failing E2E tests - Debug flaky tests or test isolation issues - Troubleshoot connection errors (database, Kafka, Redis) - Fix timeout issues or async operation failures - Diagnose race conditions or state leakage - Debug Kafka message consumption issues **OPTIMIZE** - Improve E2E test performance: - Speed up slow E2E tests - Optimize Docker infrastructure startup - Replace fixed waits with smart polling - Reduce beforeEach cleanup time - Improve test parallelization where safe Keywords: e2e, end-to-end, integration test, e2e-spec.ts, test/e2e, Jest, supertest, NestJS, Kafka, Redpanda, PostgreSQL, MongoDB, Redis, docker-compose, GWT pattern, Given-When-Then, real infrastructure, test isolation, flaky test, MSW, nock, waitForMessages, fix e2e, debug e2e, run e2e, review e2e, optimize e2e, setup e2e