🧰 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:
var browser = await playwright.Chromium.LaunchAsync(new() { Args = new[] { "--enable-features=WebMCP" } });
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
foreach (var tool in await page.Webmcp.ToolsAsync())
Console.WriteLine($"{tool.Name}: {tool.Description}");
var result = await page.Webmcp.CallToolAsync("add", new { a = 2, b = 40 });
Console.WriteLine(result?.GetProperty("content")[0].GetProperty("text")); // "42"Playwright MCP also supports WebMCP by default, with page-defined tools offered to the agent as webmcp_<tool>. Pass --no-webmcp to opt out.
playwright-cli exposes 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:
await page.Screencast.StartAsync(new()
{
Path = "video.webm",
Size = new() { Width = 1920, Height = 1080 },
Fps = 60,
});
await page.Screencast.ShowActionsAsync(new()
{
Style = new()
{
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
RecordVideoFpsoption and newFpsoption in Screencast.StartAsync(). 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":
var saveButton = page.GetByRole(AriaRole.Button, new() { Name = "Save" });
var dialog = page.GetByTestId("settings-dialog");
await saveButton.Within(dialog).ClickAsync();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.
var thirdColumn = page.GetByRole(AriaRole.Cell).Nth(2).Within(page.GetByRole(AriaRole.Row));
await Expect(thirdColumn).ToHaveTextAsync(new[] { "Apple", "Banana", "Cherry" });New APIs
-
New Page.GetByRef() locates an element by its aria ref, such as
e2, reported by Page.AriaSnapshotAsync() in theAriaSnapshotMode.Aimode. -
New option
IncludeShadowin Page.ContentAsync() and Frame.ContentAsync() serializes open shadow roots as declarative shadow DOM. -
New option
SignCountsets the initial signature counter of a virtual credential. Credentials.CreateAsync() and Credentials.GetAsync() return the currentSignCount, and it is saved and restored together with the credentials in the storage state. -
New APIRequestContext.AddCookiesAsync(), APIRequestContext.CookiesAsync() and APIRequestContext.ClearCookiesAsync() manage cookies of a request context, mirroring the BrowserContext methods:
await request.AddCookiesAsync(new[] { new Cookie { Name = "session-id", Value = "42", Url = "https://example.com" }, }); Console.WriteLine(await request.CookiesAsync("https://example.com")); await request.ClearCookiesAsync(new() { Name = "session-id" });
Breaking Changes ⚠️
- 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.IsVisibleAsync() and Expect(locator).ToBeVisibleAsync().
Browser Versions
- Chromium 156.0.8078.4
- Mozilla Firefox 157.0
- WebKit 27.2
This version was also tested against the following stable channels:
- Google Chrome 155
- Microsoft Edge 155