| name | playwright-skill |
| description | Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing. |
IMPORTANT - Path Resolution:
Determine the skill directory from where this SKILL.md was loaded. Replace .cursor/skills/playwright-skill with that path in all commands below.
Common installation paths:
- Plugin system:
~/.claude/plugins/marketplaces/playwright-skill/skills/playwright-skill
- Manual global:
~/.cursor/skills/playwright-skill
- Project-specific (codex):
.cursor/skills/playwright-skill
- Project-specific:
<project>/.cursor/skills/playwright-skill
Playwright Browser Automation
CRITICAL WORKFLOW
Follow these steps in order for every request:
1. Detect dev servers (localhost testing — run this first, always):
cd .cursor/skills/playwright-skill && node -e "require('./lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
- 1 server found → use it automatically, inform user
- Multiple found → ask user which one
- None found → ask for URL or offer to start dev server
2. Write script to /tmp — never write to skill directory or user's project:
/tmp/playwright-test-<task>.js
3. Execute via run.js:
cd .cursor/skills/playwright-skill && node run.js /tmp/playwright-test-<task>.js
Script Template
Every script must follow this structure:
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001';
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
try {
} catch (e) {
console.error('Error:', e.message);
} finally {
await browser.close();
}
})();
Inline Execution
For quick one-off tasks, skip writing a file:
cd .cursor/skills/playwright-skill && node run.js "
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/shot.png', fullPage: true });
console.log('Done');
"
Use inline for: screenshots, element checks, page title.
Use files for: multi-step flows, responsive tests, anything user might re-run.
Setup
cd .cursor/skills/playwright-skill && npm run setup
Only needed once. Installs Playwright and Chromium.
Available Helpers
const helpers = require('./lib/helpers');
await helpers.detectDevServers()
await helpers.safeClick(page, selector)
await helpers.safeType(page, sel, text)
await helpers.takeScreenshot(page, name)
await helpers.handleCookieBanner(page)
await helpers.extractTableData(page, sel)
await helpers.createContext(browser)
await helpers.authenticate(page, creds)
await helpers.retryWithBackoff(fn)
await helpers.waitForPageReady(page)
Custom Headers
Identify automated traffic or pass auth tokens globally:
PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill \
cd .cursor/skills/playwright-skill && node run.js /tmp/script.js
PW_EXTRA_HEADERS='{"X-Automated-By":"playwright-skill","X-Debug":"true"}' \
cd .cursor/skills/playwright-skill && node run.js /tmp/script.js
Headers apply automatically when using helpers.createContext(browser).
For raw Playwright API, use the injected getContextOptionsWithHeaders(options).
Rules
- Visible browser — always
headless: false unless user explicitly says "headless" or "background"
- Parameterize URLs — put URL in
TARGET_URL constant at top of every script
- Wait strategies — use
waitForURL, waitForSelector, waitForLoadState, never fixed waitForTimeout
- Error handling — always wrap in try/catch, close browser in finally block
Troubleshooting
cd .cursor/skills/playwright-skill && npm run setup
cd .cursor/skills/playwright-skill && node run.js /tmp/script.js
await page.waitForSelector('.target', { timeout: 10000 })
For advanced patterns (network interception, visual regression, auth sessions, CI/CD):
see API_REFERENCE.md