How to Migrate from Playwright to IronPDF in C#
Migrating from Playwright for .NET to IronPDF transforms your PDF generation workflow from a testing-centric browser automation tool to a purpose-built PDF library. This guide provides a complete, step-by-step migration path that eliminates complex async patterns, browser lifecycle management, and 400MB+ browser downloads while providing better performance and professional PDF features.
Why Migrate from Playwright to IronPDF
Understanding Playwright for .NET
Playwright for .NET is Microsoft's end-to-end testing framework, NOT a document generation library. It was built from the ground up for automated testing across Chromium, Firefox, and WebKit browsers. Playwright excels at testing scenarios: clicking buttons, filling forms, intercepting network requests, taking screenshots, and validating cross-browser compatibility.
Critical Understanding: Playwright is a testing tool being repurposed for PDF generation. PDF creation is merely a side effect of the browser's print functionality (Ctrl+P), not a primary design goal. This creates fundamental architectural mismatches:
- Testing-first architecture: Built for interactive browser testing, not headless document production
- Multi-browser overhead: Downloads 400MB+ of browser binaries (Chromium, Firefox, WebKit) even when you only need PDF generation
- Test-centric API: Complex async patterns designed for test automation workflows, not document generation
- No document features: Missing PDF/A compliance, digital signatures, watermarking, merging, security controls
The Testing Framework Problem
Playwright was designed for end-to-end testing, not document generation. This creates fundamental issues when using it for PDFs:
400MB+ browser downloads required before first use. Playwright's default configuration involves downloading multiple browsers, which can be a consideration for environments with strict resource constraints.
Complex async patterns with browser contexts and page management. Developers must gain familiarity with browser contexts and page management, along with proper disposal practices.
Testing-first architecture not optimized for document generation.
Print-to-PDF limitations equivalent to Ctrl+P browser print. Layouts may reflow, backgrounds may be omitted by default, and output is paginated for printing.
No PDF/A or PDF/UA support for accessibility compliance. Playwright cannot produce PDF/A (archival) or PDF/UA (accessibility) compliant documents. For Section 508, EU accessibility directives, or long-term archival requirements, you'll need a dedicated PDF library.
- Resource-heavy operations requiring full browser instances.
The Testing Framework Configuration Problem
Playwright requires extensive testing-centric configuration that QA engineers understand but document developers shouldn't need:
Browser Installation Required:
# Manual installation step required before first use
playwright install # Downloads 400MB+ of browser binaries
# Or programmatically:
playwright install chromium # Still 100MB+ for single browser# Manual installation step required before first use
playwright install # Downloads 400MB+ of browser binaries
# Or programmatically:
playwright install chromium # Still 100MB+ for single browserBrowser 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-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-focused launch options for PDF generation
Using playwright = Await Playwright.CreateAsync()
Dim browser = Await playwright.Chromium.LaunchAsync(New BrowserTypeLaunchOptions With {
.Headless = True, ' Required for server environments
.Args = New String() { "--disable-gpu", "--no-sandbox" } ' Linux/Docker configs
})
End UsingTesting-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 environmentsProxy: Network interception for testing (unnecessary overhead)DownloadsPath: Test artifact managementTracesDir: 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// 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' Complex context lifecycle from testing paradigm
Dim context = Await browser.NewContextAsync(New BrowserNewContextOptions With {
.ViewportSize = New ViewportSize With {.Width = 1920, .Height = 1080},
.UserAgent = "custom-user-agent",
.Locale = "en-US",
.TimezoneId = "America/New_York"
})
Dim page = Await context.NewPageAsync()
' ... generate PDF ...
Await context.CloseAsync() ' Manual cleanup required
Await browser.CloseAsync() ' Manual cleanup requiredMulti-Browser Complexity:
// Playwright downloads multiple browsers by default
await playwright.Chromium.LaunchAsync(); // For Chrome testing
await playwright.Firefox.LaunchAsync(); // For Firefox testing
await playwright.Webkit.LaunchAsync(); // For Safari testing
// All downloaded but only Chromium needed for PDF generation// Playwright downloads multiple browsers by default
await playwright.Chromium.LaunchAsync(); // For Chrome testing
await playwright.Firefox.LaunchAsync(); // For Firefox testing
await playwright.Webkit.LaunchAsync(); // For Safari testing
// All downloaded but only Chromium needed for PDF generation' Playwright downloads multiple browsers by default
Await playwright.Chromium.LaunchAsync() ' For Chrome testing
Await playwright.Firefox.LaunchAsync() ' For Firefox testing
Await playwright.Webkit.LaunchAsync() ' For Safari testing
' All downloaded but only Chromium needed for PDF generationIronPDF: Zero Configuration, Zero Installation
// No installation, no configuration, no lifecycle management
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");// No installation, no configuration, no lifecycle management
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");' No installation, no configuration, no lifecycle management
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")True plug-and-play: IronPDF eliminates all testing framework overhead. No browser installation commands, no headless configuration, no context management—just instantiate and render. Built specifically for document generation, not adapted from testing tools.
Playwright vs IronPDF Performance Comparison
| Metric | Playwright | IronPDF |
|---|---|---|
| Primary Purpose | E2E Testing Framework | PDF Document Generation |
| Design Philosophy | Testing tool with PDF side feature | Purpose-built PDF library |
| Installation Required | playwright install (400MB+ download) | None - instant setup |
| Configuration Required | Headless mode, browser launch options, contexts | Zero configuration |
| Browser Download | 400MB+ (Chromium, Firefox, WebKit) | Built-in optimized engine |
| Setup Complexity | Command-line install + launch configuration | Plug-and-play |
| First Render (Cold Start) | 4.5 seconds | 2.8 seconds |
| Subsequent Renders | 3.8-4.1 seconds | 0.8-1.2 seconds |
| Memory per Conversion | 280-420MB | 80-120MB |
| API Complexity | Complex async browser/context/page lifecycle | Simple synchronous one-liners |
| Initialization | CreateAsync() + LaunchAsync() + NewPageAsync() | new ChromePdfRenderer() |
| PDF/A Support | Not available | Supported |
| PDF/UA Accessibility | Not available | Supported |
| Digital Signatures | Not available | Supported |
| PDF Editing | Not available | Merge, split, stamp, edit |
| Professional Support | Community | Commercial with SLA |
IronPDF was built with a focus on PDF generation. Unlike the testing-centric Playwright, IronPDF provides a variety of document-centric API features. It relies on a single optimized Chromium instance, favoring efficiency and offering both synchronous and asynchronous operations. This results in a simpler mental model and workflow for developers who require PDF functionalities.
For teams planning .NET 10 and C# 14 adoption through 2025 and 2026, IronPDF provides a purpose-built PDF solution that eliminates browser automation overhead while delivering better performance and professional document features.
The Bottom Line
Playwright is Microsoft's testing framework designed for QA engineers running cross-browser automated tests. Using it for PDF generation is architectural mismatch that requires extensive testing-specific knowledge:
- Manual browser installation (
playwright install) - Headless mode configuration for production
- Browser launch option management
- Context lifecycle configuration
- Multi-browser downloads (400MB+) when only one is needed
- Complex async/await patterns from testing paradigm
IronPDF is a document generation library designed for developers building PDF workflows. It's truly plug-and-play:
- Zero installation—works immediately
- Zero configuration—intelligent defaults
- Zero browser downloads—optimized engine included
- Simple API—no testing concepts to learn
- Automatic resource management—no lifecycle complexity
If you need to test web applications across browsers, use Playwright. If you need to generate PDF documents, use IronPDF. Don't adapt a testing framework for document generation—use the tool built specifically for the job.
Before You Start
Prerequisites
- .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet Access: Ability to install NuGet packages
- IronPDF License: Obtain your license key from ironpdf.com
NuGet Package Changes
# Remove Playwright
dotnet remove package Microsoft.Playwright
# Remove browser binaries (reclaim ~400MB disk space)
# Delete the .playwright folder in your project or user directory
# Add IronPDF
dotnet add package IronPdf# Remove Playwright
dotnet remove package Microsoft.Playwright
# Remove browser binaries (reclaim ~400MB disk space)
# Delete the .playwright folder in your project or user directory
# Add IronPDF
dotnet add package IronPdfNo playwright install required with IronPDF - the rendering engine is bundled automatically.
License Configuration
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";' 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;// Before: Playwright
using Microsoft.Playwright;
using System.Threading.Tasks;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;' Before: Playwright
Imports Microsoft.Playwright
Imports System.Threading.Tasks
' After: IronPDF
Imports IronPdf
Imports IronPdf.RenderingCore API Mappings
| Playwright API | IronPDF 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.Format | RenderingOptions.PaperSize |
PagePdfOptions.Margin | RenderingOptions.MarginTop/Bottom/Left/Right |
PagePdfOptions.DisplayHeaderFooter | RenderingOptions.TextHeader/TextFooter |
PagePdfOptions.HeaderTemplate | RenderingOptions.HtmlHeader |
PagePdfOptions.FooterTemplate | RenderingOptions.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();
}
}// 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();
}
}Imports Microsoft.Playwright
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim playwright = Await Playwright.CreateAsync()
Dim browser = Await playwright.Chromium.LaunchAsync()
Dim page = Await browser.NewPageAsync()
Dim html As String = "<h1>Hello World</h1><p>This is a test PDF.</p>"
Await page.SetContentAsync(html)
Await page.PdfAsync(New PagePdfOptions With {.Path = "output.pdf"})
Await browser.CloseAsync()
End Function
End ModuleAfter (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");
}
}// 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");
}
}Imports IronPdf
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<h1>Hello World</h1><p>This is a test PDF.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End ClassThis 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();
}
}// 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();
}
}Imports Microsoft.Playwright
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim playwright = Await Playwright.CreateAsync()
Dim browser = Await playwright.Chromium.LaunchAsync()
Dim page = Await browser.NewPageAsync()
Await page.GotoAsync("https://www.example.com")
Await page.PdfAsync(New PagePdfOptions With {
.Path = "webpage.pdf",
.Format = "A4"
})
Await browser.CloseAsync()
End Function
End ModuleAfter (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");
}
}// 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");
}
}Imports IronPdf
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End ClassPlaywright 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" }
});
}
}// 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" }
});
}
}Imports Microsoft.Playwright
Imports System.Threading.Tasks
Module Program
Async Function Main() As Task
Using playwright = Await Playwright.CreateAsync()
Await Using browser = Await playwright.Chromium.LaunchAsync()
Dim page = Await browser.NewPageAsync()
Await page.SetContentAsync("<h1>Custom PDF</h1><p>Letter size with margins</p>")
Await page.PdfAsync(New PagePdfOptions With {
.Path = "custom.pdf",
.Format = "Letter",
.Margin = New Margin With {
.Top = "1in",
.Bottom = "1in",
.Left = "0.5in",
.Right = "0.5in"
}
})
End Using
End Using
End Function
End ModuleAfter (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");
}
}// 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");
}
}Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
renderer.RenderingOptions.MarginTop = 25
renderer.RenderingOptions.MarginBottom = 25
renderer.RenderingOptions.MarginLeft = 12
renderer.RenderingOptions.MarginRight = 12
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>Letter size with margins</p>")
pdf.SaveAs("custom.pdf")
End Sub
End ClassPlaywright 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();
}
}// 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();
}
}Imports Microsoft.Playwright
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim playwright = Await Playwright.CreateAsync()
Dim browser = Await playwright.Chromium.LaunchAsync()
Dim page = Await browser.NewPageAsync()
Dim html As String = "<h1>Custom PDF</h1><p>With margins and headers.</p>"
Await page.SetContentAsync(html)
Await page.PdfAsync(New PagePdfOptions With {
.Path = "custom.pdf",
.Format = "A4",
.Margin = New Margin With {.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()
End Function
End ModuleAfter (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");
}
}// 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");
}
}Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main(args As String())
Dim 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}"
Dim html As String = "<h1>Custom PDF</h1><p>With margins and headers.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom.pdf")
End Sub
End ClassThis 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;
}// 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;
}Imports System.Threading.Tasks
Imports Microsoft.Playwright
Public Class PdfGenerator
' Playwright: Async required
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Using playwright = Await Playwright.CreateAsync()
Await Using browser = Await playwright.Chromium.LaunchAsync()
Dim page = Await browser.NewPageAsync()
Await page.SetContentAsync(html)
Return Await page.PdfAsync()
End Using
End Using
End Function
' IronPDF: Sync is simpler
Public Function GeneratePdf(html As String) As Byte()
Dim renderer = New ChromePdfRenderer()
Return renderer.RenderHtmlAsPdf(html).BinaryData
End Function
End ClassMargin Unit Conversion
Playwright uses string units; IronPDF uses numeric millimeters:
| Playwright | IronPDF (mm) |
|---|---|
"1in" | 25 |
"0.5in" | 12 |
"1cm" | 10 |
Header/Footer Placeholder Conversion
| Playwright Class | IronPDF 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");// 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");' Playwright: Explicit cleanup required
Await page.CloseAsync()
Await browser.CloseAsync()
playwright.Dispose()
' IronPDF: No disposal needed - just use the renderer
Dim renderer As New ChromePdfRenderer()
Dim 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");var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");Dim pdf1 = renderer.RenderHtmlAsPdf(html1)
Dim pdf2 = renderer.RenderHtmlAsPdf(html2)
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("merged.pdf")Watermarks
pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");IRON VB CONVERTER ERROR developers@ironsoftware.comPassword Protection
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;pdf.SecuritySettings.OwnerPassword = "admin"
pdf.SecuritySettings.UserPassword = "readonly"
pdf.SecuritySettings.AllowUserCopyPasteContent = FalseDigital Signatures
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)PDF/A Compliance
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);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
Microsoft.PlaywrightNuGet package - Delete
.playwrightfolder to reclaim ~400MB disk space - Install
IronPdfNuGet package:dotnet add package IronPdf
Code Changes
- Update namespace imports
- Replace async browser lifecycle with
ChromePdfRenderer - Convert
page.SetContentAsync()+page.PdfAsync()toRenderHtmlAsPdf() - Convert
page.GotoAsync()+page.PdfAsync()toRenderUrlAsPdf() - 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






