Execute Playwright code in a session using the -e flag:
playwriter -s <sessionId> -e "<code>"
Required flags
Session ID (get one with playwriter session new). The session’s state object persists across commands.
JavaScript code to execute in the browser context
Optional flags
Execution timeout in milliseconds
Remote relay server host (overrides PLAYWRITER_HOST)
Authentication token (overrides PLAYWRITER_TOKEN)
Basic examples
Navigate to a page
playwriter -s 1 -e 'state.page = await context.newPage(); await state.page.goto("https://example.com")'
playwriter -s 1 -e 'await state.page.click("button")'
Get page title
playwriter -s 1 -e 'await state.page.title()'
Take a screenshot
playwriter -s 1 -e 'await state.page.screenshot({ path: "screenshot.png", scale: "css" })'
Get accessibility snapshot
playwriter -s 1 -e 'await snapshot({ page: state.page })'
Quoting rules
Always use single quotes for -e to prevent bash from interpreting special characters:
# GOOD: Single quotes protect $, backticks, and backslashes
playwriter -s 1 -e 'const price = text.match(/\$[\d.]+/)'
playwriter -s 1 -e 'await state.page.locator(`[id="_r_a_"]`).click()'
# BAD: Double quotes - bash interprets $ and backticks
playwriter -s 1 -e "const price = text.match(/\$[\d.]+/)" # BREAKS
Use double quotes for strings inside JavaScript:
playwriter -s 1 -e 'await state.page.goto("https://example.com")'
Multiline code
Heredoc (recommended)
Best for multiline code with complex quoting:
playwriter -s 1 -e "$(cat <<'EOF'
const links = await state.page.$$eval('a', els => els.map(e => e.href));
console.log('Found', links.length, 'links');
const price = text.match(/\$[\d.]+/);
EOF
)"
The quoted 'EOF' delimiter disables all bash expansion. Any character works inside, including $, backticks, and single quotes.
$’…’ syntax
Alternative for multiline, but beware of escape sequences:
playwriter -s 1 -e $'
const title = await state.page.title();
const url = state.page.url();
console.log({ title, url });
'
With $'...' syntax, \n, \t, and \\ become special characters. This conflicts with JavaScript regex patterns. Use heredoc instead for regex-heavy code.
Quoting summary
| Syntax | Bash expansion | Use case |
|---|
'...' | None | One-liners (best for simple code) |
<<'EOF' | None | Multiline code (best for complex code) |
$'...' | \n, \t, \' only | Multiline when you need escape sequences |
"..." | Full | ❌ Never use for JavaScript code |
Timeout option
Default timeout is 10 seconds. Increase for long-running operations:
# Wait up to 30 seconds
playwriter -s 1 --timeout 30000 -e 'await state.page.waitForSelector(".slow-element")'
# Video processing needs longer timeout
playwriter -s 1 --timeout 120000 -e 'await createDemoVideo({ recordingPath, durationMs, executionTimestamps })'
Available variables
All execute calls have access to:
Object persisted between calls within your session. Each session has its own isolated state. Use to store pages, data, listeners.
A default page (may be shared with other agents). Prefer creating your own page and storing it in state.
Browser context. Access all pages via context.pages().
Load Node.js modules (e.g., const fs = require('node:fs')). ESM import is not available.
Node.js globals are also available: setTimeout, setInterval, fetch, URL, Buffer, crypto, etc.
Output and errors
The command prints the result to stdout:
$ playwriter -s 1 -e 'await state.page.title()'
Example Domain
$ playwriter -s 1 -e 'console.log("Hello"); 2 + 2'
Hello
4
Errors print to stderr and exit with code 1:
$ playwriter -s 1 -e 'await state.page.click(".missing")'
Error: Timeout 10000ms exceeded.
Advanced examples
Store network requests
playwriter -s 1 -e "$(cat <<'EOF'
state.requests = [];
state.page.on('request', req => {
if (req.url().includes('/api/')) {
state.requests.push({ url: req.url(), method: req.method() });
}
});
EOF
)"
Load file content
playwriter -s 1 -e "$(cat <<'EOF'
const fs = require('node:fs');
const content = fs.readFileSync('./data.txt', 'utf-8');
await state.page.locator('textarea').fill(content);
EOF
)"
playwriter -s 1 -e "$(cat <<'EOF'
const data = await state.page.evaluate(() => {
return Array.from(document.querySelectorAll('.item')).map(el => ({
title: el.querySelector('h2')?.textContent,
price: el.querySelector('.price')?.textContent
}));
});
console.log(JSON.stringify(data, null, 2));
EOF
)"
Work with iframes
playwriter -s 1 -e "$(cat <<'EOF'
const frame = await state.page.locator('iframe').contentFrame();
await snapshot({ frame });
EOF
)"
Environment variables
Default session ID (can be overridden with -s)
Default relay server host (can be overridden with --host)
Authentication token for remote relay servers (can be overridden with --token)
Troubleshooting
“Error: -s/—session is required”
Create a session first:
Then use the session ID with -s.
“Warning: Extension not connected”
Click the Playwriter extension icon on any tab. The icon turns green when connected.
Timeout errors
Increase the timeout:
playwriter -s 1 --timeout 30000 -e '...'
“Error: Cannot connect to relay server”
The relay server should start automatically. Check logs: