Persistent browser automation via Playwright daemon. Keep a browser window open and send it commands (navigate, execute JS, inspect console)...
Persistent browser daemon that keeps Chrome open and accepts commands via file-based IPC.
cd ~/.claude/skills/playwright-skill
node browser-daemon.js
Or ask: "Start the browser daemon in the background"
The browser window opens and stays open.
Use absolute paths (cleaner, no directory changes):
# Navigate
~/.claude/skills/playwright-skill/browser-client.js navigate "http://localhost:8080/..."
# Execute JavaScript
~/.claude/skills/playwright-skill/browser-client.js exec "document.title"
~/.claude/skills/playwright-skill/browser-client.js exec "document.querySelectorAll('div').length"
# Console logs
~/.claude/skills/playwright-skill/browser-client.js console
~/.claude/skills/playwright-skill/browser-client.js console-clear
# Status
~/.claude/skills/playwright-skill/browser-client.js status
# Resize viewport
~/.claude/skills/playwright-skill/browser-client.js resize 1920 1080
Both scripts have shebangs and are executable, so they can be called directly.
Claude (Bash tool)
↓
browser-client.js (writes .browser-command)
↓
browser-daemon.js (polls, executes, writes .browser-result)
↓
Chrome Browser (Playwright-controlled)
IPC Files:
.browser-command - Command input (JSON).browser-result - Command output (JSON).browser-ready - Ready signal (exists when daemon is running)Files created/deleted automatically during operation.
Navigate to URL and wait for page load.
node browser-client.js navigate "http://localhost:8080/page"
Returns: { success: true, url: string, title: string }
Execute JavaScript in browser context.
node browser-client.js exec "document.querySelectorAll('div').length"
Returns: { success: true, result: any }
Get all captured console logs.
node browser-client.js console
Returns: { success: true, logs: [{ type, text, location }] }
Clear console log buffer.
node browser-client.js console-clear
Returns: { success: true }
Check daemon status and current page info.
node browser-client.js status
Returns: { success: true, url, title, consoleLogsCount }
Resize browser viewport.
node browser-client.js resize 1920 1080
Returns: { success: true, width, height }
chromium.launch({
channel: 'chrome', // Use Google Chrome, not Chromium
headless: false, // Visible window
args: ['--start-maximized']
})
Manual window resizing does NOT work:
resize command instead: node browser-client.js resize 1024 768DevTools overlay:
window.innerWidth/HeightViewport vs Window:
window.innerWidth/Height - The viewport (controlled by Playwright)window.outerWidth/Height - The window sizeresize commandInteractive development: Keep browser open while testing changes, reload and check console without manual interaction.
Debugging console logs: Track down log sources with automatic source location capture.
Inspecting page state: Query DOM, check element counts, inspect computed styles via JavaScript execution.
Testing workflows: Automate multi-step browser interactions (navigate, fill forms, submit, check results).
Daemon not responding:
ls ~/.claude/skills/playwright-skill/.browser-ready
cd ~/.claude/skills/playwright-skill && node browser-daemon.js
Commands timing out:
rm -f .browser-command .browser-resultBrowser window closed:
node browser-daemon.jscd ~/.claude/skills/playwright-skill
npm install
This installs Playwright and downloads Chrome browser.
See META_COMMANDS.md for comprehensive reference of Playwright's meta-level capabilities beyond basic testing:
When user requests browser interaction:
.browser-ready file exists)browser-client.js commands to perform actionsUser can request additional features - the codebase is straightforward and well-documented for extensions.