IRONSOFTWAREHOME
MIGRATION GUIDES

How to Migrate from Playwright to IronPDF in C#

Curtis Chau
Curtis Chau
Updated: August 1, 2026

Migrating from Microsoft Playwright for .NET to IronPDF moves your PDF generation workflow from a browser-automation testing framework to a purpose-built PDF library. This guide provides a step-by-step migration path that removes async browser lifecycle management and the separate playwright install browser-binary download step.

Why Migrate from Playwright to IronPDF

Understanding Playwright for .NET

Playwright for .NET (NuGet Microsoft.Playwright, MIT-licensed) is Microsoft's browser-automation framework, designed primarily for end-to-end testing across Chromium, Firefox, and WebKit. Its typical workloads are interactive: clicking buttons, filling forms, intercepting network requests, taking screenshots, and validating cross-browser compatibility.

PDF generation in Playwright is a secondary feature exposed via Page.PdfAsync(), and it is supported on Chromium only - Firefox and WebKit do not implement PDF output. Output uses the browser's print-to-PDF path (equivalent to Ctrl+P), which has implications for layouts, backgrounds, and pagination:

  • Testing-first architecture, not optimized for headless document production
  • Browser binaries (Chromium plus optionally Firefox and WebKit) must be installed separately via playwright install
  • Async API designed for test automation workflows
  • No built-in PDF/A, PDF/UA, digital signature, watermarking, merging, or security features

Considerations When Using Playwright for PDFs

Playwright was designed for end-to-end testing, not document generation. A few practical implications when repurposing it for PDFs:

  1. Browser binaries via playwright install. Playwright's default configuration downloads browser binaries (Chromium, Firefox, WebKit), which can be a consideration for environments with strict resource or deployment constraints.
  2. Async browser/context/page model. Developers need to be comfortable with browser contexts and page lifecycle management, including disposal.
  3. Testing-first architecture, not optimized for high-volume document generation.
  4. Print-to-PDF semantics equivalent to Ctrl+P browser print. Layouts may reflow, backgrounds may be omitted by default, and output is paginated for printing.
  5. No PDF/A or PDF/UA output. Playwright does not produce PDF/A (archival) or PDF/UA (accessibility) compliant documents. For Section 508, EU accessibility directives, or long-term archival requirements, a dedicated PDF library is typically required.
  6. Per-render browser resource usage when each PDF spins up browser contexts and pages.

Configuration Surface

Playwright exposes a configuration surface oriented toward test automation. The pieces most relevant when using it just for PDF generation:

Browser installation step:

# Separate installation step before first use
playwright install            # Downloads browser binaries (Chromium, Firefox, WebKit)
# Or for a single browser:
playwright install chromium   # Chromium-only (the only engine that supports PDF output)
SHELL

Browser Launch Configuration:

// Testing-focused launch options for PDF generation
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
    Headless = true,  // Required for server environments
    Args = new[] { "--disable-gpu", "--no-sandbox" } // Linux/Docker configs
});

Testing-Specific Configuration Options:

  • Headless: Must configure headless mode for production (defaults to headed for testing)
  • SlowMo: Test timing delays (irrelevant for PDF generation)
  • Devtools: Testing tools configuration (not needed for documents)
  • ExecutablePath: Custom browser paths for test environments
  • Proxy: Network interception for testing (unnecessary overhead)
  • DownloadsPath: Test artifact management
  • TracesDir: Test execution traces

Browser Context Management:

// Complex context lifecycle from testing paradigm
var context = await browser.NewContextAsync(new BrowserNewContextOptions
{
    ViewportSize = new ViewportSize { Width = 1920, Height = 1080 },
    UserAgent = "custom-user-agent",
    Locale = "en-US",
    TimezoneId = "America/New_York"
});
var page = await context.NewPageAsync();
// ... generate PDF ...
await context.CloseAsync();  // Manual cleanup required
await browser.CloseAsync();  // Manual cleanup required

Multi-browser surface:

