💡 Summary
Playwriter enables browser automation using the Playwright API with an extension and CLI.
🎯 Target Audience
🤖 AI Roast: “Powerful, but the setup might scare off the impatient.”
Risk: High. Review: shell/CLI command execution; outbound network access (SSRF, data egress); API keys/tokens handling and storage; filesystem read/write scope and path traversal; dependency pinning and supply-chain risk. Run with least privilege and audit before enabling in production.
Installation
-
Install Extension from Chrome Web Store
-
Click extension icon on a tab → turns green when connected
-
Install the CLI and start automating the browser:
npm i -g playwriter playwriter -s 1 -e "await page.goto('https://example.com')" -
Add skill to your agent:
npx -y skills add remorses/playwriter
Quick Start
playwriter session new # creates stateful sandbox, outputs session id (e.g. 1) playwriter -s 1 -e "await page.goto('https://example.com')" playwriter -s 1 -e "console.log(await accessibilitySnapshot({ page }))" playwriter -s 1 -e "await page.locator('aria-ref=e5').click()"
CLI Usage
Each session has isolated state. Browser tabs are shared across sessions.
# Session management playwriter session new # creates stateful sandbox, outputs id (e.g. 1) playwriter session list # show sessions + state keys playwriter session reset <id> # fix connection issues # Execute (always use -s) playwriter -s 1 -e "await page.goto('https://example.com')" playwriter -s 1 -e "await page.click('button')" playwriter -s 1 -e "console.log(await page.title())"
Create your own page to avoid interference from other agents:
playwriter -s 1 -e "state.myPage = await context.newPage(); await state.myPage.goto('https://example.com')"
Multiline:
playwriter -s 1 -e $' const title = await page.title(); console.log({ title, url: page.url() }); '
Examples
Variables in scope: page, context, state (persists between calls), require, and Node.js globals.
Persist data in state:
playwriter -e "state.users = await page.$$eval('.user', els => els.map(e => e.textContent))" playwriter -e "console.log(state.users)"
Intercept network requests:
playwriter -e "state.requests = []; page.on('response', r => { if (r.url().includes('/api/')) state.requests.push(r.url()) })" playwriter -e "await Promise.all([page.waitForResponse(r => r.url().includes('/api/')), page.click('button')])" playwriter -e "console.log(state.requests)"
Set breakpoints and debug:
playwriter -e "state.cdp = await getCDPSession({ page }); state.dbg = createDebugger({ cdp: state.cdp }); await state.dbg.enable()" playwriter -e "state.scripts = await state.dbg.listScripts({ search: 'app' }); console.log(state.scripts.map(s => s.url))" playwriter -e "await state.dbg.setBreakpoint({ file: state.scripts[0].url, line: 42 })"
Live edit page code:
playwriter -e "state.cdp = await getCDPSession({ page }); state.editor = createEditor({ cdp: state.cdp }); await state.editor.enable()" playwriter -e "await state.editor.edit({ url: 'https://example.com/app.js', oldString: 'const DEBUG = false', newString: 'const DEBUG = true' })"
Screenshot with labels:
playwriter -e "await screenshotWithAccessibilityLabels({ page })"
MCP Setup
Using the CLI with the skill (step 4 above) is the recommended approach. For direct MCP server configuration, see MCP.md.
Visual Labels
Vimium-style labels for AI agents to identify elements:
await screenshotWithAccessibilityLabels({ page }) // Returns screenshot + accessibility snapshot with aria-ref selectors await page.locator('aria-ref=e5').click()
Color-coded: yellow=links, orange=buttons, coral=inputs, pink=checkboxes, peach=sliders, salmon=menus, amber=tabs.
Comparison
vs Playwright MCP
| | Playwright MCP | Playwriter | |---|---|---| | Browser | Spawns new Chrome | Uses your Chrome | | Extensions | None | Your existing ones | | Login state | Fresh | Already logged in | | Bot detection | Always detected | Can bypass (disconnect extension) | | Collaboration | Separate window | Same browser as user |
vs BrowserMCP
| | BrowserMCP | Playwriter |
|---|---|---|
| Tools | 12+ dedicated tools | 1 execute tool |
| API | Limited actions | Full Playwright |
| Context usage | High (tool schemas) | Low |
| LLM knowledge | Must learn tools | Already knows Playwright |
vs Antigravity (Jetski)
| | Jetski | Playwriter | |---|---|---| | Tools | 17+ tools | 1 tool | | Subagent | Spawns for each browser task | Direct execution | | Latency | High (agent overhead) | Low |
vs Claude Browser Extension
| | Claude Extension | Playwriter | |---|---|---| | Agent support | Claude only | Any MCP client | | Windows WSL | No | Yes | | Context method | Screenshots (100KB+) | A11y snapshots (5-20KB) | | Playwright API | No | Full | | Debugger/breakpoints | No | Yes | | Live code editing | No | Yes | | Network interception | Limited | Full | | Raw CDP access | No | Yes |
Architecture
+---------------------+ +-------------------+ +-----------------+
| BROWSER | | LOCALHOST | | MCP CLIENT |
| | | | | |
| +---------------+ | | WebSocket Server | | +-----------+ |
| | Extension |<---------> :19988 | | | AI Agent | |
| +-------+-------+ | WS | | | +-----------+ |
| | | | /extension | | | |
| chrome.debugger | | | | | v |
| v | | v | | +-----------+ |
| +---------------+ | | /cdp/:id <--------------> | execute | |
| | Tab 1 (green) | | +-------------------+ WS | +-----------+ |
| | Tab 2 (green) | | | | |
| | Tab 3 (gray) | | Tab 3 not controlled | Playwright API |
+---------------------+ (no extension click) +-----------------+
Remote CLI
Run CLI from a different machine (devcontainer, VM, SSH) while Chrome runs on your host.
On host:
playwriter serve --token <secret>
From remote:
playwriter --host 192.168.1.10 --token <secret> session new playwriter --host 192.168.1.10 --token <secret> -s 1 -e "await page.goto('https://example.com')"
Or with env vars:
export PLAYWRITER_HOST=192.168.1.10 export PLAYWRITER_TOKEN=<secret> playwriter -s 1 -e "await page.goto('https://example.com')"
Security
- Local only: WebSocket server on
localhost:19988 - Origin validation: Only our extension IDs allowed (browsers can't spoof Origin)
- Explicit consent: Only tabs where you clicked the extension icon
- Visible automation: Chrome shows automation banner on controlled tabs
- No remote access: Malicious websites cannot connect
Playwright API
Connect programmatically (without CLI):
import { chromium } from 'playwright-core' import { startPlayWriterCDPRelayServer, getCdpUrl } from 'playwriter' const server = await startPlayWriterCDPRelayServer() const browser = await chromium.connectOverCDP(getCdpUrl()) const page = browser.contexts()[0].pages()[0] await page.goto('https://example.com') await page.screenshot({ path: 'screenshot.png' }) // Don't call browser.close() - it closes the user's Chrome server.close()
Or connect to a running server:
npx -y playwriter serve --host 127.0.0.1
const browser = await chromium.connectOverCDP('http://127.0.0.1:19988')
Troubleshooting
View relay server logs to debug issues:
playwriter logfile # prints the log file path # typically: /tmp/playwriter/relay-server.log (Linux/macOS)
The relay log contains extension, MCP and WebSocket server logs. A separate CDP JSONL log is also created alongside it (see playwriter logfile). Both are recreated on each server start.
Example: summarize CDP traffic counts by direction + method:
jq -r '.direction + "\t" + (.message.method // "response")' /tmp/playwriter/cdp.jsonl | uniq -c
Known Issues
- If all pages return
about:blank, restart Chrome (Chrome bug inchrome.debuggerAPI) - Browser may switch to light mode on connect (Playwright issue)
Pros
- Integrates seamlessly with Playwright
- Supports complex browser automation tasks
- Isolated session management for safety
- Extensive CLI commands for flexibility
Cons
- Requires installation of a browser extension
- May have a learning curve for new users
- Limited to local browser automation
- Potential issues with browser state management
Related Skills
pytorch
S“It's the Swiss Army knife of deep learning, but good luck figuring out which of the 47 installation methods is the one that won't break your system.”
agno
S“It promises to be the Kubernetes for agents, but let's see if developers have the patience to learn yet another orchestration layer.”
nuxt-skills
S“It's essentially a well-organized cheat sheet that turns your AI assistant into a Nuxt framework parrot.”
Disclaimer: This content is sourced from GitHub open source projects for display and rating purposes only.
Copyright belongs to the original author remorses.
