Free tools Windows power users keep installed
One-click scans. No signup required.
Use Microsoft.Playwright’s Page.PdfAsync method. Open the page (or set its HTML), wait until the content is ready, then export it:
await page.PdfAsync(new() { Path = "output.pdf" });
Playwright renders PDFs with print CSS by default. If the PDF must match the screen presentation, call EmulateMediaAsync with Media.Screen before exporting.
What you need before converting HTML
- A .NET project with the
Microsoft.PlaywrightNuGet package. - The browser binary required by the Playwright version installed in that project.
- A URL or HTML document that your Playwright page can load.
- A writable destination for the generated PDF.
Playwright browser binaries are version-specific. Microsoft’s documentation states that each Playwright version needs specific browser versions. Install the browsers after adding the package, and repeat that installation after upgrading Playwright. In a build pipeline or Linux host, install the system dependencies documented for your browser as well.
Step-by-step: convert a web page to PDF in C#
1. Create the project and add Playwright
dotnet new console -n HtmlToPdf
cd HtmlToPdf
dotnet add package Microsoft.Playwright
Build the project once, then run the Playwright installation script generated under the build output. For a typical .NET 8 Debug build, the command is:
#1 Best Overall
dotnet build
pwsh bin/Debug/net8.0/playwright.ps1 install
Use the framework directory produced by your project if it is not net8.0. On CI or Linux, use the corresponding Playwright CLI option to install browser operating-system dependencies when required.
2. Launch a browser, open the page, and export
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new()
{
Headless = true
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
await page.PdfAsync(new()
{
Path = "output.pdf"
});
PdfAsync returns the PDF data and, when Path is supplied, writes the file to that path. The example uses Chromium because PDF generation is provided by the Chromium browser engine.
3. Wait for content that is not ready at navigation time
Navigation completing does not guarantee that client-rendered data, fonts, images, or lazy sections are ready. Choose a wait that matches the page rather than adding an arbitrary long delay.
await page.GotoAsync("https://example.com/report");
await page.WaitForSelectorAsync("#report-ready");
await page.PdfAsync(new() { Path = "report.pdf" });
If the page has no reliable readiness element, wait for a known response or use a short, deliberate timeout for the final asset. Inspect the resulting PDF for clipped content and missing fonts instead of assuming that a navigation event means the page is complete.
Print CSS versus screen CSS
PDF generation uses print media by default. That is usually desirable because a page’s @media print rules can remove navigation, change colors, or control page breaks. To render the screen design instead, select screen media before calling PdfAsync:
await page.EmulateMediaAsync(new()
{
Media = Media.Screen
});
await page.PdfAsync(new()
{
Path = "screen-styled.pdf"
});
Do not select screen media merely because the browser preview looks better. Decide whether the deliverable is a printable document or a screen-faithful snapshot, then test that choice against the actual HTML and CSS.
Rank #2
PDF layout options worth setting
The .NET binding exposes PDF options for paper size, explicit dimensions, margins, scaling, page ranges, backgrounds, and CSS page-size precedence. Property names can vary with the binding version, so check the Microsoft.Playwright .NET API for the version in your project before copying a JavaScript example.
Paper, dimensions, and margins
await page.PdfAsync(new()
{
Path = "letter.pdf",
Format = "Letter",
Margin = new()
{
Top = "0.5in",
Right = "0.5in",
Bottom = "0.5in",
Left = "0.5in"
}
});
Letter is the documented default when no format or dimensions are supplied. Use a named format when the output must follow a known paper standard; use width and height when the document has a custom page size.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteLet CSS @page control the size
When the document defines its own @page size, enable the option that gives CSS page size priority (named PreferCSSPageSize in the .NET binding). Otherwise, an API format or dimensions setting can override the stylesheet.
await page.PdfAsync(new()
{
Path = "css-sized.pdf",
PreferCSSPageSize = true
});
Backgrounds, scale, and page ranges
Background printing is an explicit PDF option. Enable it when branded color blocks or background images are part of the intended document. Scale and page-range options are useful for fitting a dense report or exporting only selected pages.
await page.PdfAsync(new()
{
Path = "selected-pages.pdf",
PrintBackground = true,
Scale = 0.9f,
PageRanges = "1-3,5"
});
Verify the exact option types for your installed .NET package; some releases represent scale and range values differently.
Headers and footers
Header and footer templates are supported, but their scripts are not evaluated and normal page styles are not visible inside the templates. Put the required styling directly in the template and do not rely on page JavaScript to populate it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Controlling the HTML before export
Convert a string of HTML
var page = await browser.NewPageAsync();
await page.SetContentAsync("""
Invoice
Generated by Playwright.
""");
await page.PdfAsync(new()
{
Path = "invoice.pdf",
PreferCSSPageSize = true
});
Make page breaks predictable
Use print CSS to keep headings with following content and to avoid splitting rows where the browser supports it:
@media print {
h1, h2, h3 { break-after: avoid; }
table, img { break-inside: avoid; }
}
Large images, web fonts, and lazy-loaded sections are common sources of differences. Wait for a known ready state, and inspect a representative long document rather than testing only a short page.
Why does a Playwright PDF look different from the browser?
- Print media is active. Print rules may hide elements or alter colors. Select
Media.Screenonly when screen styling is the requirement. - Backgrounds are disabled. Enable the PDF background-printing option and check print CSS.
- CSS page size is being ignored. Enable CSS page-size preference and remove conflicting API dimensions.
- Fonts or images were not ready. Wait for the relevant selector or asset, then export.
- Page breaks differ. Check margins, scale,
@page, and break rules together; changing one can move content onto another page.
Browser installation and CI troubleshooting
“Executable doesn’t exist” or launch failure
The package is installed but its matching browser is not. Run the Playwright install script generated by your build, and run it again after a Playwright upgrade. Pin package versions in CI so the browser cache and .NET package stay aligned.
Linux reports missing libraries
Install the operating-system dependencies through the Playwright CLI using the browser-specific dependency option documented for your environment. Container images should include those libraries before the test or conversion job starts.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →The PDF is empty or stops before dynamic content
Confirm that navigation reached the expected URL, wait for a page-specific readiness selector, and check that authentication or required headers are present. A page that fails in a normal headless browser session will not become valid merely because PdfAsync was called.
Colors or images are missing
Enable background printing, inspect @media print, and verify that assets load before export. Print output can modify colors; the CSS property -webkit-print-color-adjust can request exact color rendering, but validate the result in the PDF viewer you use.
Rank #4
Output ignores the declared paper size
Look for a conflict between Format, explicit width or height, and CSS @page. Set CSS page-size preference when the stylesheet is authoritative.
Reliability, performance, and security considerations
Reuse the browser process
For batches, launch Chromium once and create a new page or browser context per document. Repeated process startup is slower and consumes more resources. Close pages and contexts after each conversion, and close the browser in a finally path when wrapping this in a service.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Control resource usage
Very long pages, high-resolution images, and large scale values increase memory and PDF size. Set a navigation timeout appropriate to your page, use page ranges when a complete document is unnecessary, and avoid exporting more resolution than the reader needs.
Protect the conversion service
If users can submit URLs, restrict outbound access to prevent requests to internal services, validate allowed schemes, and isolate browser processes. Treat downloaded HTML, JavaScript, and generated PDFs as untrusted content. Supply authentication headers or cookies only for destinations you control.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If you need an HTTP service rather than a locally managed browser, ScreenshotNeo returns a PDF from one request. Its capture flow accepts cookie and consent banners before removing more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
See the parameter reference in the ScreenshotNeo documentation. A basic cURL request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For PDF output, request the PDF format using the documented format parameter:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-d format=pdf
-o page.pdf
The same endpoint works from Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com", "format": "pdf"},
timeout=90,
)
r.raise_for_status()
open("page.pdf", "wb").write(r.content)
And Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com', format: 'pdf' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('page.pdf', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It supports paper size, margins, landscape mode, page ranges, custom CSS and JavaScript, waiting rules, headers, cookies, user agents, caching, async jobs, and bulk capture. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is on every plan. Create a free ScreenshotNeo account.
Frequently asked questions
Frequently Asked Questions
Can Playwright generate a PDF from HTML that is not hosted online?
Yes. Use SetContentAsync with the HTML string, then call PdfAsync. Include any CSS in the document or load stylesheets that the browser can reach.
Does PdfAsync return bytes as well as save a file?
Yes. The call returns PDF data; supplying the Path option also writes that data to the specified file.
Which browser should I install for PDF generation?
Use the browser binary installed by the Playwright version in your project and keep the package and binary installation synchronized. Chromium is the normal engine for this workflow.
Can I export only part of a PDF document?
Use the PDF page-range option for selected pages, or create a page containing only the section you want before exporting.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