// Playwright supports launching multiple engines
await playwright.Chromium.LaunchAsync();  // For Chromium-based testing (and PDF output)
await playwright.Firefox.LaunchAsync();   // For Firefox testing
await playwright.Webkit.LaunchAsync();    // For WebKit/Safari testing
// Note: Page.PdfAsync() is implemented on Chromium only.

IronPDF: single bundled renderer

// No separate browser-binary install or context management
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

IronPDF ships its rendering engine inside the NuGet package, so there is no separate playwright install step and no browser/context/page lifecycle to manage.

Playwright vs IronPDF Performance Comparison

MetricPlaywrightIronPDF
Primary PurposeE2E browser-automation frameworkPDF document generation
Design PhilosophyTesting-first; PDF is a secondary featurePurpose-built PDF library
NuGet PackageMicrosoft.Playwright (MIT)IronPdf (commercial)
Browser-Binary StepSeparate playwright install downloadBundled in the NuGet package
Engines Supporting PDFChromium only (Firefox / WebKit do not implement Page.PdfAsync())Single bundled Chromium-based renderer
First Render (Cold Start)4.5 seconds2.8 seconds
Subsequent Renders3.8-4.1 seconds0.8-1.2 seconds
Memory per Conversion280-420MB80-120MB
API StyleAsync browser/context/page lifecycleSynchronous or async; renderer-based
InitializationCreateAsync() + LaunchAsync() + NewPageAsync()new ChromePdfRenderer()
PDF/A SupportNot availableSupported
PDF/UA AccessibilityNot availableSupported
Digital SignaturesNot availableSupported
PDF EditingNot availableMerge, split, stamp, edit
Support ModelCommunityCommercial with SLA

IronPDF is built specifically for PDF generation, with a document-centric API surface. It uses a single bundled Chromium-based rendering engine and supports both synchronous and asynchronous operations, which gives developers a simpler mental model when PDF output - not browser interaction - is the goal.

The Bottom Line

Playwright is a strong fit when the primary workload is browser automation or cross-browser testing, with PDF output as an occasional secondary task. IronPDF is the better fit when PDF generation is the primary workload: there is no separate browser-binary install step, no browser/context/page lifecycle to manage, and document features like PDF/A, digital signatures, security, and merging are available out of the box.


Before You Start

Prerequisites

  1. .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. NuGet Access: Ability to install NuGet packages
  3. IronPDF License: Obtain your license key from ironpdf.com

NuGet Package Changes

# Remove Playwright
dotnet remove package Microsoft.Playwright

# Remove the downloaded browser binaries
# Delete the .playwright folder in your project (and any cached binaries
# under your user profile, e.g. %USERPROFILE%\.cache\ms-playwright on Windows)

# Add IronPDF
dotnet add package IronPdf
SHELL

No playwright install required with IronPDF - the rendering engine is bundled automatically.

License Configuration

// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

Complete API Reference

Namespace Changes

// Before: Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;

// After: IronPDF
using IronPdf;
using IronPdf.Rendering;

Core API Mappings

Playwright APIIronPDF API
Playwright.CreateAsync()new ChromePdfRenderer()
playwright.Chromium.LaunchAsync()Not needed
browser.NewPageAsync()Not needed
page.GotoAsync(url)renderer.RenderUrlAsPdf(url)
page.SetContentAsync(html) + page.PdfAsync()renderer.RenderHtmlAsPdf(html)
page.CloseAsync()Not needed
browser.CloseAsync()Not needed
PagePdfOptions.FormatRenderingOptions.PaperSize
PagePdfOptions.MarginRenderingOptions.MarginTop/Bottom/Left/Right
PagePdfOptions.DisplayHeaderFooterRenderingOptions.TextHeader/TextFooter
PagePdfOptions.HeaderTemplateRenderingOptions.HtmlHeader
PagePdfOptions.FooterTemplateRenderingOptions.HtmlFooter
<span class='pageNumber'>{page}

Code Migration Examples

Example 1: HTML String to PDF Conversion

