> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
title: "Changelog"
description: "Release notes for Changelog."
mode: "center"
---

import _ChangelogIntro from './changelog/intro.mdx'

<Aside full>
  <Note>
    This changelog is generated automatically from the [GitHub releases](https://github.com/remorses/playwriter/releases) page.
  </Note>
</Aside>

import { ChangelogHeroSection } from '../components/hero-section.tsx'

<Above>
  <ChangelogHeroSection />
</Above>

<div className="h-6" />

What's new in Playwriter. All releases are published on [GitHub](https://github.com/remorses/playwriter/releases).

<Update id={"extension@0.0.97"} label={"Jun 25, 2026"}>
  ## Extension 0.0.97

  1. **10s timeout for CDP init commands** — frozen or hibernated tabs (common in Ghost Browser and other Chromium forks) no longer block the entire Playwright connection setup. Init commands like Page.enable, Runtime.enable, and Network.enable time out individually after 10 seconds.
  2. **Multi-profile relay routing** — extension connections are identified by per-profile install id, so two Chrome profiles signed into the same Google account no longer replace each other.
  3. **Better browser name detection** — shows more specific browser names using full user-agent client hints.
</Update>

<Update id={"playwriter@0.4.0"} label={"Jun 25, 2026"}>
  ## playwriter\@0.4.0

  1. **Cloud browser sessions via Browser Use** — spin up stealth Chromium VMs in the cloud with `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.

     New CLI commands:

     ```bash
     playwriter 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
     ```

  2. **Headless browser mode** — run without the extension or a visible browser:
     ```bash
     playwriter browser install                    # download Chrome for Testing
     playwriter session new --browser headless      # launch headless Chrome
     ```
     Multiple sessions share the same Chrome process with isolated contexts.

  3. **API key authentication for cloud browsers** — skip the interactive device flow in CI and headless environments:
     ```bash
     export PLAYWRITER_API_KEY=pw_xxxxx
     playwriter session new --browser cloud
     ```
     Create and revoke keys at [https://playwriter.dev/dashboard](https://playwriter.dev/dashboard).

  4. **Fixed relay routing across Chrome profiles** — two profiles signed into the same Google account no longer replace each other's relay connection.

  5. **Fixed cloud billing race conditions** — concurrent cloud session requests now use durable per-org slot claims.

  6. **Fixed `playwriter cloud login`** — uses Better Auth's current device authorization endpoints.

  Fixes [https://github.com/remorses/playwriter/issues/80](https://github.com/remorses/playwriter/issues/80)
</Update>

<Update id={"playwriter@0.3.1"} label={"Jun 13, 2026"}>
  ## playwriter\@0.3.1

  1. **Auto-page creation enabled by default** — MCP and CLI sessions now automatically create a blank Playwriter-enabled tab when no targets are available, so agents can start working immediately without manual tab setup. Set `PLAYWRITER_AUTO_ENABLE=false` to disable.
</Update>

<Update id={"playwriter@0.3.0"} label={"Jun 13, 2026"}>
  ## playwriter\@0.3.0

  1. **New `sinceLastCall` option for `getLatestLogs()`** — inspect browser logs after every action without seeing duplicate messages:
     ```bash
     playwriter -s 1 -e 'console.log(await getLatestLogs({ page, sinceLastCall: true }))'
     ```
     The first call returns all buffered console logs and page errors for the page. Later calls return only new entries since the previous `sinceLastCall` read. Logs also persist across navigations, so hydration errors, redirect failures, and startup exceptions are not lost when the page changes.
  2. **CDP logs now rotate automatically** — `~/.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.
  3. **More reliable `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.
  4. **CLI-created sessions auto-open pages more reliably** — `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.
  5. **Remote status checks send bearer tokens** — `/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.
  6. **Concurrent relay startup no longer crashes on port races** — simultaneous CLI and MCP commands now deduplicate startup work and treat a competing process winning port `19988` as a clean handoff instead of surfacing `EADDRINUSE`.
  7. **Clearer multi-browser names in `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.
  8. **Skill docs prefer `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.

  Fixes [https://github.com/remorses/playwriter/issues/75](https://github.com/remorses/playwriter/issues/75)
  Fixes [https://github.com/remorses/playwriter/issues/85](https://github.com/remorses/playwriter/issues/85)
  Fixes [https://github.com/remorses/playwriter/issues/92](https://github.com/remorses/playwriter/issues/92)
</Update>

<Update id={"extension@0.0.94"} label={"May 27, 2026"}>
  ## Extension 0.0.94

  1. **Copy React Component Source Path** right-click menu item. Right-click an element on a React page to copy the source file path (e.g. `src/components/Button.tsx:42`) to your clipboard. Uses bippy to walk the React fiber tree.

  2. **In-page floating toolbar** with pin element mode. A compact dark pill toolbar injected into tabs with Playwriter attached. Pin elements to assign them to `globalThis.playwriterPinnedElemN` and copy the reference to clipboard. Shared pin counter between toolbar and context menu.

  3. **Pinned element clipboard copies a shell-ready command**. Toolbar pins and context menu now copy `playwriter -e 'inspectPinnedElement(...)'` with React component inspection when supported. Bash-safe single-quote wrapping handles any page content.

  4. **Always-on ghost cursor** injected into every attached tab via `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.

  5. **Auto-relocate popup windows into tabs**. OAuth popups and similar windows opened by connected tabs are moved into the source tab's window automatically, so agents no longer need `cmd+click` workarounds.

  6. **Cross-browser relay identity**. Per-install `installId` persisted in `chrome.storage.local` prevents relay takeover when multiple Chromium-family browsers connect.

  7. **Fix debugger crash on pages with chrome-extension:// iframes** (LastPass, SurfingKeys, password managers). Restricted iframes are removed before attach, and restricted child targets are filtered from CDP events.

  8. **Fix Target.detachFromTarget routing on root CDP session**. Commands without a top-level sessionId now resolve via `params.sessionId` fallback instead of throwing.

  9. **Runtime-scoped root CDP tab session IDs** prevent collisions across multiple Chrome profiles.

  10. **Skip welcome tab in packaged automation builds**. The CLI-bundled extension no longer opens `welcome.html` on install.
</Update>

<Update id={"playwriter@0.2.0"} label={"May 19, 2026"}>
  ## playwriter\@0.2.0

  1. **New `-f/--file` flag** — execute JavaScript from a file instead of inline `-e` strings:
     ```bash
     playwriter -s 1 -f script.js
     ```
     The file runs in the same sandbox as `-e` with all context variables (`state`, `page`, `context`, etc.) available. `-e` and `-f` are mutually exclusive.

  2. **React component inspection for pinned elements** — call `getReactComponentInfo({ locator })` to get the nearest React component name, parent hierarchy, sanitized props, and source file locations. Non-React elements return `null`.

  3. **Performance profiling guide** — new `performance-profiling.md` resource covering TTFB, FCP, LCP, CLS measurement, heavy request detection, and interactivity blockers with concrete Playwriter + CDP snippets.

  4. **Shell tab completions** — `playwriter` now supports shell completions via goke for tab completion on commands and flags.

  5. **Security: token required on all requests regardless of source** — the previous loopback bypass on `/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.

  6. **`--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.

  7. **`POST /mcp-log` is now token-protected** — previously open to any reachable client.

  8. **Fixed Next.js webpack layer prefixes in React source paths** — `/(app-pages-browser)/`, `/(ssr)/`, `/(rsc)/` and other webpack layer prefixes are now stripped correctly.

  9. **Docs: absolute paths required for saved artifacts** — `page.screenshot({ path })`, `page.pdf({ path })`, etc. must use absolute paths since Playwright resolves them outside the sandboxed `fs`.
</Update>

<Update id={"playwriter@0.1.0"} label={"Apr 16, 2026"}>
  ## playwriter\@0.1.0

  1. **New in-page toolbar with pin mode (available when extension review completes)** — every attached tab now gets a floating toolbar you can use to pin elements directly from the page. Pinning copies a natural-language prompt plus the exact `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.
  2. **Always-on ghost cursor with better motion (available when extension review completes)** — the cursor overlay now appears on every Playwriter-attached tab, survives hard navigations, uses smoother move/press animation timing, and fades away after 5 seconds of idle time so manual browsing stays uncluttered. The next Playwright-driven mouse action brings it back instantly.
  3. **Shared JavaScript dialogs no longer crash multi-client sessions** — when multiple `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.
</Update>

<Update id={"playwriter@0.0.105"} label={"Apr 7, 2026"}>
  ## playwriter\@0.0.105

  1. **Popup windows auto-relocate to tabs** — when a connected page opens a popup via `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.

  2. **New page warning replaces unreachable popup warning** — the executor now emits `[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.

  3. **Minimum extension version enforcement** — if the installed extension is older than `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.

  4. **Fix multi-browser relay collisions** — Chromium-based browsers that don't have a signed-in Google account (Chromium, Vivaldi, Helium, Dia, etc.) previously all shared the same `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.

  5. **Fix extension takeover loop** — after being replaced by another instance, the extension's reconnect loop now waits until the replacement is fully gone before reclaiming the relay slot. Previously it checked `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.
</Update>

<Update id={"playwriter@0.0.103"} label={"Apr 5, 2026"}>
  ## playwriter\@0.0.103

  Fixes env var leak and noisy output when auto-returning Playwright objects from the CLI.

  1. **Auto-returned Playwright handles are now silently skipped** — `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.

     By default expression results are printed and that was the cause — now we don't print those objects which would also waste LLM context.

     To see data, explicitly return specific fields or use `console.log`:

     ```js
     return response.url()           // prints the URL
     return response.status()        // prints 200
     console.log(response)           // prints safe summary
     ```

  2. **`console.log(response)` now renders a clean summary** (via `@xmorse/playwright-core@1.59.7`) — no env var dump, no 400K+ output:
     ```
     Response@response@abc123 { url: 'https://...', status: 200, statusText: 'OK', headers: [...] }
     ```

  Fixes #82.
</Update>

<Update id={"playwriter@0.0.102"} label={"Mar 29, 2026"}>
  ## playwriter\@0.0.102

  1. **Direct CDP connection mode (`--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.

     ```bash
     playwriter session new --direct
     playwriter browser list
     ```

     In direct mode, `browser.contexts()` gives access to pages across all open Chrome profiles.

  2. **`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`.

  3. **Kitty Graphics Protocol support** — when `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.

     ```bash
     AGENT_GRAPHICS=kitty playwriter -s 1 -e "await screenshot({ page })"
     ```

  4. **Screenshots and images now use PNG** — `screenshotWithAccessibilityLabels()` and `resizeImageForAgent()` now consistently output PNG instead of JPEG, fixing `image/png` vs `image/jpeg` mismatch errors in MCP clients.

  5. **`resizeImageForAgent`** — renamed from `resizeImage`. Resized images are now automatically collected and included in responses. The old name still works as a backward-compatible alias.

  6. **Chrome 136+ direct CDP discovery** — `--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.

  7. **Show session cwd in `playwriter session list`** — session table now includes the working directory, making it easier to tell similar sessions apart.

  8. **Fix session cwd leakage across relay restarts** — relative `fs` paths in the sandbox now resolve from the cwd captured by `session new`.

  9. **Contenteditable detection in snapshots** — bare `contenteditable` elements are now correctly detected as interactive textboxes in accessibility snapshots.

  10. **`PLAYWRITER_DIRECT` only accepts `'1'`** — removed `'auto'` and `'true'` aliases. Explicit `ws://` endpoints still work.
</Update>

<Update id={"playwriter@0.0.89"} label={"Mar 13, 2026"}>
  ## playwriter\@0.0.89

  1. More reliable downloads in extension mode: download behavior now stays compatible with both `Page.download*` and `Browser.download*` event paths, so flows like `page.waitForEvent('download')` work consistently through the relay.

  2. Default action timeout is now 60 seconds, which reduces false click failures on slower real-world pages when interactions succeed but post-action waiting exceeds short budgets.

  3. Ghost cursor injection is more stable for recording flows by using direct per-page injection instead of the unreliable init-script persistence path.
</Update>

<Update id={"playwriter@0.0.80"} label={"Feb 28, 2026"}>
  ## playwriter\@0.0.80

  1. **Ghost cursor overlay during recording** — smooth animated cursor visualizes automated mouse actions (clicks, moves, presses) directly on the page during screen recordings, driven by Playwright `onMouseAction` callbacks so both `page.mouse.*` and `locator.click()` are captured

  2. **Demo video creation** — new `createDemoVideo()` automatically detects and speeds up idle sections between interactions, with hardware encoder detection (h264\_videotoolbox, etc.) and optimized FFmpeg output for social media

  3. **`resizeImage()` sandbox utility** — shrink screenshots before feeding them to LLMs; default mode fits within 1568×1568px, supports explicit width/height/maxDimension

  4. **Descriptive click timeout errors** — when `locator.click()` times out, the error now explains why ("Element is not visible", "Element is not stable", etc.) instead of a generic timeout message

  5. **Faster action timeouts** — default Playwright action timeout reduced from 10s to 2s so agents get fast failures with descriptive errors; navigation timeout unchanged at 10s

  6. **State-aware page-close warnings** — executor warns when a closed page is referenced in session state and reports which state key(s) need reassignment, with automatic fallback to another open tab

  7. **Popup detection warnings** — executor emits `[WARNING]` when popup windows open during execution so agents are aware of context changes

  8. **`recording` and `ghostCursor` namespaces** — cleaner API in the execute sandbox: `recording.start/stop/isRecording/cancel` and `ghostCursor.show/hide`, with backward-compatible top-level aliases

  9. **Multi-profile Chrome support** — auto-selects the correct extension when multiple Chrome profiles are connected simultaneously

  10. **Snapshot diff scoped by locator** — `showDiffSinceLastCall` cache now isolated per locator scope; also skipped automatically when `search` is provided

  11. **Relay state centralized to Zustand store** — internal relay state (extensions, targets, playwright clients) unified in a single immutable atom, eliminating scattered Maps and fixing edge-case reconnect bugs

  12. **`page.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`)

  13. **Suppress stack traces for timeout/abort errors** — CLI and MCP output is cleaner; only the message is shown for expected timeout failures
</Update>

<Update id={"playwriter@0.0.63"} label={"Feb 17, 2026"}>
  ## playwriter\@0.0.63

  ## Security

  * **Harden privileged HTTP routes against cross-origin attacks**: Added route-level middleware on `/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 enforcement on HTTP routes**: When `--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.
  * **Security regression tests**: Added tests covering Sec-Fetch-Site blocking, Content-Type enforcement, token validation on privileged routes, and pass-through for legitimate Node.js clients.
</Update>

<Update id={"playwriter@0.0.62"} label={"Feb 14, 2026"}>
  ## playwriter\@0.0.62

  ### Features

  * **Remote access support**: `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 traforo
  * **WebSocket over HTTPS**: Automatically uses `wss://` protocol when connecting to HTTPS relay hosts
  * **Remote access documentation**: Added comprehensive guide covering architecture, setup, use cases, and security model for remote Playwriter access

  ### Internal

  * **Centralized host parsing**: New `parseRelayHost()` utility handles URL/hostname detection and returns correct HTTP/WebSocket base URLs
</Update>

<Update id={"playwriter@0.0.61"} label={"Feb 14, 2026"}>
  ## playwriter\@0.0.61

  ## Improvements

  * **Simplified Unix port killing**: Replaced shell pipeline approach (lsof/grep/awk/xargs) with direct `lsof -t` for PID discovery and `process.kill()` for termination. This eliminates spawn overhead and makes the code more maintainable while improving reliability.
</Update>

<Update id={"@xmorse/playwright-core@1.59.3"} label={"Feb 11, 2026"}>
  ## @xmorse/playwright-core\@1.59.3

  * Fix missing runtime dependencies for lockfile.js: add graceful-fs, retry, and signal-exit to package.json dependencies
  * Fixes "Cannot find module 'graceful-fs'" error on clean npx playwriter installs (GitHub #45)
</Update>

<Update id={"playwriter@0.0.59"} label={"Feb 11, 2026"}>
  ## playwriter\@0.0.59

  ### Bug Fixes

  * **Fix 'Cannot find module graceful-fs' error**: Updated @xmorse/playwright-core to 1.59.3 which adds missing runtime dependencies (graceful-fs, retry, signal-exit) for clean npx playwriter installs (GitHub #45)
</Update>

<Update id={"playwriter@0.0.58"} label={"Feb 11, 2026"}>
  ## playwriter\@0.0.58

  * Fix `bunx playwriter@latest` relay restarts by replacing `kill-port-process` with a vendored cross-platform port killer.
  * Harden relay/test/serve port cleanup by routing all kills through local `killPortProcess({ port })` on Windows, macOS, and Linux.
  * Remove `kill-port-process` dependency and its transitive process-management packages from the lockfile.
  * thanks @remorses for the contributions.
</Update>

<Update id={"extension@0.0.71"} label={"Feb 11, 2026"}>
  ## extension\@0.0.71

  ### Bug Fixes

  * **Route Runtime.enable to child CDP sessions**: Runtime enable/disable now uses the incoming `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.
</Update>

<Update id={"playwriter@0.0.57"} label={"Feb 11, 2026"}>
  ## playwriter\@0.0.57

  ### Features

  * **Ghost Browser Support**: Added integration with Ghost Browser APIs (multi-identity, proxies)
  * **Multi-browser Support**: Added support for connecting to multiple browser instances/extensions
  * **Screen Recording**: Added concurrent screen recording support in MP4 format (requires extension update)
  * **Iframe Handling**: Improved iframe targeting using `Frame` objects and `Runtime.enable` routing
  * **Accessibility Snapshots**: Added support for inline locators and better filtering
  * **CDP JSONL Logging**: Added structured CDP logging to `~/.playwriter/cdp.jsonl`

  ### Bug Fixes

  * **Fix hung navigations on YouTube and similar sites**: Resume filtered targets (like service workers) to avoid blocking navigations
  * **Fix tab group infinite loop**: Prevent infinite loop when dragging tabs
  * **Fix log dir permissions on shared machines**: Move default log directory from `/tmp/playwriter` to `~/.playwriter` so each OS user gets their own directory. Fixes startup crash when `/tmp/playwriter` is owned by another user (#44).
</Update>

<Update id={"playwriter@0.0.56"} label={"Jan 26, 2026"}>
  ## playwriter\@0.0.56

  ## Bug Fixes

  * **Fix hung navigations on YouTube and similar sites**: Resume filtered targets (like service workers) to avoid blocking navigations. CDP `Target.setAutoAttach` with `waitForDebuggerOnStart: true` requires calling `Runtime.runIfWaitingForDebugger` even on targets we filter out, otherwise they hang forever.
  * **Fix auto-enable page selection when no pages**: Properly handles the case when there are no existing pages during auto-enable

  ## Features

  * **CDP JSONL logging**: Added structured CDP logging to a JSONL file (`/tmp/playwriter/cdp.jsonl`) for debugging. Log all CDP messages with direction, timestamp, and source info. Use `jq` to analyze.
  * **Sync tab state for automated tabs**: Tab state is now properly synced for programmatically created tabs

  ## Improvements

  * **Better logging output**: Use `util.inspect` for cleaner log output with proper object formatting
  * **Set default timeout**: Added sensible default timeouts for operations
</Update>

<Update id={"playwriter@0.0.55"} label={"Jan 25, 2026"}>
  ## playwriter\@0.0.55

  ### Features

  * **`playwriter 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 resources

  ### Internal

  * Moved SKILL.md to src/ - source of truth for agent instructions now lives in `src/skill.md`
  * Removed docker.package.json - cleaned up unused Docker configuration
</Update>

<Update id={"playwriter@0.0.54"} label={"Jan 25, 2026"}>
  ## playwriter\@0.0.54

  ## Features

  * **Faster aria snapshot ref lookup**: Refs are now extracted directly from the snapshot string and fetched in parallel (20 concurrent requests), significantly reducing time to generate accessibility snapshots with labels
  * **`refFilter` parameter for `getAriaSnapshot`**: New optional filter to include only specific refs by role/name, reducing unnecessary ref lookups
  * **Increased default execution timeout**: Execution timeout increased from 5s to 10s for better handling of slow operations

  ## Bug Fixes

  * **Pass cwd to executor in MCP**: File operations in executed code now use the correct working directory
</Update>

<Update id={"playwriter@0.0.53"} label={"Jan 24, 2026"}>
  ## playwriter\@0.0.53

  ## Bug Fixes

  * **Fix CLI relay server startup from source**: Detect source vs compiled via `__filename.endsWith('.ts')` instead of env var, fixing `tsx` and `vite-node` execution
  * **Wait for extension to reconnect**: CLI now waits up to 10 seconds for extension to reconnect after server (re)start before executing commands

  ## Improvements

  * **Colored CLI output**: Setup messages now use colors (dim for progress, green for success, yellow for warnings)
</Update>

<Update id={"playwriter@0.0.52"} label={"Jan 24, 2026"}>
  ## playwriter\@0.0.52

  ## Features

  * **First extension keeps connection**: When multiple Playwriter extensions are installed (e.g., dev and prod), the first one with active tabs now keeps the connection instead of being replaced by newer connections. Idle extensions (no tabs) can still be replaced.
  * **Smarter extension slot detection**: `/extension/status` endpoint now returns `activeTargets` count, allowing extensions to know when the slot becomes available (no active tabs).
  * **Accessibility snapshot format options**: `accessibilitySnapshot` now supports `format` option (`'yaml'` or `'markdown'`) with deduplication of interactive refs
  * **Session management CLI commands**: New CLI commands for managing relay sessions (`playwriter sessions list`, `playwriter sessions kill`)
  * **Eval CLI flag**: New `-e/--eval` CLI flag for quick code execution from command line
  * **Auto-enable environment variable**: CLI now passes `PLAYWRITER_AUTO_ENABLE` when starting relay server

  ## Bug Fixes

  * **Relay server auto-recovery**: Restored auto-recovery on every execute call
  * **Preserve tabs during relay reconnects**: Tabs now persist correctly when relay reconnects
  * **Show log file path on connection refused error**: Better debugging experience with log file location in errors
  * **Improved error messages for extension connection states**: Clearer error messages when extension isn't connected

  ## Security

  * **Block browser access to CLI endpoints**: Prevents browsers from accessing CLI-specific endpoints

  ## Internal

  * **SKILL.md as source of truth**: Refactored to generate `prompt.md` from `SKILL.md`
  * **Aria snapshot module**: New `aria-snapshot.ts` with dedicated accessibility snapshot functions
</Update>

<Update id={"playwriter@0.0.50"} label={"Jan 19, 2026"}>
  ## playwriter\@0.0.50

  ## Bug Fixes

  * **Sharp fallback with viewport clipping**: When sharp is unavailable (optional dependency), screenshots now clip to max 1568px instead of relying on Claude's auto-resize
  * **Error logging for sharp failures**: Added logging when sharp import or resize fails, making it easier to debug screenshot optimization issues
</Update>

<Update id={"playwriter@0.0.49"} label={"Jan 16, 2026"}>
  ## playwriter\@0.0.49

  ## Features

  * **CORS support for relay server**: Added CORS middleware to allow extension's fetch/XHR requests during development. Only allows requests from our specific extension IDs for security.

  ## Bug Fixes

  * **Clearer error messages**: Improved error messages when another Playwriter extension connects, making it easier to diagnose connection issues
</Update>

<Update id={"playwriter@0.0.48"} label={"Jan 15, 2026"}>
  ## playwriter\@0.0.48

  ## Bug Fixes

  * **Fix SSE streaming (issue #22)**: CDP's Network domain buffers response bodies by default, which breaks SSE/streaming - data arrives at Chrome but `ReadableStream` never receives it. Now `Network.enable` defaults to `maxTotalBufferSize: 0` to disable buffering.

  ## Features

  * **Auto-switch to another page when default page is closed**: When the current page is closed, MCP automatically switches to another available page instead of erroring
  * **Optimized screenshot token usage**: Screenshots are now resized with sharp to reduce Claude token consumption
  * **Reading response bodies**: Agents can re-enable Network buffering via `Network.disable` + `Network.enable` with explicit buffer sizes when they need `response.body()`

  ## Changes

  * **Dependencies cleanup**: Removed unused deps, updated to zod v4, replaced chalk with picocolors
</Update>

<Update id={"playwriter@0.0.47"} label={"Jan 14, 2026"}>
  ## playwriter\@0.0.47

  ## Bug Fixes

  * **Improved connection reliability**: Use `127.0.0.1` instead of `localhost` to avoid DNS/IPv6 resolution issues, add 15s global timeout wrapper around `connect()` to prevent hanging forever
  * **Use domcontentloaded everywhere**: Changed `getCurrentPage()` and prompt guidance to use `domcontentloaded` instead of `load` for faster, more reliable page detection
  * **Allow attaching to own extension pages**: Extension pages can now be debugged while still blocking other extensions

  ## Changes

  * **Centralized target filtering**: Consolidated extension ID arrays and target filtering logic for cleaner code
  * **Optional wsUrl in getCDPSessionForPage**: `wsUrl` parameter now defaults to `getCdpUrl()` if not provided
</Update>

<Update id={"playwriter@0.0.46"} label={"Jan 13, 2026"}>
  ## playwriter\@0.0.46

  ### Bug Fixes

  * **Limit screenshot dimensions to 2000px**: Screenshots are now clipped to max 2000x2000 pixels to avoid Claude API rejection for many-image requests (Claude enforces 2000px limit when >20 images in a request)
</Update>

<Update id={"playwriter@0.0.45"} label={"Jan 12, 2026"}>
  ## playwriter\@0.0.45

  ## Bug Fixes

  * **Filter non-page targets from Playwright (issue #14)**: Service workers, web workers, and other non-page targets are now filtered out at the server level. This prevents Playwright from trying to initialize these targets, which would cause timeouts waiting for `executionContextCreated` events and errors on `Target.detachFromTarget`.
</Update>

<Update id={"playwriter@0.0.44"} label={"Jan 12, 2026"}>
  ## playwriter\@0.0.44

  ## Features

  * **Search context lines**: `accessibilitySnapshot`, `getCleanHTML`, and `getLatestLogs` now include 5 lines of context above and below each search match
    * Non-contiguous sections are separated by `---`
    * Provides better context for understanding search results
</Update>

<Update id={"playwriter@0.0.43"} label={"Jan 11, 2026"}>
  ## playwriter\@0.0.43

  ## Features

  * **`getCleanHTML` utility**: New function to get cleaned HTML from a locator or page
    * Removes script, style, svg, head tags
    * Keeps only essential attributes (aria-*, data-*, href, role, title, alt, etc.)
    * Supports `search` option to filter results (returns first 10 matching lines)
    * Supports `showDiffSinceLastCall` to see changes since last snapshot
    * Supports `includeStyles` to optionally keep style/class attributes

  ## Changes

  * **Simplified `accessibilitySnapshot` search**: Removed `contextLines` parameter, search now returns just matching lines instead of context around matches. Use `.split('\n').slice()` for pagination instead.
</Update>

<Update id={"playwriter@0.0.42"} label={"Jan 6, 2026"}>
  ## playwriter\@0.0.42

  ## Bug Fixes

  * **Fix "no low surrogate in string" API error**: Sanitize accessibility snapshot text using `toWellFormed()` to remove unpaired Unicode surrogates that break JSON encoding for Claude API (requires Node.js 20+ for sanitization, gracefully degrades on older versions)
</Update>

<Update id={"playwriter@0.0.41"} label={"Jan 6, 2026"}>
  ## playwriter\@0.0.41

  ### Features

  * **Arrow connectors in screenshot labels**: Visual labels now show arrow lines from label to element center, making it clearer which element each label references

  ### Patch Changes

  * **Bigger label font**: Increased label font size from 11px to 12px for better readability
  * **Fixed screenshot dimensions**: Screenshots now use actual viewport size (`innerWidth`/`innerHeight`) with `scale: 'css'` to match visual appearance
</Update>

<Update id={"playwriter@0.0.40"} label={"Jan 5, 2026"}>
  ## playwriter\@0.0.40

  ### Features

  * **`screenshotWithAccessibilityLabels`**: New utility function that takes a screenshot with Vimium-style visual labels overlaid on interactive elements
    * Labels show aria-ref IDs that can be used with `page.locator('aria-ref=e5')`
    * Image and accessibility snapshot are automatically included in the response
    * Can be called multiple times to capture multiple screenshots
    * Labels are color-coded by element type
  * **Media elements in aria labels**: Added `img`, `video`, `audio` to INTERACTIVE\_ROLES
    * Light blue color scheme for media element labels
    * Agents can now reference images by aria-ref for visual tasks

  ### Patch Changes

  * **Extension fix**: Query playwriter tab group by title instead of caching ID, fixing stale group issues after debugger detach/reattach
</Update>

<Update id={"playwriter@0.0.39"} label={"Jan 3, 2026"}>
  ## playwriter\@0.0.39

  ### Patch Changes

  * **Fix icon not updating on WS disconnect**: `maintainLoop` now ensures tabs transition to 'connecting' state when WebSocket is not connected, fixing edge cases where `handleClose` wasn't called
  * **Increased aria-labels auto-hide timeout**: Labels now auto-hide after 30 seconds instead of 5 seconds
</Update>

<Update id={"playwriter@0.0.38"} label={"Jan 3, 2026"}>
  ## playwriter\@0.0.38

  ### Patch Changes

  * Internal connection handling improvements
</Update>
