Playwright Browser Automation skill

Complete browser automation with Playwright.

by lackeyjb·MIT license·★ 3,178 Stars on the repo·GitHub ↗

Use now

Files of Playwright Browser Automation

lackeyjb/main1 file shown
SKILL.md
Show the full text216 lines

Playwright Browser Automation

Write and execute focused Playwright scripts for the user's request. Prefer the skill's executor and helpers, but use the full Playwright API when needed.

Path resolution

This skill can be installed in several locations, so resolve its directory first. Set SKILL_DIR to the directory containing this SKILL.md file, then run the commands below as written:

export SKILL_DIR=<absolute path of the directory containing this SKILL.md>
export TMP_DIR="$(node -p 'require("node:os").tmpdir()')"

If shell state does not persist between commands, substitute the literal paths for $SKILL_DIR and $TMP_DIR in each command instead.

Common installation paths:

  • Plugin system: ~/.claude/plugins/marketplaces/playwright-skill/skills/playwright-skill
  • Manual global: ~/.claude/skills/playwright-skill
  • Project-specific: <project>/.claude/skills/playwright-skill

Workflow

  1. For localhost work, detect running servers before writing a URL:

    node -e "require('$SKILL_DIR/lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
    

    Use the only result automatically. Ask which URL to use when there are multiple results. Ask for a URL or offer to start a server when none exist.

  2. Write reusable scripts to $TMP_DIR/playwright-test-*.js unless the user asks to save them in the project. Use PW_SCRIPT_DIR to preserve scripts.

  3. Use a visible browser by default. Use headless: true only when requested or when the environment has no display.

  4. Put the target URL in a constant or environment variable.

  5. Run scripts with node "$SKILL_DIR/run.js" <script.js>.

  6. Report actions, failures, and artifact paths. Do not claim success without checking the resulting page.

Setup

Run once:

cd "$SKILL_DIR" && npm run setup

This installs Playwright and Chromium. Use cd "$SKILL_DIR" && npm run install-all-browsers when Firefox or WebKit is required.

Minimal example

const os = require('node:os');
const path = require('node:path');
const { chromium } = require('playwright');

const targetUrl = process.env.TARGET_URL || 'http://localhost:3000';
const artifactDir = process.env.PW_ARTIFACT_DIR || os.tmpdir();

(async () => {
  const browser = await chromium.launch({ headless: false });
  try {
    const page = await browser.newPage();
    await page.goto(targetUrl);
    console.log('Page loaded:', await page.title());
    await page.screenshot({ path: path.join(artifactDir, 'page.png'), fullPage: true });
  } finally {
    await browser.close();
  }
})();

Run it:

node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-page.js"

For short one-off tasks, use inline execution:

node "$SKILL_DIR/run.js" -e "const browser = await chromium.launch({headless: false}); try { const page = await browser.newPage(); await page.goto('https://example.com'); console.log(await page.title()); } finally { await browser.close(); }"

The -e process exits as soon as the snippet settles, so close the browser inside the snippet.

Current Playwright patterns

Prefer locators that describe what a user sees, in this order:

  1. page.getByRole() with an accessible name
  2. page.getByLabel() for form controls
  3. page.getByText() for visible content
  4. page.getByTestId() when the application provides a test contract

Actions auto-wait for actionability. Use web-first assertions or a locator's waitFor() instead of waitForSelector(), fixed sleeps, or networkidle.

await page.getByLabel('Email').fill('[email protected]');
await page.getByRole('button', { name: 'Sign in' }).click();
await page.waitForURL('**/dashboard');
await page.getByRole('heading', { name: 'Dashboard' }).waitFor();

Common tasks

Responsive checks
{
  const os = require('node:os');
  const path = require('node:path');

  const artifactDir = process.env.PW_ARTIFACT_DIR || os.tmpdir();
  const viewports = [
    { name: 'desktop', width: 1440, height: 900 },
    { name: 'mobile', width: 390, height: 844 },
  ];

  for (const viewport of viewports) {
    await page.setViewportSize(viewport);
    await page.goto(targetUrl);
    await page.screenshot({ path: path.join(artifactDir, `${viewport.name}.png`), fullPage: true });
  }
}
Login flow

Use test credentials supplied by the user. Never invent or expose real credentials. Verify both the navigation and a post-login element.

await page.goto(`${targetUrl}/login`);
await page.getByLabel('Email').fill(process.env.TEST_EMAIL);
await page.getByLabel('Password').fill(process.env.TEST_PASSWORD);
await page.getByRole('button', { name: /sign in|log in/i }).click();
await page.waitForURL('**/dashboard');
await page.getByRole('heading', { name: /dashboard/i }).waitFor();
Save scripts and artifacts
PW_SCRIPT_DIR=./playwright-tests node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-login.js"
PW_ARTIFACT_DIR=./playwright-artifacts node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-page.js"

PW_SCRIPT_DIR copies file-based scripts before execution and adds a timestamp when a filename already exists. PW_ARTIFACT_DIR controls helper screenshot output; the default is the operating system temporary directory.

Connect to an existing Chrome session

Start Chrome with remote debugging enabled, then connect with Playwright:

const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
const page = browser.contexts()[0].pages()[0];

This reuses cookies and extensions in that session. Do not use it for secrets unless the user explicitly asks; a connected browser has the user's access.

Helpers

const helpers = require(`${process.env.PW_SKILL_DIR}/lib/helpers`);

const servers = await helpers.detectDevServers();
const browser = await helpers.launchBrowser('chromium');
const context = await helpers.createContext(browser);
const page = await context.newPage();
await helpers.handleCookieBanner(page);
await helpers.takeScreenshot(page, 'result');

Available helpers are detectDevServers, getExtraHeadersFromEnv, launchBrowser, createContext, handleCookieBanner, and takeScreenshot. Use Playwright locators and assertions directly for actions, waits, extraction, authentication, tables, and retries.

Configuration

  • PW_BROWSER: chromium, firefox, or webkit for launchBrowser().
  • PW_CHANNEL: installed browser channel such as chrome or msedge.
  • PW_EXECUTABLE_PATH: explicit browser executable path.
  • PW_HEADLESS: true or false; visible mode is the default.
  • SLOW_MO: action delay in milliseconds.
  • PW_HEADER_NAME and PW_HEADER_VALUE: one extra HTTP header.
  • PW_EXTRA_HEADERS: JSON object of extra HTTP headers.
  • PW_SCRIPT_DIR: directory for preserving file-based scripts.
  • PW_ARTIFACT_DIR: directory for helper-generated screenshots.

See API_REFERENCE.md for network interception, API mocking, authentication state, video, visual checks, device emulation, and CI patterns.