Before (Playwright):

// NuGet: Install-Package Microsoft.Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var playwright = await Playwright.CreateAsync();
        var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();
        
        string html = "<h1>Hello World</h1><p>This is a test PDF.</p>";
        await page.SetContentAsync(html);
        await page.PdfAsync(new PagePdfOptions { Path = "output.pdf" });
        
        await browser.CloseAsync();
    }
}

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();
        
        string html = "<h1>Hello World</h1><p>This is a test PDF.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}

This example demonstrates the fundamental architectural difference. Playwright requires five async operations: Playwright.CreateAsync(), Chromium.LaunchAsync(), NewPageAsync(), SetContentAsync(), and PdfAsync(), plus explicit browser cleanup with CloseAsync().

IronPDF eliminates all this complexity: create a ChromePdfRenderer, call RenderHtmlAsPdf(), and SaveAs(). No async patterns, no browser lifecycle, no cleanup code. IronPDF's approach offers cleaner syntax and better integration with modern .NET applications. See the HTML to PDF documentation for comprehensive examples.

Example 2: URL to PDF Conversion

Before (Playwright):

// NuGet: Install-Package Microsoft.Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var playwright = await Playwright.CreateAsync();
        var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();
        
        await page.GotoAsync("https://www.example.com");
        await page.PdfAsync(new PagePdfOptions 
        { 
            Path = "webpage.pdf",
            Format = "A4"
        });
        
        await browser.CloseAsync();
    }
}

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();
        
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}

Playwright uses GotoAsync() to navigate to a URL followed by PdfAsync(). IronPDF provides a single RenderUrlAsPdf() method that handles navigation and PDF generation in one call. Note that Playwright requires specifying the Format in PagePdfOptions, while IronPDF uses RenderingOptions.PaperSize for paper size configuration. Learn more in our tutorials.

Example 3: Custom Page Size with Margins

Before (Playwright):

// NuGet: Install-Package Microsoft.Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var playwright = await Playwright.CreateAsync();
        await using var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();
        await page.SetContentAsync("<h1>Custom PDF</h1><p>Letter size with margins</p>");
        await page.PdfAsync(new PagePdfOptions 
        { 
            Path = "custom.pdf",
            Format = "Letter",
            Margin = new Margin { Top = "1in", Bottom = "1in", Left = "0.5in", Right = "0.5in" }
        });
    }
}

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
        renderer.RenderingOptions.MarginTop = 25;
        renderer.RenderingOptions.MarginBottom = 25;
        renderer.RenderingOptions.MarginLeft = 12;
        renderer.RenderingOptions.MarginRight = 12;
        var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>Letter size with margins</p>");
        pdf.SaveAs("custom.pdf");
    }
}

Playwright uses string-based margin values ("1in", "0.5in") while IronPDF uses numeric millimeter values. The conversion is: 1 inch = 25.4mm, so "1in" becomes 25 and "0.5in" becomes approximately 12. Playwright's Format = "Letter" maps to IronPDF's PaperSize = PdfPaperSize.Letter.

Example 4: Headers, Footers, and Custom Settings

Before (Playwright):

// NuGet: Install-Package Microsoft.Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var playwright = await Playwright.CreateAsync();
        var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();
        
        string html = "<h1>Custom PDF</h1><p>With margins and headers.</p>";
        await page.SetContentAsync(html);
        
        await page.PdfAsync(new PagePdfOptions
        {
            Path = "custom.pdf",
            Format = "A4",
            Margin = new Margin { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" },
            DisplayHeaderFooter = true,
            HeaderTemplate = "<div style='font-size:10px; text-align:center;'>Header</div>",
            FooterTemplate = "<div style='font-size:10px; text-align:center;'>Page <span class='pageNumber'></span></div>"
        });
        
        await browser.CloseAsync();
    }
}

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();
        
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.TextHeader.CenterText = "Header";
        renderer.RenderingOptions.TextFooter.CenterText = "Page {page}";
        
        string html = "<h1>Custom PDF</h1><p>With margins and headers.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("custom.pdf");
    }
}

