Playwright v1.61.0 shipped today, June 15, 2026, at 10:05 UTC, about six weeks after v1.60.0 on May 11. It is a feature release with no breaking changes, and three of the new APIs directly address long-standing gaps in how teams test passkey flows, manipulate browser storage, and reason about flaky CI runs. The release also ships the Chromium 149, Firefox 151, and WebKit 26.5 browser channels and adds Ubuntu 26.04 to the supported platform list.
A virtual WebAuthn authenticator for passkey tests
The headline feature is browserContext.credentials, a virtual authenticator that can register passkeys and answer navigator.credentials.create() / navigator.credentials.get() ceremonies in the page. No real hardware key is required, and it works in every browser channel Chromium, Firefox, and WebKit.
The typical flow is to seed a passkey the backend already provisioned for a test user, then have the page's navigator.credentials.get() answer the challenge with that key:
const context = await browser.newContext();
// Seed a passkey your backend provisioned for a test user.
await context.credentials.create('example.com', {
id: credentialId,
userHandle,
privateKey,
publicKey,
});
await context.credentials.install();
const page = await context.newPage();
await page.goto('https://example.com/login');
// The page's navigator.credentials.get() is answered with the seeded passkey.
The release notes call out an alternative pattern: run a one-shot setup test that registers a passkey through the real UI, read it back with credentials.get(), and seed it into the rest of the suite. That is the right shape for projects that discover passkey support is required to log in and that previously skipped those tests entirely.
The practical consequence is that the explicit resource management patch Bun shipped in 1.3.12 is now a much smaller excuse: testing a passkey-only login used to require a real YubiKey on the CI runner, a custom virtual authenticator driver, or skipping the flow. After 1.61.0, it is a credentials.create call in a beforeEach.
A first-class page.localStorage and page.sessionStorage API
The second piece is the new WebStorage API, exposed as page.localStorage and page.sessionStorage. Reads and writes go directly to the page's storage for the current origin, no page.evaluate round-trip required:
await page.localStorage.setItem('token', 'abc');
const token = await page.localStorage.getItem('token');
const items = await page.sessionStorage.items();
page.evaluate(() => localStorage.setItem('token', 'abc')) still works, but the new API is a first-class protocol command on the same shape Playwright uses for cookies and storage state. That makes it usable on background pages, on service workers, and in tests that just want to assert storage state without bouncing through the JS context.
Network: securityDetails() and serverAddr() on API responses
The new apiResponse.securityDetails() and apiResponse.serverAddr() mirror the browser-side response.securityDetails() and response.serverAddr(). For teams that intercept and replay HTTP via Playwright's request / APIRequestContext API, that is finally a way to assert the negotiated TLS version, the cipher, the certificate subject, and the resolved server address, all in a single test. It is the same kind of capability that drove the esbuild 0.28.1 dev-server path-traversal story for offense; this is the defense side.
Test runner: trace-style video modes and expect.soft.poll
The runner picks up three video modes that bring testOptions.video to parity with testOptions.trace. The new values are 'on-all-retries', 'retain-on-first-failure', and 'retain-on-failure-and-retries'. The video modes table documents which runs are recorded and which are kept in each mode. For CI, 'retain-on-failure' is the obvious win: only broken runs burn disk.
Other runner improvements are small but useful:
expect.soft.poll(...)is now supported, the polling form ofexpect.soft. Failed assertions are recorded against the test, but execution continues, so a dashboard test can assert five loosely-coupled things and report all the failures at the end instead of fixing one, re-running, finding the next, and repeating.fullConfig.argvis a snapshot ofprocess.argvfrom the runner process, which reporters can read to surface custom arguments passed after the--separator.fullConfig.failOnFlakyTestsmirrors the config option, so reporters can explain why a run marked flaky failed.testInfo.errorsnow lists each sub-error of anAggregateErroras a separate entry, so a multi-failure assertion no longer collapses to a single line in the report.- A new
-Gshorthand for--grep-inverton the CLI.
Browser versions, HAR, and platform support
The release pins Chromium 149.0.7827.55, Mozilla Firefox 151.0, and WebKit 26.5, and is also tested against Google Chrome 149 and Microsoft Edge 149 stable channels. Ubuntu 26.04 is now a supported platform.
HAR and trace recordings now include WebSocket requests. Before 1.61.0, a regression that surfaced only over a WebSocket connection (chat, live cursors, real-time updates, server-sent events that are multiplexed over a single socket) was invisible in the recorded artifact. The trace viewer's network panel and the HAR file now both contain the WebSocket frames, which is what most teams expected from day one.
Smaller touches
- A new
artifactsDiroption onbrowserType.connectOverCDP()controls where traces and downloads go when attaching to an existing browser. - A new
cursoroption onscreencast.showActions()controls the cursor decoration rendered for pointer actions. - The
onFramecallback inscreencast.start()now receives atimestampof when the frame was presented by the browser.
For most teams the upgrade is bun install @playwright/test@latest and a re-install of the browsers. The new APIs are additive, no flag day. The passkey and WebStorage APIs are the parts worth a small migration, since they make the test suite meaningfully more honest about what the production app actually has to handle.



