playwriter session new --browser cloud. Supports residential proxies (--proxy us, --proxy de), custom proxies (--custom-proxy host:port), and configurable timeouts (--timeout 120). Idle sessions auto-disconnect after 10 minutes.1234playwriter cloud login # authenticate via device flow playwriter cloud status # list active cloud VMs playwriter cloud subscribe # open subscription page playwriter cloud live # open live browser view
12playwriter browser install # download Chrome for Testing playwriter session new --browser headless # launch headless Chrome
12export PLAYWRITER_API_KEY=pw_xxxxx playwriter session new --browser cloud
playwriter cloud login — uses Better Auth's current device authorization endpoints.PLAYWRITER_AUTO_ENABLE=false to disable.sinceLastCall option for getLatestLogs() — inspect browser logs after every action without seeing duplicate messages:1playwriter -s 1 -e 'console.log(await getLatestLogs({ page, sinceLastCall: true }))'
sinceLastCall read. Logs also persist across navigations, so hydration errors, redirect failures, and startup exceptions are not lost when the page changes.~/.playwriter/cdp.jsonl is capped at 10,000 entries by default to prevent unbounded disk growth. Set PLAYWRITER_CDP_LOG_MAX_ENTRIES to tune the cap. Rotation keeps the newest half of the log and writes through an atomic temp-file rename to avoid corrupting the JSONL file.getLatestLogs({ page }) results — page runtime errors and console messages emitted by related frame targets now appear in the returned log stream. This makes React and hydration failures visible through pageerror entries instead of requiring manual console listeners.playwriter session new can auto-create an initial extension tab even when the shared relay was originally started by MCP. This avoids No Playwright pages are available after all enabled tabs have closed./extensions/status and /extension/status requests now include the configured auth token, so remote relays using --token no longer reject status checks with 403 responses.19988 as a clean handoff instead of surfacing EADDRINUSE.playwriter session new — browser lists now use full user-agent client hints when available, so Chromium-family browsers such as Chrome Canary can show a more specific name.getLatestLogs() for page diagnostics — the generated Playwriter skill now tells agents to call getLatestLogs({ page }) instead of adding manual console listeners that miss errors emitted before listener setup.src/components/Button.tsx:42) to your clipboard. Uses bippy to walk the React fiber tree.globalThis.playwriterPinnedElemN and copy the reference to clipboard. Shared pin counter between toolbar and context menu.playwriter -e 'inspectPinnedElement(...)' with React component inspection when supported. Bash-safe single-quote wrapping handles any page content.Page.addScriptToEvaluateOnNewDocument. Auto-hides after 5s of inactivity. Press feedback uses a dedicated 140ms ease-out, independent of move duration. Scale and transform-origin tuned per Emil Kowalski design principles.cmd+click workarounds.installId persisted in chrome.storage.local prevents relay takeover when multiple Chromium-family browsers connect.params.sessionId fallback instead of throwing.welcome.html on install.-f/--file flag — execute JavaScript from a file instead of inline -e strings:1playwriter -s 1 -f script.js
-e with all context variables (state, page, context, etc.) available. -e and -f are mutually exclusive.getReactComponentInfo({ locator }) to get the nearest React component name, parent hierarchy, sanitized props, and source file locations. Non-React elements return null.performance-profiling.md resource covering TTFB, FCP, LCP, CLS measurement, heavy request detection, and interactivity blockers with concrete Playwriter + CDP snippets.playwriter now supports shell completions via goke for tab completion on commands and flags./cli/*, /recording/*, and /mcp-log let any request from 127.0.0.1 skip auth. Under tunnel setups (traforo/ngrok/cloudflared), every public request arrives from localhost, making the bypass equivalent to no auth. Fixed.--token works on every remote subcommand — session new, session list, session delete, session reset, and browser list all forward Authorization: Bearer … to the relay. Previously only playwriter -e sent the token. Thanks @ivanleomk for the original fix.POST /mcp-log is now token-protected — previously open to any reachable client./(app-pages-browser)/, /(ssr)/, /(rsc)/ and other webpack layer prefixes are now stripped correctly.page.screenshot({ path }), page.pdf({ path }), etc. must use absolute paths since Playwright resolves them outside the sandboxed fs.playwriter -e '…' code needed to inspect that element later, so pasted prompts are immediately useful to an agent instead of just exposing a fragile DOM handle.connectOverCDP() clients auto-close the same alert()/confirm()/prompt(), duplicate best-effort closes are now ignored instead of surfacing an unhandled rejection that kills the process.window.open or target="_blank", the extension moves it into the source window as a regular tab and auto-attaches it. Agents no longer need the cmd+click workaround for OAuth flows.[WARNING] New page opened from current page (index N, initial url: ...) pointing agents at the new tab. The old Popup window detected ... cannot be controlled by playwriter warning is gone.0.0.80, the CLI and MCP warn the user to update via chrome://extensions. The warning is also surfaced in the MCP agent's warning stream.browser:Chromium relay key, causing them to replace each other's WebSocket connection. The extension now persists a per-install ID in chrome.storage.local and uses it as a stable fallback key.activeTargets === 0, which is briefly true right after a fresh replacement connects, causing the old worker to steal the slot back and drop the active Playwright tab.await page.goto(url) and similar single-expression code no longer prints anything when the return value is a Playwright handle (Response, Page, Browser, Request, Frame, etc.). These are programmatic references, not display data. The previous behavior also leaked every process.env variable (API keys, tokens, credentials) via util.inspect at depth 4.console.log:123return response.url() // prints the URL return response.status() // prints 200 console.log(response) // prints safe summary
console.log(response) now renders a clean summary (via @xmorse/playwright-core@1.59.7) — no env var dump, no 400K+ output:1Response@response@abc123 { url: 'https://...', status: 200, statusText: 'OK', headers: [...] }
--direct) — connect to Chrome's built-in debugging WebSocket without needing the Playwriter extension. Works with any Chromium-based browser (Chrome, Brave, Ghost Browser, Arc, Edge, etc.) that has debugging enabled via chrome://inspect/#remote-debugging or --remote-debugging-port. Auto-discovers instances via DevToolsActivePort files and port scanning. For MCP, set PLAYWRITER_DIRECT=1 env var.12playwriter session new --direct playwriter browser list
browser.contexts() gives access to pages across all open Chrome profiles.playwriter browser start (experimental) — launched a managed Chrome instance with the bundled Playwriter extension preloaded, useful for fresh VPS/AVPS setups. Now deprecated in favor of session new --direct. The command still works but is hidden from --help.AGENT_GRAPHICS=kitty is set, the CLI emits screenshots and resized images as Kitty Graphics Protocol escape sequences. Agents with kitty-graphics-agent automatically extract images and pass them to the LLM as media parts.1AGENT_GRAPHICS=kitty playwriter -s 1 -e "await screenshot({ page })"
screenshotWithAccessibilityLabels() and resizeImageForAgent() now consistently output PNG instead of JPEG, fixing image/png vs image/jpeg mismatch errors in MCP clients.resizeImageForAgent — renamed from resizeImage. Resized images are now automatically collected and included in responses. The old name still works as a backward-compatible alias.--direct auto-discovery now detects Chrome instances where /json/version returns 404 (Chrome 136+ with chrome://inspect debugging). Uses HTTP-only probing and never triggers Chrome's approval dialog.playwriter session list — session table now includes the working directory, making it easier to tell similar sessions apart.fs paths in the sandbox now resolve from the cwd captured by session new.contenteditable elements are now correctly detected as interactive textboxes in accessibility snapshots.PLAYWRITER_DIRECT only accepts '1' — removed 'auto' and 'true' aliases. Explicit ws:// endpoints still work.Page.download* and Browser.download* event paths, so flows like page.waitForEvent('download') work consistently through the relay.onMouseAction callbacks so both page.mouse.* and locator.click() are capturedcreateDemoVideo() automatically detects and speeds up idle sections between interactions, with hardware encoder detection (h264_videotoolbox, etc.) and optimized FFmpeg output for social mediaresizeImage() sandbox utility — shrink screenshots before feeding them to LLMs; default mode fits within 1568×1568px, supports explicit width/height/maxDimensionlocator.click() times out, the error now explains why ("Element is not visible", "Element is not stable", etc.) instead of a generic timeout message[WARNING] when popup windows open during execution so agents are aware of context changesrecording and ghostCursor namespaces — cleaner API in the execute sandbox: recording.start/stop/isRecording/cancel and ghostCursor.show/hide, with backward-compatible top-level aliasesshowDiffSinceLastCall cache now isolated per locator scope; also skipped automatically when search is providedpage.onMouseAction callback in Playwright fork — fires for both page.mouse.* and locator.click() actions; Locator.selector() now publicly typed (@xmorse/playwright-core@1.59.6)/cli/* and /recording/* that blocks cross-origin browser requests via Sec-Fetch-Site header validation, rejects POST requests without Content-Type: application/json (prevents the CORS preflight bypass via text/plain), and enforces token authentication when token mode is enabled. Previously, CORS alone was relied upon, but CORS only blocks reading responses — it does not prevent "simple" POST requests from executing side effects like /cli/execute.--token is set (remote access mode), /cli/* and /recording/* routes now require Authorization: Bearer <token> or ?token=<token>, matching the behavior already documented in remote-access.md.PLAYWRITER_HOST now accepts full URLs (e.g., https://x-tunnel.traforo.dev) in addition to plain hostnames, enabling secure remote browser access through tunnels like traforowss:// protocol when connecting to HTTPS relay hostsparseRelayHost() utility handles URL/hostname detection and returns correct HTTP/WebSocket base URLslsof -t for PID discovery and process.kill() for termination. This eliminates spawn overhead and makes the code more maintainable while improving reliability.bunx playwriter@latest relay restarts by replacing kill-port-process with a vendored cross-platform port killer.killPortProcess({ port }) on Windows, macOS, and Linux.kill-port-process dependency and its transitive process-management packages from the lockfile.sessionId when targeting OOPIF child sessions instead of always using the tab root session. This fixes missing Runtime.executionContextCreated events for child iframe targets, which could cause iframe locator operations to hang.Frame objects and Runtime.enable routing~/.playwriter/cdp.jsonl/tmp/playwriter to ~/.playwriter so each OS user gets their own directory. Fixes startup crash when /tmp/playwriter is owned by another user (#44).Target.setAutoAttach with waitForDebuggerOnStart: true requires calling Runtime.runIfWaitingForDebugger even on targets we filter out, otherwise they hang forever./tmp/playwriter/cdp.jsonl) for debugging. Log all CDP messages with direction, timestamp, and source info. Use jq to analyze.util.inspect for cleaner log output with proper object formattingplaywriter skill CLI command: New command that prints full MCP instructions to stdout, useful for agents that need up-to-date documentation without relying on MCP resourcessrc/skill.mdrefFilter parameter for getAriaSnapshot: New optional filter to include only specific refs by role/name, reducing unnecessary ref lookups__filename.endsWith('.ts') instead of env var, fixing tsx and vite-node execution/extension/status endpoint now returns activeTargets count, allowing extensions to know when the slot becomes available (no active tabs).accessibilitySnapshot now supports format option ('yaml' or 'markdown') with deduplication of interactive refsplaywriter sessions list, playwriter sessions kill)-e/--eval CLI flag for quick code execution from command linePLAYWRITER_AUTO_ENABLE when starting relay serverprompt.md from SKILL.mdaria-snapshot.ts with dedicated accessibility snapshot functionsReadableStream never receives it. Now Network.enable defaults to maxTotalBufferSize: 0 to disable buffering.Network.disable + Network.enable with explicit buffer sizes when they need response.body()127.0.0.1 instead of localhost to avoid DNS/IPv6 resolution issues, add 15s global timeout wrapper around connect() to prevent hanging forevergetCurrentPage() and prompt guidance to use domcontentloaded instead of load for faster, more reliable page detectionwsUrl parameter now defaults to getCdpUrl() if not providedexecutionContextCreated events and errors on Target.detachFromTarget.accessibilitySnapshot, getCleanHTML, and getLatestLogs now include 5 lines of context above and below each search match---getCleanHTML utility: New function to get cleaned HTML from a locator or pagesearch option to filter results (returns first 10 matching lines)showDiffSinceLastCall to see changes since last snapshotincludeStyles to optionally keep style/class attributesaccessibilitySnapshot search: Removed contextLines parameter, search now returns just matching lines instead of context around matches. Use .split('\n').slice() for pagination instead.toWellFormed() to remove unpaired Unicode surrogates that break JSON encoding for Claude API (requires Node.js 20+ for sanitization, gracefully degrades on older versions)innerWidth/innerHeight) with scale: 'css' to match visual appearancescreenshotWithAccessibilityLabels: New utility function that takes a screenshot with Vimium-style visual labels overlaid on interactive elementspage.locator('aria-ref=e5')img, video, audio to INTERACTIVE_ROLESmaintainLoop now ensures tabs transition to 'connecting' state when WebSocket is not connected, fixing edge cases where handleClose wasn't called