
Playwright Cli
- 2 installs
- 21 repo stars
- Updated August 5, 2026
- joaquimscosta/arkhe-claude-plugins
Drives Playwright from the command line for browser automation and end-to-end testing.
About
Runs Playwright browser automation and end-to-end tests via the CLI. A developer uses it when writing or executing browser-based E2E tests.
- Playwright browser automation via CLI
- End-to-end test execution
Playwright Cli by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,693 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joaquimscosta/arkhe-claude-plugins --skill playwright-cliAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 21 |
| Last updated | August 5, 2026 |
| Repository | joaquimscosta/arkhe-claude-plugins ↗ |
What it does
Drives Playwright from the command line for browser automation and end-to-end testing.
Files
Playwright CLI
Automate browsers through shell commands via the Bash tool.
Core Workflow
Every interaction follows this pattern:
1. Open a page: playwright-cli open <url> 2. Snapshot to discover elements: playwright-cli snapshot 3. Interact using refs from the snapshot: playwright-cli click <ref> 4. Verify the result: playwright-cli screenshot or playwright-cli snapshot
Always run snapshot before interacting — element refs come exclusively from snapshot output and become stale after navigation.
Command Reference
Navigation
| Command | Description |
|---|---|
open <url> | Open URL in new page |
goto <url> | Navigate current page |
go-back / go-forward | Browser back/forward |
reload | Reload current page |
close | Close the browser |
Interaction
| Command | Description |
|---|---|
click <ref> | Click an element |
dblclick <ref> | Double-click an element |
fill <ref> <text> | Clear field, then type text |
type <text> | Type into focused element (appends) |
check <ref> / uncheck <ref> | Toggle checkbox |
select <ref> <values> | Select dropdown option(s) |
hover <ref> | Hover over element |
drag <start> <end> | Drag between elements |
upload <ref> <paths> | Upload file(s) to file input |
eval "<js>" | Evaluate JavaScript on page |
eval "<js>" <ref> | Evaluate JavaScript on element |
dialog-accept [text] | Accept dialog (optional prompt text) |
dialog-dismiss | Dismiss dialog |
resize <w> <h> | Resize browser window |
Output
| Command | Description |
|---|---|
screenshot [ref] [--filename=f] | Capture PNG screenshot (page or element) |
snapshot [--filename=f] | Accessibility tree — structured, token-efficient |
pdf [--filename=f] | Generate PDF of the page |
Important:--filenameresolves relative to the working directory, NOToutputDir.
When using--filename, always prepend the project'soutputDirvalue
(check.playwright/cli.config.json; defaults to.playwright-cli).
Example: playwright-cli screenshot --filename=<outputDir>/my-screenshot.pngTabs
| Command | Description |
|---|---|
tab list | List open tabs |
tab create [url] | Open new tab |
tab select <index> | Switch to tab |
tab close [index] | Close tab |
Keyboard
playwright-cli press Enter # Enter, Tab, Escape, ArrowDown, etc.
playwright-cli keydown Shift # Hold key down
playwright-cli keyup Shift # Release keyMouse
playwright-cli mousemove 150 300 # Move to coordinates
playwright-cli mousedown [button] # Press button (left/right)
playwright-cli mouseup [button] # Release button
playwright-cli mousewheel 0 100 # Scroll (deltaX deltaY)Sessions
- Default session — all commands share one session automatically
- Named sessions —
playwright-cli -s=<name> open <url>for parallel browsers - List sessions —
playwright-cli list - Close one —
playwright-cli -s=<name> close - Close all —
playwright-cli close-all - Force kill —
playwright-cli kill-all - Persistent profile —
playwright-cli open <url> --persistent - Custom profile —
playwright-cli open <url> --profile=/path/to/dir - Delete data —
playwright-cli delete-dataorplaywright-cli -s=<name> delete-data - Environment variable —
PLAYWRIGHT_CLI_SESSION=my-project
Configuration
playwright-cli open <url> --browser=chromium # chromium (default), firefox, webkit, chrome, msedge
playwright-cli open <url> --headed # Visible browser window
playwright-cli open <url> --config=config.json # Custom config file
playwright-cli open <url> --extension # Connect via browser extensionCreate .playwright/cli.config.json in the project for persistent settings:
{ "browser": { "browserName": "chromium", "launchOptions": { "headless": true } }, "outputDir": ".playwright-cli", "timeouts": { "action": 5000, "navigation": 60000 } }Other options: network.allowedOrigins, network.blockedOrigins, saveVideo. Environment variables use PLAYWRIGHT_MCP_ prefix (e.g., PLAYWRIGHT_MCP_BROWSER=firefox).
Common Pitfalls
- Interacting without snapshot — refs are unknown until
snapshotruns - Stale refs after navigation — re-run
snapshotaftergoto, link clicks, or form submissions - fill vs type —
fillclears the field first;typeappends to current content - Stuck sessions — run
playwright-cli kill-allto force-close all browsers
Resources
- EXAMPLES.md — Multi-step workflow examples
- TROUBLESHOOTING.md — Error diagnosis and fixes
- references/request-mocking.md — Intercept, mock, and block network requests
- references/running-code.md — Execute arbitrary Playwright code via
run-code - references/session-management.md — Named sessions, isolation, concurrent browsers
- references/storage-state.md — Cookies, localStorage, sessionStorage management
- references/test-generation.md — Generate Playwright test code from CLI actions
- references/tracing.md — Capture execution traces for debugging
- references/video-recording.md — Record browser sessions as WebM video
Playwright CLI Examples
Practical workflow examples progressing from simple to complex.
---
1. Basic Screenshot Capture
Capture a screenshot of any public page:
# Open the page
playwright-cli open https://example.com
# Capture screenshot (--filename must include outputDir path)
playwright-cli screenshot --filename=.playwright-cli/example-homepage.png
# Close the browser
playwright-cli close---
2. Login Form Flow
Authenticate into a web application using form fields:
# Open the login page
playwright-cli open https://myapp.com/login
# Discover form elements
playwright-cli snapshot
# Output includes refs like:
# textbox "Email" [ref=e12]
# textbox "Password" [ref=e15]
# button "Sign in" [ref=e18]
# Fill credentials using refs from snapshot
playwright-cli fill e12 "user@example.com"
playwright-cli fill e15 "my-password"
# Submit the form
playwright-cli click e18
# Verify login succeeded — re-snapshot after navigation
playwright-cli snapshot
# Look for dashboard elements in the output
# Capture evidence (--filename must include outputDir path)
playwright-cli screenshot --filename=.playwright-cli/logged-in-dashboard.pngKey points:
- Always
snapshotbefore interacting to get element refs - Re-run
snapshotafter navigation (the click triggered a page change) - Use
fill(nottype) for form fields — it clears existing content first
---
3. TodoMVC Testing Workflow
Add items, check them off, and verify the result:
# Open the app with a visible browser for observation
playwright-cli open https://demo.playwright.dev/todomvc/ --headed
# Add todo items by typing into the focused input
playwright-cli type "Buy groceries"
playwright-cli press Enter
playwright-cli type "Water flowers"
playwright-cli press Enter
playwright-cli type "Read a book"
playwright-cli press Enter
# Snapshot to discover checkbox refs
playwright-cli snapshot
# Output includes:
# checkbox "Toggle Todo" [ref=e21] (for "Buy groceries")
# checkbox "Toggle Todo" [ref=e28] (for "Water flowers")
# checkbox "Toggle Todo" [ref=e35] (for "Read a book")
# Check off the first two items
playwright-cli check e21
playwright-cli check e28
# Verify the result (--filename must include outputDir path)
playwright-cli screenshot --filename=.playwright-cli/todo-progress.png
# Clean up
playwright-cli closeKey points:
typeappends text to the focused element (the new-todo input auto-focuses)press Entersubmits each todo itemchecktoggles checkboxes using refs from the snapshot
---
4. Multi-Tab Research with Named Sessions
Work across multiple pages simultaneously using named sessions:
# Open the main application in session "app"
playwright-cli -s=app open https://myapp.com/dashboard
# Open documentation in session "docs"
playwright-cli -s=docs open https://docs.myapp.com/api
# Work in the docs session — find an API endpoint
playwright-cli -s=docs snapshot
# Switch back to the app session — it's still on the dashboard
playwright-cli -s=app snapshot
# Use tabs within a single session
playwright-cli -s=app tab create https://myapp.com/settings
playwright-cli -s=app tab list
# Output:
# 0: Dashboard - MyApp (active)
# 1: Settings - MyApp
playwright-cli -s=app tab select 1
playwright-cli -s=app snapshot
# List all active sessions
playwright-cli list
# Close specific session
playwright-cli -s=docs close
# Close all sessions when done
playwright-cli close-allKey points:
- Named sessions (
-s=<name>) run independent browser instances - Each session maintains its own cookies, localStorage, and tabs
playwright-cli listshows all active sessions- Tabs within a session share the same browser context
---
5. Headed Debugging with Configuration
Set up a persistent configuration for visual debugging:
.playwright/cli.config.json:
{
"browser": {
"browserName": "chromium",
"launchOptions": {
"headless": false
}
},
"outputDir": "./screenshots",
"timeouts": {
"action": 10000,
"navigation": 30000
}
}# With config file in place, browser opens visually by default
playwright-cli open https://myapp.com
# Take a full-page snapshot to understand the layout
playwright-cli snapshot
# Interact step by step — watch the browser respond
playwright-cli click e5
playwright-cli fill e10 "search query"
playwright-cli press Enter
# --filename must include outputDir path (./screenshots/ here)
playwright-cli screenshot --filename=./screenshots/debug-result.png
# Override browser engine via environment variable
PLAYWRIGHT_MCP_BROWSER=firefox playwright-cli open https://myapp.comKey points:
.playwright/cli.config.jsonpersists configuration across all CLI invocations- Set
headless: falsefor visual debugging sessions - Increase timeouts for slow-loading pages
outputDircontrols where auto-named screenshots and PDFs are saved- When using
--filename, prepend theoutputDirpath (e.g.,./screenshots/name.png) - Environment variables (
PLAYWRIGHT_MCP_prefix) override config file settings
---
Pattern Summary
| Pattern | Commands Used | When to Use |
|---|---|---|
| Screenshot | open → screenshot → close | Quick page capture |
| Form fill | open → snapshot → fill → click → snapshot | Login, search, data entry |
| Testing | open → type/press → snapshot → check/click | E2E test workflows |
| Multi-context | -s=<name> for each context | Parallel page research |
| Debugging | Config file + --headed | Visual inspection |
Request Mocking
Intercept, mock, modify, and block network requests.
CLI Route Commands
# Mock with custom status
playwright-cli route "**/*.jpg" --status=404
# Mock with JSON body
playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json
# Mock with custom headers
playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"
# Remove headers from requests
playwright-cli route "**/*" --remove-header=cookie,authorization
# List active routes
playwright-cli route-list
# Remove a route or all routes
playwright-cli unroute "**/*.jpg"
playwright-cli unrouteURL Patterns
**/api/users - Exact path match
**/api/*/details - Wildcard in path
**/*.{png,jpg,jpeg} - Match file extensions
**/search?q=* - Match query parametersAdvanced Mocking with run-code
For conditional responses, request body inspection, response modification, or delays:
Conditional Response Based on Request
playwright-cli run-code "async page => {
await page.route('**/api/login', route => {
const body = route.request().postDataJSON();
if (body.username === 'admin') {
route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) });
} else {
route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) });
}
});
}"Modify Real Response
playwright-cli run-code "async page => {
await page.route('**/api/user', async route => {
const response = await route.fetch();
const json = await response.json();
json.isPremium = true;
await route.fulfill({ response, json });
});
}"Simulate Network Failures
playwright-cli run-code "async page => {
await page.route('**/api/offline', route => route.abort('internetdisconnected'));
}"
# Options: connectionrefused, timedout, connectionreset, internetdisconnectedDelayed Response
playwright-cli run-code "async page => {
await page.route('**/api/slow', async route => {
await new Promise(r => setTimeout(r, 3000));
route.fulfill({ body: JSON.stringify({ data: 'loaded' }) });
});
}"Running Custom Playwright Code
Use run-code to execute arbitrary Playwright code for advanced scenarios not covered by CLI commands.
Table of Contents
- Syntax
- Geolocation
- Permissions
- Media Emulation
- Wait Strategies
- Frames and Iframes
- File Downloads
- Clipboard
- Page Information
- JavaScript Execution
- Error Handling
- Complex Workflows
Syntax
playwright-cli run-code "async page => {
// Your Playwright code here
// Access page.context() for browser context operations
}"Geolocation
# Grant geolocation permission and set location
playwright-cli run-code "async page => {
await page.context().grantPermissions(['geolocation']);
await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
}"
# Set location to London
playwright-cli run-code "async page => {
await page.context().grantPermissions(['geolocation']);
await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
}"
# Clear geolocation override
playwright-cli run-code "async page => {
await page.context().clearPermissions();
}"Permissions
# Grant multiple permissions
playwright-cli run-code "async page => {
await page.context().grantPermissions([
'geolocation',
'notifications',
'camera',
'microphone'
]);
}"
# Grant permissions for specific origin
playwright-cli run-code "async page => {
await page.context().grantPermissions(['clipboard-read'], {
origin: 'https://example.com'
});
}"Media Emulation
# Emulate dark color scheme
playwright-cli run-code "async page => {
await page.emulateMedia({ colorScheme: 'dark' });
}"
# Emulate light color scheme
playwright-cli run-code "async page => {
await page.emulateMedia({ colorScheme: 'light' });
}"
# Emulate reduced motion
playwright-cli run-code "async page => {
await page.emulateMedia({ reducedMotion: 'reduce' });
}"
# Emulate print media
playwright-cli run-code "async page => {
await page.emulateMedia({ media: 'print' });
}"Wait Strategies
# Wait for network idle
playwright-cli run-code "async page => {
await page.waitForLoadState('networkidle');
}"
# Wait for specific element
playwright-cli run-code "async page => {
await page.waitForSelector('.loading', { state: 'hidden' });
}"
# Wait for function to return true
playwright-cli run-code "async page => {
await page.waitForFunction(() => window.appReady === true);
}"
# Wait with timeout
playwright-cli run-code "async page => {
await page.waitForSelector('.result', { timeout: 10000 });
}"Frames and Iframes
# Work with iframe
playwright-cli run-code "async page => {
const frame = page.locator('iframe#my-iframe').contentFrame();
await frame.locator('button').click();
}"
# Get all frames
playwright-cli run-code "async page => {
const frames = page.frames();
return frames.map(f => f.url());
}"File Downloads
# Handle file download
playwright-cli run-code "async page => {
const [download] = await Promise.all([
page.waitForEvent('download'),
page.click('a.download-link')
]);
await download.saveAs('./downloaded-file.pdf');
return download.suggestedFilename();
}"Clipboard
# Read clipboard (requires permission)
playwright-cli run-code "async page => {
await page.context().grantPermissions(['clipboard-read']);
return await page.evaluate(() => navigator.clipboard.readText());
}"
# Write to clipboard
playwright-cli run-code "async page => {
await page.evaluate(text => navigator.clipboard.writeText(text), 'Hello clipboard!');
}"Page Information
# Get page title
playwright-cli run-code "async page => {
return await page.title();
}"
# Get current URL
playwright-cli run-code "async page => {
return page.url();
}"
# Get page content
playwright-cli run-code "async page => {
return await page.content();
}"
# Get viewport size
playwright-cli run-code "async page => {
return page.viewportSize();
}"JavaScript Execution
# Execute JavaScript and return result
playwright-cli run-code "async page => {
return await page.evaluate(() => {
return {
userAgent: navigator.userAgent,
language: navigator.language,
cookiesEnabled: navigator.cookieEnabled
};
});
}"
# Pass arguments to evaluate
playwright-cli run-code "async page => {
const multiplier = 5;
return await page.evaluate(m => document.querySelectorAll('li').length * m, multiplier);
}"Error Handling
# Try-catch in run-code
playwright-cli run-code "async page => {
try {
await page.click('.maybe-missing', { timeout: 1000 });
return 'clicked';
} catch (e) {
return 'element not found';
}
}"Complex Workflows
# Login and save state
playwright-cli run-code "async page => {
await page.goto('https://example.com/login');
await page.fill('input[name=email]', 'user@example.com');
await page.fill('input[name=password]', 'secret');
await page.click('button[type=submit]');
await page.waitForURL('**/dashboard');
await page.context().storageState({ path: 'auth.json' });
return 'Login successful';
}"
# Scrape data from multiple pages
playwright-cli run-code "async page => {
const results = [];
for (let i = 1; i <= 3; i++) {
await page.goto(\`https://example.com/page/\${i}\`);
const items = await page.locator('.item').allTextContents();
results.push(...items);
}
return results;
}"Browser Session Management
Run multiple isolated browser sessions concurrently with state persistence.
Table of Contents
- Named Browser Sessions
- Browser Session Isolation Properties
- Browser Session Commands
- Environment Variable
- Common Patterns
- Default Browser Session
- Browser Session Configuration
- Best Practices
Named Browser Sessions
Use -s flag to isolate browser contexts:
# Browser 1: Authentication flow
playwright-cli -s=auth open https://app.example.com/login
# Browser 2: Public browsing (separate cookies, storage)
playwright-cli -s=public open https://example.com
# Commands are isolated by browser session
playwright-cli -s=auth fill e1 "user@example.com"
playwright-cli -s=public snapshotBrowser Session Isolation Properties
Each browser session has independent:
- Cookies
- LocalStorage / SessionStorage
- IndexedDB
- Cache
- Browsing history
- Open tabs
Browser Session Commands
# List all browser sessions
playwright-cli list
# Stop a browser session (close the browser)
playwright-cli close # stop the default browser
playwright-cli -s=mysession close # stop a named browser
# Stop all browser sessions
playwright-cli close-all
# Forcefully kill all daemon processes (for stale/zombie processes)
playwright-cli kill-all
# Delete browser session user data (profile directory)
playwright-cli delete-data # delete default browser data
playwright-cli -s=mysession delete-data # delete named browser dataEnvironment Variable
Set a default browser session name via environment variable:
export PLAYWRIGHT_CLI_SESSION="mysession"
playwright-cli open example.com # Uses "mysession" automaticallyCommon Patterns
Concurrent Scraping
#!/bin/bash
# Scrape multiple sites concurrently
# Start all browsers
playwright-cli -s=site1 open https://site1.com &
playwright-cli -s=site2 open https://site2.com &
playwright-cli -s=site3 open https://site3.com &
wait
# Take snapshots from each
playwright-cli -s=site1 snapshot
playwright-cli -s=site2 snapshot
playwright-cli -s=site3 snapshot
# Cleanup
playwright-cli close-allA/B Testing Sessions
# Test different user experiences
playwright-cli -s=variant-a open "https://app.com?variant=a"
playwright-cli -s=variant-b open "https://app.com?variant=b"
# Compare
playwright-cli -s=variant-a screenshot
playwright-cli -s=variant-b screenshotPersistent Profile
By default, browser profile is kept in memory only. Use --persistent flag on open to persist the browser profile to disk:
# Use persistent profile (auto-generated location)
playwright-cli open https://example.com --persistent
# Use persistent profile with custom directory
playwright-cli open https://example.com --profile=/path/to/profileDefault Browser Session
When -s is omitted, commands use the default browser session:
# These use the same default browser session
playwright-cli open https://example.com
playwright-cli snapshot
playwright-cli close # Stops default browserBrowser Session Configuration
Configure a browser session with specific settings when opening:
# Open with config file
playwright-cli open https://example.com --config=.playwright/my-cli.json
# Open with specific browser
playwright-cli open https://example.com --browser=firefox
# Open in headed mode
playwright-cli open https://example.com --headed
# Open with persistent profile
playwright-cli open https://example.com --persistentBest Practices
1. Name Browser Sessions Semantically
# GOOD: Clear purpose
playwright-cli -s=github-auth open https://github.com
playwright-cli -s=docs-scrape open https://docs.example.com
# AVOID: Generic names
playwright-cli -s=s1 open https://github.com2. Always Clean Up
# Stop browsers when done
playwright-cli -s=auth close
playwright-cli -s=scrape close
# Or stop all at once
playwright-cli close-all
# If browsers become unresponsive or zombie processes remain
playwright-cli kill-all3. Delete Stale Browser Data
# Remove old browser data to free disk space
playwright-cli -s=oldsession delete-dataStorage Management
Manage cookies, localStorage, sessionStorage, and browser storage state.
Table of Contents
Storage State
Save and restore complete browser state including cookies and storage.
Save Storage State
# Save to auto-generated filename (storage-state-{timestamp}.json)
playwright-cli state-save
# Save to specific filename
playwright-cli state-save my-auth-state.jsonRestore Storage State
# Load storage state from file
playwright-cli state-load my-auth-state.json
# Reload page to apply cookies
playwright-cli open https://example.comStorage State File Format
The saved file contains:
{
"cookies": [
{
"name": "session_id",
"value": "abc123",
"domain": "example.com",
"path": "/",
"expires": 1735689600,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
}
],
"origins": [
{
"origin": "https://example.com",
"localStorage": [
{ "name": "theme", "value": "dark" },
{ "name": "user_id", "value": "12345" }
]
}
]
}Cookies
List All Cookies
playwright-cli cookie-listFilter Cookies by Domain
playwright-cli cookie-list --domain=example.comFilter Cookies by Path
playwright-cli cookie-list --path=/apiGet Specific Cookie
playwright-cli cookie-get session_idSet a Cookie
# Basic cookie
playwright-cli cookie-set session abc123
# Cookie with options
playwright-cli cookie-set session abc123 --domain=example.com --path=/ --httpOnly --secure --sameSite=Lax
# Cookie with expiration (Unix timestamp)
playwright-cli cookie-set remember_me token123 --expires=1735689600Delete a Cookie
playwright-cli cookie-delete session_idClear All Cookies
playwright-cli cookie-clearAdvanced: Multiple Cookies or Custom Options
For complex scenarios like adding multiple cookies at once, use run-code:
playwright-cli run-code "async page => {
await page.context().addCookies([
{ name: 'session_id', value: 'sess_abc123', domain: 'example.com', path: '/', httpOnly: true },
{ name: 'preferences', value: JSON.stringify({ theme: 'dark' }), domain: 'example.com', path: '/' }
]);
}"Local Storage
List All localStorage Items
playwright-cli localstorage-listGet Single Value
playwright-cli localstorage-get tokenSet Value
playwright-cli localstorage-set theme darkSet JSON Value
playwright-cli localstorage-set user_settings '{"theme":"dark","language":"en"}'Delete Single Item
playwright-cli localstorage-delete tokenClear All localStorage
playwright-cli localstorage-clearAdvanced: Multiple Operations
For complex scenarios like setting multiple values at once, use run-code:
playwright-cli run-code "async page => {
await page.evaluate(() => {
localStorage.setItem('token', 'jwt_abc123');
localStorage.setItem('user_id', '12345');
localStorage.setItem('expires_at', Date.now() + 3600000);
});
}"Session Storage
List All sessionStorage Items
playwright-cli sessionstorage-listGet Single Value
playwright-cli sessionstorage-get form_dataSet Value
playwright-cli sessionstorage-set step 3Delete Single Item
playwright-cli sessionstorage-delete stepClear sessionStorage
playwright-cli sessionstorage-clearIndexedDB
List Databases
playwright-cli run-code "async page => {
return await page.evaluate(async () => {
const databases = await indexedDB.databases();
return databases;
});
}"Delete Database
playwright-cli run-code "async page => {
await page.evaluate(() => {
indexedDB.deleteDatabase('myDatabase');
});
}"Common Patterns
Authentication State Reuse
# Step 1: Login and save state
playwright-cli open https://app.example.com/login
playwright-cli snapshot
playwright-cli fill e1 "user@example.com"
playwright-cli fill e2 "password123"
playwright-cli click e3
# Save the authenticated state
playwright-cli state-save auth.json
# Step 2: Later, restore state and skip login
playwright-cli state-load auth.json
playwright-cli open https://app.example.com/dashboard
# Already logged in!Save and Restore Roundtrip
# Set up authentication state
playwright-cli open https://example.com
playwright-cli eval "() => { document.cookie = 'session=abc123'; localStorage.setItem('user', 'john'); }"
# Save state to file
playwright-cli state-save my-session.json
# ... later, in a new session ...
# Restore state
playwright-cli state-load my-session.json
playwright-cli open https://example.com
# Cookies and localStorage are restored!Security Notes
- Never commit storage state files containing auth tokens
- Add
*.auth-state.jsonto.gitignore - Delete state files after automation completes
- Use environment variables for sensitive data
- By default, sessions run in-memory mode which is safer for sensitive operations
Test Generation
Generate Playwright test code automatically as you interact with the browser.
How It Works
Every action you perform with playwright-cli generates corresponding Playwright TypeScript code. This code appears in the output and can be copied directly into your test files.
Example Workflow
# Start a session
playwright-cli open https://example.com/login
# Take a snapshot to see elements
playwright-cli snapshot
# Output shows: e1 [textbox "Email"], e2 [textbox "Password"], e3 [button "Sign In"]
# Fill form fields - generates code automatically
playwright-cli fill e1 "user@example.com"
# Ran Playwright code:
# await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
playwright-cli fill e2 "password123"
# Ran Playwright code:
# await page.getByRole('textbox', { name: 'Password' }).fill('password123');
playwright-cli click e3
# Ran Playwright code:
# await page.getByRole('button', { name: 'Sign In' }).click();Building a Test File
Collect the generated code into a Playwright test:
import { test, expect } from '@playwright/test';
test('login flow', async ({ page }) => {
// Generated code from playwright-cli session:
await page.goto('https://example.com/login');
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
await page.getByRole('textbox', { name: 'Password' }).fill('password123');
await page.getByRole('button', { name: 'Sign In' }).click();
// Add assertions
await expect(page).toHaveURL(/.*dashboard/);
});Best Practices
1. Use Semantic Locators
The generated code uses role-based locators when possible, which are more resilient:
// Generated (good - semantic)
await page.getByRole('button', { name: 'Submit' }).click();
// Avoid (fragile - CSS selectors)
await page.locator('#submit-btn').click();2. Explore Before Recording
Take snapshots to understand the page structure before recording actions:
playwright-cli open https://example.com
playwright-cli snapshot
# Review the element structure
playwright-cli click e53. Add Assertions Manually
Generated code captures actions but not assertions. Add expectations in your test:
// Generated action
await page.getByRole('button', { name: 'Submit' }).click();
// Manual assertion
await expect(page.getByText('Success')).toBeVisible();Tracing
Capture detailed execution traces for debugging and analysis. Traces include DOM snapshots, screenshots, network activity, and console logs.
Table of Contents
- Basic Usage
- Trace Output Files
- What Traces Capture
- Use Cases
- Trace vs Video vs Screenshot
- Best Practices
- Limitations
Basic Usage
# Start trace recording
playwright-cli tracing-start
# Perform actions
playwright-cli open https://example.com
playwright-cli click e1
playwright-cli fill e2 "test"
# Stop trace recording
playwright-cli tracing-stopTrace Output Files
When you start tracing, Playwright creates a traces/ directory with several files:
trace-{timestamp}.trace
Action log - The main trace file containing:
- Every action performed (clicks, fills, navigations)
- DOM snapshots before and after each action
- Screenshots at each step
- Timing information
- Console messages
- Source locations
trace-{timestamp}.network
Network log - Complete network activity:
- All HTTP requests and responses
- Request headers and bodies
- Response headers and bodies
- Timing (DNS, connect, TLS, TTFB, download)
- Resource sizes
- Failed requests and errors
resources/
Resources directory - Cached resources:
- Images, fonts, stylesheets, scripts
- Response bodies for replay
- Assets needed to reconstruct page state
What Traces Capture
| Category | Details |
|---|---|
| Actions | Clicks, fills, hovers, keyboard input, navigations |
| DOM | Full DOM snapshot before/after each action |
| Screenshots | Visual state at each step |
| Network | All requests, responses, headers, bodies, timing |
| Console | All console.log, warn, error messages |
| Timing | Precise timing for each operation |
Use Cases
Debugging Failed Actions
playwright-cli tracing-start
playwright-cli open https://app.example.com
# This click fails - why?
playwright-cli click e5
playwright-cli tracing-stop
# Open trace to see DOM state when click was attemptedAnalyzing Performance
playwright-cli tracing-start
playwright-cli open https://slow-site.com
playwright-cli tracing-stop
# View network waterfall to identify slow resourcesCapturing Evidence
# Record a complete user flow for documentation
playwright-cli tracing-start
playwright-cli open https://app.example.com/checkout
playwright-cli fill e1 "4111111111111111"
playwright-cli fill e2 "12/25"
playwright-cli fill e3 "123"
playwright-cli click e4
playwright-cli tracing-stop
# Trace shows exact sequence of eventsTrace vs Video vs Screenshot
| Feature | Trace | Video | Screenshot |
|---|---|---|---|
| Format | .trace file | .webm video | .png/.jpeg image |
| DOM inspection | Yes | No | No |
| Network details | Yes | No | No |
| Step-by-step replay | Yes | Continuous | Single frame |
| File size | Medium | Large | Small |
| Best for | Debugging | Demos | Quick capture |
Best Practices
1. Start Tracing Before the Problem
# Trace the entire flow, not just the failing step
playwright-cli tracing-start
playwright-cli open https://example.com
# ... all steps leading to the issue ...
playwright-cli tracing-stop2. Clean Up Old Traces
Traces can consume significant disk space:
# Remove traces older than 7 days
find .playwright-cli/traces -mtime +7 -deleteLimitations
- Traces add overhead to automation
- Large traces can consume significant disk space
- Some dynamic content may not replay perfectly
Video Recording
Capture browser automation sessions as video for debugging, documentation, or verification. Produces WebM (VP8/VP9 codec).
Basic Recording
# Start recording
playwright-cli video-start
# Perform actions
playwright-cli open https://example.com
playwright-cli snapshot
playwright-cli click e1
playwright-cli fill e2 "test input"
# Stop and save
playwright-cli video-stop demo.webmBest Practices
1. Use Descriptive Filenames
# Include context in filename
playwright-cli video-stop recordings/login-flow-2024-01-15.webm
playwright-cli video-stop recordings/checkout-test-run-42.webmTracing vs Video
| Feature | Video | Tracing |
|---|---|---|
| Output | WebM file | Trace file (viewable in Trace Viewer) |
| Shows | Visual recording | DOM snapshots, network, console, actions |
| Use case | Demos, documentation | Debugging, analysis |
| Size | Larger | Smaller |
Limitations
- Recording adds slight overhead to automation
- Large recordings can consume significant disk space
Playwright CLI Troubleshooting
Common issues and solutions when using Playwright CLI.
---
1. Element Not Found / Invalid Reference
Symptoms:
Error: element not found for ref "e12"- Click or fill does nothing
Invalid referror message
Causes:
- No
snapshotwas run before interacting - Refs are stale — the page changed since the last snapshot
- Using a ref from a different tab or session
Solutions:
# Always snapshot first to get current refs
playwright-cli snapshot
# After any navigation, re-snapshot to refresh refs
playwright-cli goto https://myapp.com/page2
playwright-cli snapshot
# After clicking a link that navigates, re-snapshot
playwright-cli click e5
playwright-cli snapshotRule of thumb: Run snapshot before every interaction sequence, and again after any action that changes the page.
---
2. Session Stuck / Browser Not Responding
Symptoms:
- Commands hang indefinitely
- Browser window frozen (headed mode)
Error: session not foundafter a crash
Causes:
- Previous session crashed without cleanup
- Browser process orphaned
- Network timeout during page load
Solutions:
# List active sessions to diagnose
playwright-cli list
# Gracefully close all sessions
playwright-cli close-all
# Force-kill all sessions if close-all hangs
playwright-cli kill-all
# Start fresh
playwright-cli open https://myapp.com---
3. Timeout Errors
Symptoms:
Error: timeout 5000ms exceededNavigation timeout of 60000ms exceeded- Actions fail on slow-loading pages
Causes:
- Default
actionTimeout(5s) too short for complex interactions - Default
navigationTimeout(60s) too short for heavy pages - Page waiting for resources that never load
Solutions:
Create or update .playwright/cli.config.json in the project:
{
"timeouts": {
"action": 15000,
"navigation": 120000
}
}For one-off overrides, use environment variables:
PLAYWRIGHT_MCP_ACTION_TIMEOUT=15000 playwright-cli click e5If the page loads partially, try interacting with what is available rather than waiting for full load.
---
4. Browser Not Installed
Symptoms:
Error: browser not foundplaywright-cli: command not foundCannot find module @playwright/cli
Causes:
- Playwright CLI not installed
- Browser binaries not downloaded
- Node.js version too old (requires 18+)
Solutions:
# Install the CLI globally
npm install -g @playwright/cli@latest
# Verify installation
playwright-cli --help
# Check Node.js version (must be 18+)
node --version---
5. Headless vs Headed Confusion
Symptoms:
- Browser window appears unexpectedly (or fails to appear)
- Config file settings seem ignored
- Different behavior in CI vs local development
Causes:
.playwright/cli.config.jsonhas"browser.launchOptions.headless": falsebut--headedflag is expected- Environment variable overrides config file
- CI environment forces headless regardless
Resolution order (highest priority first): 1. Command-line flag: --headed 2. Environment variable: PLAYWRIGHT_MCP_HEADLESS=false 3. Config file: .playwright/cli.config.json → "browser.launchOptions.headless": false 4. Default: headless (no visible window)
# Force headed mode regardless of config
playwright-cli open https://myapp.com --headed
# Force headless via environment variable
PLAYWRIGHT_MCP_HEADLESS=true playwright-cli open https://myapp.com---
6. Commands Fail Silently or Return Empty Output
Symptoms:
snapshotreturns minimal or empty contentscreenshotproduces a blank imageclicksucceeds but nothing happens visually
Causes:
- Page JavaScript has not finished executing
- Page redirected and content is on a different URL
- Element is present in DOM but not visible or interactive
Solutions:
# After opening a page, snapshot to confirm content loaded
playwright-cli open https://myapp.com
playwright-cli snapshot
# If snapshot shows minimal content, the page may still be loading
# Take a screenshot to visually inspect what the browser sees
playwright-cli screenshot --filename=.playwright-cli/debug-check.png
# For single-page apps, wait briefly then re-snapshot
# (the app may need time to hydrate)
playwright-cli snapshotIf an element appears in the snapshot but interactions fail, it may be obscured by an overlay, modal, or loading spinner. Snapshot again to check for overlapping elements.
---
Quick Reference
| Problem | First Step |
|---|---|
| Invalid ref | Run playwright-cli snapshot |
| Stale ref after navigation | Run playwright-cli snapshot again |
| Session stuck | Run playwright-cli kill-all |
| Timeout error | Increase timeouts in .playwright/cli.config.json |
| CLI not found | Run npm install -g @playwright/cli@latest |
| No visible browser | Add --headed flag |
| Empty snapshot | Wait, then snapshot again |