1---
2name: playwright-skill
3description: Complete browser automation with Playwright. Auto-detects dev servers, writes reusable test scripts, and supports screenshots, responsive checks, UX validation, login flows, link checks, and arbitrary browser automation. Use when the user wants to test a website, automate browser interactions, validate web functionality, or perform browser-based testing.
4license: MIT
5compatibility: Requires Node.js 20+, npm, and network access on first setup to install Playwright and Chromium.
6metadata:
7 author: lackeyjb
8 version: "5.0.0"
9allowed-tools: Bash(node:*) Bash(npm:*) Read Write
10---
11 
12# Playwright Browser Automation
13 
14Write and execute focused Playwright scripts for the user's request. Prefer the
15skill's executor and helpers, but use the full Playwright API when needed.
16 
17## Path resolution
18 
19This skill can be installed in several locations, so resolve its directory
20first. Set `SKILL_DIR` to the directory containing this SKILL.md file, then run
21the commands below as written:
22 
23```bash
24export SKILL_DIR=<absolute path of the directory containing this SKILL.md>
25export TMP_DIR="$(node -p 'require("node:os").tmpdir()')"
26```
27 
28If shell state does not persist between commands, substitute the literal paths
29for `$SKILL_DIR` and `$TMP_DIR` in each command instead.
30 
31Common installation paths:
32 
33- Plugin system: `~/.claude/plugins/marketplaces/playwright-skill/skills/playwright-skill`
34- Manual global: `~/.claude/skills/playwright-skill`
35- Project-specific: `<project>/.claude/skills/playwright-skill`
36 
37## Workflow
38 
391. For localhost work, detect running servers before writing a URL:
40 
41 ```bash
42 node -e "require('$SKILL_DIR/lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
43 ```
44 
45 Use the only result automatically. Ask which URL to use when there are
46 multiple results. Ask for a URL or offer to start a server when none exist.
472. Write reusable scripts to `$TMP_DIR/playwright-test-*.js` unless the user
48 asks to save them in the project. Use `PW_SCRIPT_DIR` to preserve scripts.
493. Use a visible browser by default. Use `headless: true` only when requested
50 or when the environment has no display.
514. Put the target URL in a constant or environment variable.
525. Run scripts with `node "$SKILL_DIR/run.js" <script.js>`.
536. Report actions, failures, and artifact paths. Do not claim success without
54 checking the resulting page.
55 
56## Setup
57 
58Run once:
59 
60```bash
61cd "$SKILL_DIR" && npm run setup
62```
63 
64This installs Playwright and Chromium. Use `cd "$SKILL_DIR" && npm run
65install-all-browsers` when Firefox or WebKit is required.
66 
67## Minimal example
68 
69```javascript
70const os = require('node:os');
71const path = require('node:path');
72const { chromium } = require('playwright');
73 
74const targetUrl = process.env.TARGET_URL || 'http://localhost:3000';
75const artifactDir = process.env.PW_ARTIFACT_DIR || os.tmpdir();
76 
77(async () => {
78 const browser = await chromium.launch({ headless: false });
79 try {
80 const page = await browser.newPage();
81 await page.goto(targetUrl);
82 console.log('Page loaded:', await page.title());
83 await page.screenshot({ path: path.join(artifactDir, 'page.png'), fullPage: true });
84 } finally {
85 await browser.close();
86 }
87})();
88```
89 
90Run it:
91 
92```bash
93node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-page.js"
94```
95 
96For short one-off tasks, use inline execution:
97 
98```bash
99node "$SKILL_DIR/run.js" -e "const browser = await chromium.launch({headless: false}); try { const page = await browser.newPage(); await page.goto('https://example.com'); console.log(await page.title()); } finally { await browser.close(); }"
100```
101 
102The `-e` process exits as soon as the snippet settles, so close the browser
103inside the snippet.
104 
105## Current Playwright patterns
106 
107Prefer locators that describe what a user sees, in this order:
108 
1091. `page.getByRole()` with an accessible name
1102. `page.getByLabel()` for form controls
1113. `page.getByText()` for visible content
1124. `page.getByTestId()` when the application provides a test contract
113 
114Actions auto-wait for actionability. Use web-first assertions or a locator's
115`waitFor()` instead of `waitForSelector()`, fixed sleeps, or `networkidle`.
116 
117```javascript
118await page.getByLabel('Email').fill('[email protected]');
119await page.getByRole('button', { name: 'Sign in' }).click();
120await page.waitForURL('**/dashboard');
121await page.getByRole('heading', { name: 'Dashboard' }).waitFor();
122```
123 
124## Common tasks
125 
126### Responsive checks
127 
128```javascript
129{
130 const os = require('node:os');
131 const path = require('node:path');
132 
133 const artifactDir = process.env.PW_ARTIFACT_DIR || os.tmpdir();
134 const viewports = [
135 { name: 'desktop', width: 1440, height: 900 },
136 { name: 'mobile', width: 390, height: 844 },
137 ];
138 
139 for (const viewport of viewports) {
140 await page.setViewportSize(viewport);
141 await page.goto(targetUrl);
142 await page.screenshot({ path: path.join(artifactDir, `${viewport.name}.png`), fullPage: true });
143 }
144}
145```
146 
147### Login flow
148 
149Use test credentials supplied by the user. Never invent or expose real
150credentials. Verify both the navigation and a post-login element.
151 
152```javascript
153await page.goto(`${targetUrl}/login`);
154await page.getByLabel('Email').fill(process.env.TEST_EMAIL);
155await page.getByLabel('Password').fill(process.env.TEST_PASSWORD);
156await page.getByRole('button', { name: /sign in|log in/i }).click();
157await page.waitForURL('**/dashboard');
158await page.getByRole('heading', { name: /dashboard/i }).waitFor();
159```
160 
161### Save scripts and artifacts
162 
163```bash
164PW_SCRIPT_DIR=./playwright-tests node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-login.js"
165PW_ARTIFACT_DIR=./playwright-artifacts node "$SKILL_DIR/run.js" "$TMP_DIR/playwright-test-page.js"
166```
167 
168`PW_SCRIPT_DIR` copies file-based scripts before execution and adds a timestamp
169when a filename already exists. `PW_ARTIFACT_DIR` controls helper screenshot
170output; the default is the operating system temporary directory.
171 
172### Connect to an existing Chrome session
173 
174Start Chrome with remote debugging enabled, then connect with Playwright:
175 
176```javascript
177const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
178const page = browser.contexts()[0].pages()[0];
179```
180 
181This reuses cookies and extensions in that session. Do not use it for secrets
182unless the user explicitly asks; a connected browser has the user's access.
183 
184## Helpers
185 
186```javascript
187const helpers = require(`${process.env.PW_SKILL_DIR}/lib/helpers`);
188 
189const servers = await helpers.detectDevServers();
190const browser = await helpers.launchBrowser('chromium');
191const context = await helpers.createContext(browser);
192const page = await context.newPage();
193await helpers.handleCookieBanner(page);
194await helpers.takeScreenshot(page, 'result');
195```
196 
197Available helpers are `detectDevServers`, `getExtraHeadersFromEnv`,
198`launchBrowser`, `createContext`, `handleCookieBanner`, and `takeScreenshot`.
199Use Playwright locators and assertions directly for actions, waits, extraction,
200authentication, tables, and retries.
201 
202## Configuration
203 
204- `PW_BROWSER`: `chromium`, `firefox`, or `webkit` for `launchBrowser()`.
205- `PW_CHANNEL`: installed browser channel such as `chrome` or `msedge`.
206- `PW_EXECUTABLE_PATH`: explicit browser executable path.
207- `PW_HEADLESS`: `true` or `false`; visible mode is the default.
208- `SLOW_MO`: action delay in milliseconds.
209- `PW_HEADER_NAME` and `PW_HEADER_VALUE`: one extra HTTP header.
210- `PW_EXTRA_HEADERS`: JSON object of extra HTTP headers.
211- `PW_SCRIPT_DIR`: directory for preserving file-based scripts.
212- `PW_ARTIFACT_DIR`: directory for helper-generated screenshots.
213 
214See [API_REFERENCE.md](API_REFERENCE.md) for network interception, API mocking,
215authentication state, video, visual checks, device emulation, and CI patterns.
216 

