A Playwright PDF alternative for .NET.
Playwright prints PDFs from a browser that you install with its command-line tool and launch from your code. SelectPdf ships Chromium in a NuGet package and converts with one class, so there is no install step and no browser to launch. In the same open benchmark, SelectPdf kept its memory flat over 1,000 conversions, produced every PDF/A and PDF/UA level valid, and ran on the official .NET Docker image, where Playwright needs Microsoft's own image of about 5 GB.
using SelectPdf.Universal;
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.Letter;
converter.Options.CssMediaType =
HtmlToPdfCssMediaType.Print;
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("report.pdf");
doc.Close();
HTML to PDF in SelectPdf, with Playwright's Letter paper and print media.
Playwright and SelectPdf at a glance.
Playwright for .NET is Microsoft's free browser automation library for end-to-end testing; its page.PdfAsync prints a page to PDF with Chromium. SelectPdf.Universal is the cross-platform .NET PDF library from SelectPdf: it converts URLs and HTML to PDF with a Chromium engine shipped in a NuGet package, and also creates, edits and reads PDF documents.
| SelectPdf | Playwright | |
|---|---|---|
| HTML engine | Chromium 154.0.8037.58, in a NuGet engine package | Chromium 153.0.8010.12 (Playwright 1.63.0), installed with playwright.ps1 install chromium |
| Setup in code | new HtmlToPdf() | Playwright.CreateAsync(), Chromium.LaunchAsync(), NewPageAsync() |
| After an upgrade | nothing extra: the engine is a package dependency | install may have to run again for the new browser versions |
| Linux | no OS packages (glibc 2.30 or later) | system packages from install-deps |
| Docker | the official .NET images | Microsoft's Playwright image (browsers and .NET 10, about 5 GB on disk) |
| PDF tools | merge, split, watermarks, forms, text extraction, PDF to image, signatures, PDF/A, PDF/UA | printing to PDF only |
| License | commercial, perpetual, from USD 499 | free, MIT (the bundled Node.js driver Apache-2.0) |
Moving over replaces the browser lifecycle with one converter class and turns PagePdfOptions into converter.Options, with margins in points and timeouts in seconds. The sections below show where SelectPdf comes out ahead, how to migrate Playwright code to SelectPdf, and what it costs.
Where SelectPdf is ahead.
Measurements from the 2026-10-15 run of the open pdf-benchmarks harness: Microsoft.Playwright 1.63.0 and SelectPdf.Universal 26.5.0 on the same machine.
| SelectPdf | Playwright | |
|---|---|---|
| Browser install | none | playwright.ps1 install chromium |
| Memory after 1,000 conversions, Windows | 140 → 156 MB, 0 failures | 276 → 302 MB, 1 failure |
| Memory after 1,000 conversions, Linux | 369 → 389 MB | 435 → 721 MB |
| Memory, 8 conversions at once, Windows | 467 MB | 797 MB |
| Test pages converted faster, Windows | 12 of 18 | 6 of 18 |
| Conversions a minute, 8 at once, Linux | 2,597 | 2,080 |
| Fidelity to Chrome, mean SSIM | 0.984 | 0.948 |
| PDF/A, PDF/UA and PDF/X levels valid | all 17 | none produced |
| Docker on the official .NET image | runs, root and non-root (270 MB) | does not run |
| Merge, watermark, forms, signatures, text extraction | included | not available |
Every number above, with the rest of the measurements, is in the full table below.
Migrate Playwright code to SelectPdf.
The same task in both: an HTML string converted to PDF. Install the library and the engine package for your platform:
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.win-x64
Playwright:
using Microsoft.Playwright;
var exitCode = Microsoft.Playwright.Program.Main(["install", "chromium"]);
if (exitCode != 0)
throw new Exception($"Playwright exited with code {exitCode}");
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
await page.PdfAsync(new() { Path = "report.pdf" });
SelectPdf:
using SelectPdf.Universal;
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.Letter;
converter.Options.CssMediaType = HtmlToPdfCssMediaType.Print;
converter.Options.WebPageWidth = 816;
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("report.pdf");
doc.Close();
The three options reproduce Playwright's defaults (Letter paper, print media, the page laid out at the paper width); without them SelectPdf uses A4, screen media and a 1,024 px layout width. Six tasks side by side, including URLs, page setup, headers and footers and an ASP.NET Core endpoint, each built and checked, are in the migration guide on GitHub.
Map Playwright APIs to SelectPdf.
SelectPdf margins and header heights are in points (20 mm is 57 pt), the layout width in pixels, and timeouts in seconds.
| Playwright | SelectPdf |
|---|---|
playwright install, Playwright.CreateAsync(), Chromium.LaunchAsync() | nothing to call |
page.SetContentAsync(html) + page.PdfAsync(...) | ConvertHtmlString(html) + doc.Save(path) |
page.GotoAsync(url) + page.PdfAsync(...) | ConvertUrl(url) + doc.Save(path) |
EmulateMediaAsync(new() { Media = Media.Screen }) | Options.CssMediaType |
SetViewportSizeAsync(width, height) | Options.WebPageWidth / WebPageHeight |
Format, Landscape | Options.PdfPageSize, Options.PdfPageOrientation |
Margin ("20mm") | MarginTop and the others (points) |
HeaderTemplate, FooterTemplate | Header / Footer with PdfHtmlSection or PdfTextSection |
pageNumber, totalPages classes | {page_number}, {total_pages} |
WaitForFunctionAsync(...), Locator.WaitForAsync() | Options.WindowStatus or selectpdf.start() |
EvaluateAsync(...), AddInitScriptAsync(...) | Options.PostLoadingScript, Options.StartupScript |
context.AddCookiesAsync, SetExtraHTTPHeadersAsync | Options.HttpCookies, Options.HttpHeaders |
Tagged, Outline | Options.Tagged, PdfBookmarkOptions |
The complete mapping is in the migration guide; every class is in the documentation.
Playwright and SelectPdf pricing.
Playwright is free under the MIT license, with its bundled Node.js driver under Apache-2.0. SelectPdf is commercial: a Single Developer license is USD 499 and a Single Developer OEM license, for SaaS and software sold to customers, USD 799, both perpetual with one year of updates (SelectPdf pricing). The SelectPdf Community Edition converts HTML to PDF for free for documents up to 5 pages, and the full library runs as a 30-day trial without a key. One license covers SelectPdf.Universal and the classic Windows library.
The full measurement.
Microsoft.Playwright 1.63.0 and SelectPdf.Universal 26.5.0 on every axis of the 2026-10-15 run, on one machine under Windows and Linux, generated from the raw data. The method, per-page numbers and eight other .NET PDF libraries are on the results page; the harness is open source, so every number can be re-run.
| Playwright | SelectPdf | |
|---|---|---|
| HTML to PDF, geometric mean of 18 page medians, ms (Windows) | 280 | 212 |
| Pages converted faster than the other library (Windows) | 6 of 18 | 12 of 18 |
| Cold start, ms (Windows) | 823 | 714 |
| Throughput, conversions/min, 1 / 4 / 8 at once, sync (Windows) | 223 / 747 / 1,167 | 353 / 948 / 1,078 |
| Throughput, conversions/min, 1 / 4 / 8 at once, async (Windows) | 208 / 710 / 1,205 | 323 / 926 / 1,158 |
| Memory, one page / 8 at once, MB (Windows) | 300 / 797 | 205 / 467 |
| Memory over 1,000 conversions, MB (Windows) | 276 → 302, 1 failure | 140 → 156, 0 failures |
| Page that never loads: gives up after, s (Windows) | 30 | 60 |
| Parallel output equals sequential (Windows) | 32 / 32 | 32 / 32 |
| HTML to PDF, geometric mean of 18 page medians, ms (Linux) | 108 | 134 |
| Pages converted faster than the other library (Linux) | 17 of 18 | 1 of 18 |
| Cold start, ms (Linux) | 771 | 745 |
| Throughput, conversions/min, 1 / 4 / 8 at once, sync (Linux) | 603 / 1,656 / 2,080 | 619 / 1,929 / 2,597 |
| Throughput, conversions/min, 1 / 4 / 8 at once, async (Linux) | 524 / 1,797 / 2,490 | 603 / 1,872 / 2,639 |
| Memory, one page / 8 at once, MB (Linux) | 522 / 849 | 462 / 727 |
| Memory over 1,000 conversions, MB (Linux) | 435 → 721, 0 failures | 369 → 389, 0 failures |
| Page that never loads: gives up after, s (Linux) | 30 | 60 |
| Parallel output equals sequential (Linux) | 32 / 32 | 32 / 32 |
| Content checks passed (Windows) | 38 / 42 | 46 / 48 |
| Content checks passed (Linux) | 38 / 42 | 46 / 48 |
| Fidelity vs Chrome, mean SSIM (Windows) | 0.948 | 0.984 |
| PDF/A, PDF/UA, PDF/X: levels produced / valid (of 17) | 0 / 0 | 17 / 17 |
| Tagged structure checks | – | 112 / 112 |
| Text extraction, lowest F1 | not supported | 0.97 |
| Search | not supported | supported |
| PDF to image | not supported | supported |
| Word to PDF | not supported | supported |
| Redaction | not supported | supported |
| Merge | not supported | supported |
| Split | not supported | supported |
| Watermark | not supported | supported |
| Digital signature | not supported | supported |
| Form filling | not supported | supported |
| ZUGFeRD / Factur-X | not supported | supported |
| Docker, minimal image (Linux) | does not run, 123 MB | runs, 270 MB |
| Docker, vendor-documented image (Linux) | – | not needed (the minimal image runs) |
| Publish size win-x64 / linux-x64, MB | 103.5 / 134.9 | 477.0 / 449.6 |
Linux, Docker and ARM64.
Playwright's Linux browsers need the system packages from install-deps, and its Docker guide uses Microsoft's Playwright image, which holds the browsers and their packages (Chromium, Firefox and WebKit, on .NET 10, about 5 GB on disk); its tag must match the package version. SelectPdf's engine package bundles the Chromium libraries, so the official .NET images work without apt-get lines, as root or as a non-root user; the benchmark image was 270 MB. Linux needs glibc 2.30 or later; on Alpine, conversions run in the SelectPdf engine container.
Step by step: HTML to PDF in Docker on Linux. Both libraries' Dockerfiles are side by side in the C# PDF libraries comparison.
Questions, answered.
Something else? Write to support@selectpdf.com with your settings and, if you can, the HTML.