playwright
- 1.64.1 is the latest, published 14 October 2026.
- 1 security advisory, all fixed.
- 1.x: 155 releases since 6 May 2020, 5 in the last 90 days.
Security advisories
Grouped by the version that fixes them, so one upgrade reads as one step.
Fixed in 1.55.1 · 1 advisory
Releases in the last 90 days
Feed of releases and advisoriesEvery stable release, newest first. Notes are quoted as the maintainers published them.
1.64.1
14 October 2026[Bug]: _electron.launch intermittently loses a packaged app's first window since 1.64.0
Bug Fixes
[Bug]: _electron.launch intermittently loses a packaged app's first window since 1.64.0
[Regression]: Chromium 155+ aborts a preflighted cross-origin redirect whenever any route is registered (net::ERR_ABORTED)
1.64.0
7 October 2026New page.webmcp and frame.webmcp give access to the tools that a page registers through the experimental WebMCP browser API, so you can test them like any other part of your app:
WebMCP
New page.webmcp and frame.webmcp give access to the tools that a page registers through the experimental WebMCP browser API, so you can test them like any other part of your app:
const browser = await chromium.launch({ args: ['--enable-features=WebMCP'] }); const page = await browser.newPage(); await page.goto('https://example.com'); for (const tool of await page.webmcp.tools()) console.log(tool.name, tool.description); const result = await page.webmcp.callTool('add', { a: 2, b: 40 }); console.log(result.content[0].text); // "42"Playwright MCP also supports WebMCP by default, with page-defined tools offered to the agent as
webmcp_<tool>. Pass--no-webmcpto opt out.playwright-cliexposes them as well:playwright-cli webmcp-list playwright-cli webmcp-call search_catalog --params '{"query":"cats"}'Better videos
Videos can now be recorded at a custom frame rate, and the decorations for actions are styled with plain CSS:
// playwright.config.ts import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { video: { mode: 'on', size: { width: 1920, height: 1080 }, fps: 60, show: { actions: { style: { point: 'width: 20px; height: 20px; border-radius: 50%; background: red', highlight: 'outline: 2px solid #333; background: rgba(0, 128, 255, .15)', title: 'font-size: 16px', }, }, }, }, }, });New
fpsoption in testOptions.video,recordVideoand screencast.start(). Firefox and WebKit currently capture up to 25 frames per second.New
styleoption takes CSS declarations for thepointmarker, the targethighlightand the actiontitle. It replaces thefontSizeoption, which is now deprecated.The cursor stays visible at the last action point, survives navigations and travels along a natural, eased path.
Videos are encoded with VP9 instead of VP8, which takes less CPU and produces smaller files of the same or better quality.
All video options are also available in Playwright MCP and
playwright-cli.
Locator.within()
New locator.within() combines two locators that you already have, reading in the natural order "this button, within that dialog":
const saveButton = page.getByRole('button', { name: 'Save' }); const dialog = page.getByTestId('settings-dialog'); await saveButton.within(dialog).click();Relative locators such as locator.nth() or locator.first() are resolved inside each parent separately, which makes column-like queries straightforward:
// The third cell of every row, not the third cell in the table. const thirdColumn = page.getByRole('cell').nth(2).within(page.getByRole('row')); await expect(thirdColumn).toHaveText(['Apple', 'Banana', 'Cherry']);New APIs
New page.getByRef() locates an element by its aria ref, such as
e2, reported by page.ariaSnapshot() in the'ai'mode.New option
includeShadowin page.content() and frame.content() serializes open shadow roots as declarative shadow DOM.New option
signCountsets the initial signature counter of a virtual credential. credentials.create() and credentials.get() return the currentsignCount, and it is saved and restored together with the credentials in the storage state.New fullConfig.filteredProjects lists the projects that were selected to run after applying the
--projectfilter. It is available in global setup and reporters.New apiRequestContext.addCookies(), apiRequestContext.cookies() and apiRequestContext.clearCookies() manage cookies of a request context, mirroring the BrowserContext methods:
await request.addCookies([{ name: 'session-id', value: '42', url: 'https://example.com' }]); console.log(await request.cookies('https://example.com')); await request.clearCookies({ name: 'session-id' });
Breaking changes
- breaking
screenproperty is now forwarded from the device descriptors. If you use...devices['Desktop Chrome']and alike,window.screenand media queries now see the emulated screen size. You can opt-out by explicitly settingscreentoundefined:// playwright.config.ts export default defineConfig({ use: { ...devices['Desktop Chrome'], screen: undefined, }, }); - breaking
JSX in your test files now follows your
tsconfig.json. Playwright compiles JSX in test files according to thejsx,jsxFactory,jsxFragmentFactoryandjsxImportSourcetsconfig options, and defaults to the automatic runtime fromreact/jsx-runtime. - breaking
--update-snapshots=missingnow passes the test run. Tests that only create missing snapshots now pass in the'missing'mode of testConfig.updateSnapshots, so that CI can generate new snapshots and verify the existing ones in a single run. The mode used when the option is not specified is now called'default'and behaves as before: missing snapshots are written and the test fails. - breaking
Elements inside hidden iframes are considered hidden. Elements inside an iframe that is not visible, for example with
visibility: hidden, are now considered hidden by actions, locator.isVisible() and expect(locator).toBeVisible().
1.63.0
4 September 2026Tests that access a shared resource — an external service, a global account setting — can now declare a named lock.
Test locks
Tests that access a shared resource — an external service, a global account setting — can now declare a named
lock. Tests that share a lock name never run concurrently, across files, workers and projects, while everything else keeps running in parallel:test('update user settings', { lock: 'user-settings' }, async ({ page }) => { // never runs at the same time as other tests holding 'user-settings' });A test can hold multiple locks, and test.describe() accepts a
lockfor the whole group. Learn more about test locks.Locate across frames
page.frameLocator() and frame.frameLocator() called without a selector search in any frame of the subtree, so you no longer need to locate the iframe first:
// Finds the button in any frame on the page. await page.frameLocator().getByRole('button').click();The rest of the locator resolves inside a single frame, just like a regular locator, and an error is thrown when it matches elements in several frames.
Visible-only locators
New locator.visible() returns a locator that matches only visible elements. It is the recommended replacement for the
:visibleCSS pseudo-class:await page.locator('button').visible().click();Step params and subtitles
Steps now carry structured data for reporters. Playwright API steps report the target locator and call arguments, and test.step() accepts
subtitleandparamsoptions for your own steps:await test.step('Login', async () => { // ... }, { subtitle: 'as admin', params: { user: 'admin' } });Reporters receive them via testStep.subtitle and testStep.params. For Playwright API steps, the subtitle is the locator or the navigation url — for example,
Clickwith subtitlegetByRole('button'). Both are rendered next to the step title in the trace viewer and the HTML report.Aria and screen snapshots in traces
The
snapshotsoption of tracing.start() and the testOptions.trace fixture option now accept an object selecting what to capture on every action:// playwright.config.ts export default defineConfig({ use: { trace: { mode: 'on', snapshots: { dom: true, aria: true, screen: true } }, }, });With aria and screen snapshots recorded, the new Display Aria mode in the trace viewer shows the action screenshot side by side with the aria snapshot, and hovering an aria node highlights it on the screenshot.
New APIs
Browser and Context
httpCredentialsnow also accepts an array of credentials. The first entry matching the request origin is used, and entries without an origin match any request.New option
opfsincludes the origin private file system in the storage state, so it can be persisted and restored into later contexts.New events page.on('dialogclosed') and browserContext.on('dialogclosed') are emitted when a JavaScript dialog is accepted, dismissed or closed by the user.
Locators
New locator.ariaSnapshotJSON() and page.ariaSnapshotJSON() return the aria snapshot as a JSON value instead of YAML markup, with
mode,depthandboxesoptions.apiRequestContext.get() and other request methods accept a type argument that types the response
json():
const response = await request.get<User>('/api/users/42'); const user = await response.json(); // typed as UserCommand line
npx playwright install --no-removekeeps the browsers of other Playwright installations instead of removing them.
1.62.1
30 July 2026[Regression]: tsconfig "extends" bare specifier isn't resolved via node_modules walk-up like tsc (fatal since 1.62)
Bug Fixes
[Regression]: tsconfig "extends" bare specifier isn't resolved via node_modules walk-up like tsc (fatal since 1.62)
[Regression]: directory-form tsconfig project references ("path": "../pkg") fail to resolve (fatal since 1.62)
Accessibility snapshot drops button name when text is nested inside spans with aria-hidden SVG
[Regression]: page.evaluate() arg of a branded primitive type (string & { brand }) no longer type-checks since 1.62
[BUG]Image-type actionable elements are not presented in the snapshot.
1.62.0
24 July 2026Component testing moves to a stories and galleries model.
New component testing model
Component testing moves to a stories and galleries model. A story wraps your component in one specific scenario — hard-coded props, mock data, providers — and a gallery page that you serve renders stories on demand. The new fixtures.mount() fixture navigates to the gallery, mounts a story by id, and returns a Locator scoped to the story's root element:
test('click should expand', async ({ mount }) => { const component = await mount('components/Expandable/Stateful'); await component.getByRole('button').click(); await expect(component.getByTestId('expanded')).toHaveValue('true'); });Pass a story type as a template argument to type-check its props, and use
update(props)/unmount()on the returned locator to re-render or tear down within a test.Cancel operations with AbortSignal
Most operations and web-first assertions now accept a
signaloption that takes anAbortSignal, letting you cancel long-running actions, navigations, waits, and assertions:const controller = new AbortController(); setTimeout(() => controller.abort(), 1000); await page.getByRole('button', { name: 'Submit' }).click({ signal: controller.signal }); await expect(page.getByText('Done')).toBeVisible({ signal: controller.signal });Providing a signal does not disable the default timeout; pass
timeout: 0to disable it.WebP screenshots
expect(page).toHaveScreenshot() and expect(locator).toHaveScreenshot() can now store snapshots in the WebP format — just give the snapshot a
.webpname:// Visual comparisons store the golden snapshot as lossless WebP. await expect(page).toHaveScreenshot('homepage.webp'); // Standalone screenshots can trade quality for size with lossy WebP. await page.screenshot({ path: 'homepage.webp', quality: 50 });page.screenshot() and [locator.screenshot() (playwright.dev/docs/api/class-locator) also accept
webpas atype, where quality100(the default) is lossless and lower values use lossy compression.Custom test filtering with Reporter.preprocess()
New reporter.preprocess() hook runs after the configuration is resolved and before reporter.onBegin(), letting a reporter mark individual tests as skipped, excluded, fixed, or failing through a TestRun object:
class MyReporter { async preprocess({ config, suite, testRun }) { for (const test of suite.allTests()) { if (shouldSkip(test)) testRun.skip(test); } } }Isolated retries
New testConfig.retryStrategy controls when failed tests are retried. The default
'immediate'retries as soon as a worker is free;'isolated'runs all retries at the end, one by one in a single worker, to minimize interference with the rest of the suite:// playwright.config.ts export default defineConfig({ retries: 2, retryStrategy: 'isolated', });New APIs
Browser and Context
New option
credentialsincludes the context's virtual WebAuthn Credentials (passkeys) in the storage state, so they can be persisted and re-seeded into later contexts.
Actions
New
scrolloption ("auto"|"none") on actions to opt out of Playwright's automatic scroll-into-view.
Network
New apiResponse.timing() returns resource timing information for an API response.
Evaluation
New locator.waitForFunction() waits until a function — called with the matching element — returns a truthy value.
page.evaluate() and related methods now accept functions as evaluate arguments.
page.addInitScript() / browserContext.addInitScript() now accept functions as init-script arguments.
Command line & MCP
Major versions
- 1.xsince 6 May 2020 · latest 1.64.1 · 155 releases
- 0.xsince 23 January 2015 · latest 0.18.0 · 36 releases
Quality and security signals
What npm and deps.dev say about the latest release. Signals, not a verdict.
Reading npm and deps.dev…
Registry facts last checked 15 October 2026. Releases and advisories last read 15 October 2026.
Know when your own dependencies move
Inlinr tracks your coding time automatically. Switch dependency tracking on for a project and it reads that repository's manifest to show what is behind and what has been deprecated — off by default, one project at a time.