Discussion

Alternatives

Browser Automation SkillWeb browser automation with AI-optimized snapshots for claude-flow agentsCoding · MITDeepevalDeepEval evaluation workflow for AI agents and LLM applications. TRIGGER when the user wants to evaluate or improve an AI agent, tool-using workflow, multi-turn chatbot, RAG pipeline, or LLM app; add evals; generate datasets or goldens; use deepeval generate; use deepeval test run; send results to Confident AI; monitor production; run online evals; inspect traces; or iterate on prompts, tools, retrieval, or agent behavior from eval failures. AI agents are the primary use case. Covers Python SDK, pytest eval suites, CLI generation, traced evals, Confident AI reporting, and agent-driven improvement loops. DO NOT TRIGGER for unrelated generic pytest, non-AI test setup, or non-DeepEval observability work unless the user asks to compare or migrate to DeepEval; for instrumenting an app with DeepEval tracing, @observe, or framework integrations (use the `deepeval-tracing` skill); or for raw OpenTelemetry / OTLP export without the deepeval package (use the `deepeval-otel` skill).Business & ops · Apache-2.0Dev browserBrowser automation with persistent named pages via the dev-browser CLI. Use when users ask to navigate websites, fill forms, take screenshots, extract web data, test web apps, log into sites, or automate browser workflows. Trigger phrases include "go to [url]", "click on", "fill out the form", "take a screenshot", "scrape", "automate", "test the website", "log into", "open the browser", or any browser interaction request.Business & ops · MITTurn into appTurn visible project context, a proven thread, skill, or workflow into a runnable Agent-Native app with simple buttons, visible agent steps, preview, and deployment handoff. Use when a user invokes `/turn-into-app` or asks to make a workflow into an app, including from Claude or ChatGPT on the web, including when the source is a spreadsheet link or upload.Business & ops · MIT