This example shows the header/footer placeholder syntax difference. Playwright uses HTML class-based placeholders (<span class='pageNumber'></span>), while IronPDF uses curly brace placeholders ({page}). Note that Playwright requires DisplayHeaderFooter = true to enable headers/footers, while IronPDF enables them automatically when you set header/footer content.


Critical Migration Notes

Async to Sync Conversion

Playwright requires async/await throughout; IronPDF supports synchronous operations:

// Playwright: Async required
public async Task<byte[]> GeneratePdfAsync(string html)
{
    using var playwright = await Playwright.CreateAsync();
    await using var browser = await playwright.Chromium.LaunchAsync();
    var page = await browser.NewPageAsync();
    await page.SetContentAsync(html);
    return await page.PdfAsync();
}

// IronPDF: Sync is simpler
public byte[] GeneratePdf(string html)
{
    var renderer = new ChromePdfRenderer();
    return renderer.RenderHtmlAsPdf(html).BinaryData;
}

Margin Unit Conversion

Playwright uses string units; IronPDF uses numeric millimeters:

PlaywrightIronPDF (mm)
"1in"25
"0.5in"12
"1cm"10

Header/Footer Placeholder Conversion

Playwright ClassIronPDF Placeholder
<span class='pageNumber'>{page}
<span class='totalPages'>{total-pages}
<span class='date'>{date}
<span class='title'>{html-title}

Browser Lifecycle Elimination

Remove all browser management code:

// Playwright: Explicit cleanup required
await page.CloseAsync();
await browser.CloseAsync();
playwright.Dispose();

// IronPDF: No disposal needed - just use the renderer
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

New Capabilities After Migration

After migrating to IronPDF, you gain capabilities that Playwright cannot provide:

PDF Merging

var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");

Watermarks

pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");

Password Protection

pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;

Digital Signatures

var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);

PDF/A Compliance

pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);

Migration Checklist

Pre-Migration

  • Identify all Playwright PDF generation code
  • Document margin values (convert inches/cm to millimeters)
  • Note header/footer placeholder syntax for conversion
  • Obtain IronPDF license key from ironpdf.com

Package Changes

  • Remove the Microsoft.Playwright NuGet package
  • Delete the .playwright folder (and any cached Playwright browser binaries under your user profile)
  • Install the IronPdf NuGet package: dotnet add package IronPdf

Code Changes

  • Update namespace imports
  • Replace async browser lifecycle with ChromePdfRenderer
  • Convert page.SetContentAsync() + page.PdfAsync() to RenderHtmlAsPdf()
  • Convert page.GotoAsync() + page.PdfAsync() to RenderUrlAsPdf()
  • Convert margin strings to millimeter values
  • Convert header/footer placeholder syntax
  • Remove all browser/page disposal code
  • Add license initialization at application startup

Post-Migration

  • Visual comparison of PDF output
  • Verify header/footer rendering with page numbers
  • Test margin and page sizing accuracy
  • Add new capabilities (security, watermarks, merging) as needed

Please note: Playwright is a registered trademark of its respective owner. This site is not affiliated with, endorsed by, or sponsored by Microsoft. All product names, logos, and brands are property of their respective owners. Comparisons are for informational purposes only and reflect publicly available information at the time of writing.
Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...
Read More

Related Articles

Key in blue circle

Get your free 30-day Trial Key instantly.

Your trial license will be sent to your email address

No limitations. 100% unlocked. No credit card.

bullet_checkedNo credit card or account creation requiredNo limitations. 100% unlocked. No credit card.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Book your free Live Demo
Booking Badge

Trusted by Millions of Engineers Worldwide

Iron Software's customer logos
Get Your No-Obligation Consult
Complete the form below or email sales@ironsoftware.com
Your details will always be kept confidential.
Trusted by Millions of Engineers Worldwide
Iron Software's customer logos
Get your free 30-day Trial Key instantly.
No credit card or account creation required