with one click
playwright-skill
Browser automation for web projects using playwright-cli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Browser automation for web projects using playwright-cli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | playwright-skill |
| description | Browser automation for web projects using playwright-cli |
| version | 2.0.0 |
| allowed-tools | Bash(playwright-cli:*), Bash(bin/open), Bash(bin/close), Bash(bin/click-css), Bash(bin/fill-css), Bash(bin/upload), Bash(bin/auth-save), Bash(bin/auth-load), Bash(bin/context), Bash(bin/inject-capture), Bash(bin/cache-query) |
Browser automation using playwright-cli (Microsoft's official Playwright CLI). No daemon management required — the browser starts and stops automatically.
Always start with bin/open (not bare playwright-cli open):
bin/open --headed
playwright-cli goto <url>
bin/open derives a session name from the current directory (e.g. my-project), appends a short agent identifier when running under Claude Code, and starts the browser under that named session. All other bin/ scripts resolve the session automatically.
Session isolation: When CLAUDE_SESSION_ID is set (automatic in Claude Code), each agent gets its own session name (e.g. my-project-a1b2c3d4) and session file. Parallel agents never interfere with each other. If a session is already open for this agent, bin/open closes it first to prevent orphaned Chrome processes — other agents' sessions are unaffected.
Before opening a new session, check if you already have one:
playwright-cli list # see all open sessions
If your session is already listed and open, skip bin/open and use it directly.
At the end of a task, clean up with:
bin/close
This closes the browser and removes the session tracking file. If the browser is stuck use playwright-cli kill-all instead.
Overriding the session name:
bin/open --headed --session my-custom-name
After every command, stdout contains a link to the current accessibility tree:
### Snapshot
- [Snapshot](.playwright-cli/page-<timestamp>.yml)
Always read the snapshot file to see what's on the page:
Read .playwright-cli/page-<timestamp>.yml
The snapshot contains all interactive elements with [ref=eN] identifiers used for clicking, filling, and hovering.
playwright-cli goto <url> # navigate to URL
playwright-cli go-back # browser back
playwright-cli go-forward # browser forward
playwright-cli reload # reload page
playwright-cli click <ref> # click element
playwright-cli fill <ref> <value> # fill input (clears first)
playwright-cli type <text> # type text (appends)
playwright-cli press <key> # press key: Enter, Tab, Escape, Control+A
playwright-cli hover <ref> # hover to reveal menus/tooltips
playwright-cli select <ref> <val> # select dropdown option
playwright-cli snapshot # capture accessibility tree
playwright-cli screenshot # take screenshot
playwright-cli dialog-accept # accept alert/confirm/prompt
playwright-cli dialog-dismiss # dismiss dialog
bin/close # close browser session + clean up session file (preferred)
playwright-cli kill-all # force-kill all playwright-cli daemons (use when stuck)
playwright-cli list # list all open sessions
playwright-cli run-code '<async page => { }>' # run arbitrary Playwright JS
Use these when ARIA-ref commands fail — for example, when framework-rendered elements are outside the main ARIA tree.
Modal dialogs — often rendered as DOM portals:
bin/click-css "[data-modal-confirm]"
bin/click-css "button[data-dismiss]"
Hidden file inputs — often hidden from accessibility tree:
bin/upload "input[type=file]" /path/to/file.pdf
Framework event targets — ARIA-ref clicks don't always fire framework event handlers:
bin/fill-css "[data-field=email]" "user@example.com"
bin/click-css "[data-action=save]"
See skill/CONFIG.md for project-specific selector patterns.
Auth profile names and base URLs are defined in skill/worktrees.json (gitignored).
See skill/CONFIG.md for setup instructions.
Save after authenticating:
bin/auth-save <profile-name> # profile names from skill/worktrees.json
Restore on a new session:
bin/open --headed
playwright-cli goto <baseUrl> # baseUrl from skill/worktrees.json
bin/auth-load <profile-name>
playwright-cli goto <baseUrl>/dashboard
Profiles are stored in .playwright-skill/auth/ and gitignored.
| Problem | Solution |
|---|---|
| Browser stuck / daemon hung | playwright-cli kill-all then bin/open --headed |
| No session open (bin/context error) | bin/open --headed |
| Auth expired | bin/auth-load <profile> then reload |
| Element ref not found | playwright-cli snapshot then read the new snapshot file |
| Modal/portal not clickable from ARIA tree | Use bin/click-css with CSS selector |
| End of task cleanup | bin/close |
# Wait for a specific element
playwright-cli run-code 'await page.waitForSelector(".loading-complete")'
# Dispatch a custom JS event
playwright-cli run-code 'await page.evaluate(() => window.dispatchEvent(new Event("refresh")))'
# Scroll to bottom
playwright-cli run-code 'await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight))'
# Get element count
playwright-cli run-code 'console.log(await page.locator("table tbody tr").count())'
Three tools integrate ResponseBuilder and CacheStore into the v2 skill, enabling rich page diagnostics.
| Command | Description |
|---|---|
bin/context [--screenshot] | Capture full page context → compact TrimmedResponse JSON on stdout |
bin/inject-capture | Inject browser-side console + fetch/XHR patching |
bin/cache-query <cmd> [args] | Query cached data by ID and type |
bin/contextCollects context from three sources and stores it in .playwright-skill/cache/:
playwright-cli snapshot — accessibility tree (YAML)playwright-cli console / playwright-cli network — native browser logsplaywright-cli run-code — page URL, title, HTML, cookies, injected capturesOutputs a TrimmedResponse (~200 tokens) with:
pageState — URL, title, auth status, error flagcacheRef.id — reference ID to retrieve full context latercacheRef.available — list of available data typesbin/context # text/ARIA capture only
bin/context --screenshot # also capture PNG screenshot
bin/inject-capturePatches console.*, window.fetch, and XMLHttpRequest in the browser to capture events in window.__capturedConsole and window.__capturedRequests. These are merged with playwright-layer captures by bin/context.
Idempotent — safe to run multiple times. Only captures events after injection.
bin/inject-capture
# → {"success":true,"hasCapture":true}
bin/cache-queryRetrieves full context stored by bin/context.
bin/cache-query query <id> snapshot # accessibility tree YAML
bin/cache-query query <id> html # full page HTML
bin/cache-query query <id> console # console messages JSON
bin/cache-query query <id> network # network requests JSON
bin/cache-query query <id> screenshot # base64-encoded PNG
bin/cache-query list # JSON array of all cached entries
bin/cache-query stats # entry count, total size, max entries
bin/cache-query clear # clear all entries
bin/cache-query clear <id> # clear one entry
# 1. Start browser and navigate
bin/open --headed
playwright-cli goto http://localhost:8000
bin/auth-load <profile>
# 2. Inject browser-side capture (optional but recommended)
bin/inject-capture
# 3. Perform actions (click, fill, navigate...)
playwright-cli click e5
playwright-cli fill e7 "search term"
playwright-cli press Enter
# 4. Capture full context
bin/context --screenshot
# Read cacheRef.id from the TrimmedResponse output
# 5. Diagnose issues
bin/cache-query query <id> console # check for JS errors
bin/cache-query query <id> network # check API responses
bin/cache-query query <id> snapshot # review page structure
bin/cache-query query <id> screenshot # view page visually (base64 PNG)
# 6. Clean up
bin/close
Multi-project / parallel agent note: When running under Claude Code, each agent automatically gets an isolated session via
CLAUDE_SESSION_ID. Directplaywright-clicommands (goto, click, fill, etc.) work as-is when only one session is open. If multiple sessions are active, prefix with-s=<session>— e.g.playwright-cli -s=my-project-a1b2c3d4 goto <url>. The session name is printed when you runbin/open.
bin/cache-query query <id> console | python3 -c "
import sys, json
msgs = json.load(sys.stdin)
errors = [m for m in msgs if m['type'] == 'error']
for e in errors:
print(e['text'])
"