PlaywrightNative is a .NET library to automate Chromium, Firefox, and WebKit with a pure .NET implementation — no Node.js, no driver process, no PowerShell scripts.
Chromium is the primary, fully supported browser. Firefox and WebKit launch today through the same API; Firefox is not in CI yet.
PlaywrightNative is a community-first project, created by the community, for the community.
Microsoft's playwright-dotnet is a thin auto-generated wrapper around a bundled Node.js process. After years of accumulated community frustration — 89% of open issues unanswered, top feature requests open for 4+ years, and a widening gap with the Node.js version — we decided to build something better.
The playwright-dotnet library ships an entire Node.js runtime inside your NuGet package. This means bloated CI/CD pipelines (teams have reported 300 GB/month in build artifacts just from Node.js binaries), incompatibility with AOT compilation and trimmed publish, and a multi-step installation ritual involving PowerShell scripts buried inside bin/ folders.
PlaywrightNative talks to the browser directly (CDP for Chromium, Juggler for Firefox, WebKit Inspection Protocol for WebKit). No Node.js. No driver process. No PowerShell scripts. Just dotnet add package and you're ready to go.
Our goal is full feature parity with Playwright — including the features the .NET community has been asking for and never got:
- Visual snapshot testing
- Built-in reporting
- Agentic tools and AI integration
- Soft assertions, Expect.Poll, custom expect messages
- Screenshot, video, and tracing on test failure
- Test retries that actually work
- Synchronous API option
- Programmatic configuration (not just
.runsettingsXML)
dotnet add package PlaywrightNative
That's it. No PowerShell scripts. No playwright.ps1 hidden in your build output. No dotnet build before you can install browsers. BrowserFetcher downloads browsers automatically when you launch.
PlaywrightNative welcomes contributions. We review PRs, we respond to issues, and we build what the community needs. This isn't a publish-only project with a locked-down contribution model — it's a project that grows with its users.
dotnet add package PlaywrightNative
using var playwright = await Playwright.CreateAsync();
await using IBrowser browser = await playwright.Chromium.LaunchAsync();
await using IBrowserContext context = await browser.NewContextAsync();
IPage page = await context.NewPageAsync();
await page.GotoAsync("https://www.bing.com");
byte[] png = await page.ScreenshotAsync();Firefox and WebKit use the same pattern:
using var playwright = await Playwright.CreateAsync();
await using IBrowser firefox = await playwright.Firefox.LaunchAsync();
await using IBrowser webkit = await playwright.Webkit.LaunchAsync();Pass a BrowserTypeLaunchOptions bag to set ExecutablePath, Headless, and other launch options. When ExecutablePath is omitted, BrowserFetcher downloads and caches the pinned browser build.
using var playwright = await Playwright.CreateAsync();
await using IBrowser browser = await playwright.Chromium.LaunchAsync();
await using IBrowserContext context = await browser.NewContextAsync();
IPage page = await context.NewPageAsync();
await page.GotoAsync("https://www.example.com/");
Dictionary<string, int> dimensions = await page.EvaluateAsync<Dictionary<string, int>>(@"() => ({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
})");
Console.WriteLine($"{dimensions["width"]}x{dimensions["height"]}");using var playwright = await Playwright.CreateAsync();
await using IBrowser browser = await playwright.Chromium.LaunchAsync();
await using IBrowserContext context = await browser.NewContextAsync();
IPage page = await context.NewPageAsync();
await page.RouteAsync("**/*", route =>
{
Console.WriteLine(route.Request.Url);
route.ContinueAsync();
});
await page.GotoAsync("https://todomvc.com");We welcome contributions! Check out the open issues to get started, or open a new one if you have an idea. PRs are reviewed and merged — not ignored.