Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

How do you convert HTML to PDF? Choose a browser print flow when the page is already rendered for a person, Puppeteer or Playwright when you need an automated browser and JavaScript fidelity, WeasyPrint when a Python application needs a document-oriented renderer, and Prince when advanced paginated-media composition justifies a commercial engine. The best HTML-to-PDF library depends on rendering fidelity, print layout control, deployment language, security boundaries, and required PDF features—not on a universal performance winner.

Start with the output you actually need

HTML-to-PDF conversion has two different meanings. You may want a PDF that matches a live website after JavaScript, fonts, and client-side data have loaded. Or you may want a typeset document with deliberate page dimensions, running headers, footers, numbering, bookmarks, and repeatable page breaks. Browser automation is usually the safer choice for the first requirement; a paged-media renderer is often a better fit for the second.

Method Best fit Important behavior
Browser print interface A person prints an already rendered page Uses the browser’s print preview and save-as-PDF workflow; little server-side integration
Puppeteer JavaScript or TypeScript services that need Chromium automation Page.pdf() uses print CSS by default; screen media must be selected explicitly
Playwright Browser automation with Playwright’s multi-browser tooling and PDF options page.pdf() returns a PDF buffer and uses print CSS by default
WeasyPrint Python applications producing document-style PDFs A Python HTML/CSS renderer, not a full WebKit or Gecko browser; supports links, bookmarks, attachments, and forms
Prince Publishing systems needing extensive paged-media controls Commercial HTML/XML-to-PDF engine with page dimensions, headers, footers, numbering, and page-break controls

Browser print: the simplest manual method

When a person has opened the page, wait for the content to finish rendering, then use the browser’s Print command and select “Save as PDF.” This preserves the normal user workflow and avoids operating a server-side browser. It is appropriate for occasional exports, support instructions, and pages where a human must confirm the final state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

It is not a dependable batch conversion API. The result can depend on the browser, extensions, logged-in session, print settings, blocked resources, and the timing of client-side rendering. For repeatable jobs, move to an API-driven renderer and make the print assumptions explicit.

Convert HTML with Puppeteer

Puppeteer documents a sequence of launching a browser, opening a page, navigating to the content, calling Page.pdf(), and closing the browser. Font loading is awaited by default in the documented PDF-generation flow. The API reference is at pptr.dev/api/puppeteer.page.pdf.

Minimal runnable Node.js example

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com/invoice/123', {
      waitUntil: 'networkidle0'
    });

    await page.pdf({
      path: 'invoice.pdf',
      format: 'A4',
      printBackground: true,
      margin: { top: '18mm', right: '14mm', bottom: '18mm', left: '14mm' }
    });
  } finally {
    await browser.close();
  }
})();

Page.pdf() renders with print CSS by default. If the page was designed for screen media and you intentionally want that styling, select it before generating the PDF:

await page.emulateMediaType('screen');
await page.pdf({ path: 'screen-styled.pdf', printBackground: true });

Print color treatment can also change the visual result. Test backgrounds, gradients, and branded colors under the exact browser and PDF settings you will deploy. For a stable document, prefer print-specific rules such as @media print and @page rather than relying on a user’s preview settings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When Puppeteer is the right choice

  • The source depends on client-side JavaScript, authenticated browser state, or a browser-only layout engine.
  • You need the same DOM, fonts, and CSS behavior that a Chromium user sees.
  • Your service is already JavaScript/TypeScript and can operate a browser process.

Convert HTML with Playwright

Playwright’s page.pdf() returns a PDF buffer. Its API documents an output path and options for page sizing and CSS behavior. Like Puppeteer, it uses print CSS by default, so screen styling requires an explicit media choice.

import { chromium } from 'playwright';
import { writeFile } from 'node:fs/promises';

const browser = await chromium.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com/report', { waitUntil: 'networkidle' });
  const pdf = await page.pdf({
    path: 'report.pdf',
    format: 'A4',
    printBackground: true,
    preferCSSPageSize: true,
    margin: { top: '16mm', right: '14mm', bottom: '16mm', left: '14mm' }
  });
  await writeFile('report-copy.pdf', pdf);
} finally {
  await browser.close();
}

Use Playwright when its browser-context model, project tooling, or existing test infrastructure is already part of your stack. Do not assume that switching between Playwright and Puppeteer will produce byte-for-byte identical PDFs: browser versions, fonts, print settings, and page timing still matter.

Convert HTML with WeasyPrint

WeasyPrint 70.0 is documented as a Python 3.10+ HTML/CSS rendering engine under the BSD license. The project describes itself as “a visual rendering engine for HTML and CSS that can export to PDF.” It is not a wrapper around a complete WebKit or Gecko browser, so JavaScript-dependent pages may require a browser renderer instead.

Python API from a string

from weasyprint import HTML

html = '''
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      @page { size: A4; margin: 18mm 14mm; }
      h1 { break-after: avoid; }
      .invoice { page-break-inside: avoid; }
    </style>
  </head>
  <body>
    <h1>Invoice</h1>
    <div class="invoice">Thank you.</div>
  </body>
</html>
'''

HTML(string=html, base_url='https://example.com/').write_pdf('invoice.pdf')

Set base_url whenever the HTML contains relative images, stylesheets, fonts, or other resources. Without a meaningful base URL, those references cannot be resolved reliably. The API also exposes URL-fetching configuration, which lets an application control how external resources are retrieved.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Files, URLs, and the command line

The API accepts HTML strings, files, file objects, and URLs. The command-line interface is useful for batch jobs and container entrypoints; keep the input and output paths explicit and make sure the runtime has the system libraries and fonts required by your distribution.

WeasyPrint’s document features include hyperlinks, bookmarks, attachments, and forms. Its documentation says PDF/A and PDF/UA generation is supported but does not guarantee that every generated file will satisfy those standards. Validate a PDF against the specific conformance profile your regulator or archive requires.

Use Prince for advanced paged-media publishing

Prince is a commercial HTML/XML-to-PDF engine. Its user guide and styling documentation describe controls for page dimensions, headers, footers, numbering, and page breaks, making it a candidate for books, invoices, catalogs, and reports where pagination is part of the product rather than a side effect.

Prince documentation also describes HTML, Markdown, and XML input and server-side integration. Treat the renderer and its resource-fetching configuration as a security boundary, particularly when users can influence markup or URLs. The reviewed documentation does not establish a current price or affiliate program, so obtain commercial terms directly from YesLogic before budgeting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Write CSS that survives PDF pagination

Define the paper and margins

@page {
  size: A4 portrait;
  margin: 18mm 14mm 20mm;
}

@page :first {
  margin-top: 12mm;
}

@media print {
  .screen-only { display: none; }
  a { color: #000; text-decoration: none; }
}

Browser engines and document renderers share many CSS concepts but not identical feature sets. Keep critical layout rules simple, test the exact renderer version, and avoid assuming that a screen flex or grid layout will paginate exactly as it does in a viewport.

Control breaks and repeating content

  • Use break-before, break-after, and break-inside for modern pagination rules, with legacy page-break-* declarations when your renderer requires them.
  • Keep headings with the following content using break-after: avoid.
  • Protect signatures, table rows, and compact cards with break-inside: avoid, while accepting that an oversized element may still need to split.
  • Use renderer-specific running-header features only after confirming support in the version you deploy.

Make assets deterministic

PDF jobs fail or vary when fonts, images, or API data are still loading. Host required assets where the renderer can reach them, use absolute URLs or a correct base URL, wait for the page state that means “ready,” and log failed resource requests. For authenticated resources, pass credentials through the renderer’s supported context or fetch the data server-side; never place long-lived secrets in public HTML.

How to choose the best HTML-to-PDF library

Question Prefer a browser API when… Prefer WeasyPrint or Prince when…
Does the page need JavaScript? Client-side rendering, charts, or browser APIs determine the final DOM. The input is principally HTML/CSS and can be rendered without application JavaScript.
Must it match a live website? Pixel and behavior fidelity to a Chromium page matter. A controlled document layout is more important than browser parity.
How much page composition is needed? Basic paper size, margins, and print CSS are enough. Running furniture, numbering, sophisticated breaks, or publishing workflows are central.
What is the integration environment? Your service already runs Node.js and can manage browser workers. Your application is Python, or a dedicated renderer fits the deployment model.
Which PDF features matter? You mainly need a visual PDF of a web page. You need document features such as bookmarks, attachments, forms, or a paged-media workflow.

There is no evidence here of a universal speed or visual-quality winner. Select a representative set of pages, render them in the versions you will ship, and inspect text selection, links, fonts, page breaks, images, and accessibility requirements before committing.

Security and reliability checklist

  • Untrusted markup: isolate rendering of user-controlled HTML and CSS. WeasyPrint’s web-app guidance warns that user-modifiable content can create security problems.
  • Network access: restrict outbound requests, allow-list hosts where possible, and prevent access to internal metadata endpoints.
  • Resource limits: set job timeouts, maximum input sizes, browser-process limits, and temporary-directory quotas.
  • Authentication: use short-lived cookies or tokens, redact credentials from logs, and ensure generated PDFs do not expose private URLs.
  • Repeatability: pin browser or renderer versions, fonts, locale, timezone, and paper settings; record these with the job.
  • Validation: open the produced file, check its page count and size, and run PDF/A, PDF/UA, or business-rule validation when required.

Troubleshooting common failures

The PDF is blank or missing late content

Cause: conversion started before client-side rendering completed, or a resource request failed. Wait for a meaningful selector or application-ready signal instead of relying only on a short sleep. In a browser API, inspect console and request failures and confirm that the page is not still showing a loading shell.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The layout looks like the screen version

Cause: print CSS is the default for Puppeteer and Playwright, or print rules intentionally hide or restyle elements. Decide which medium you want. For screen styling, select the screen media type before calling pdf(); for a print document, move essential rules into print styles and test color handling.

Images, fonts, or CSS are absent in WeasyPrint

Cause: relative URLs lack a base URL, the process cannot reach the host, or the resource is blocked by authentication or TLS policy. Supply base_url, use accessible absolute URLs, configure URL fetching deliberately, and log the failing resource.

Pages split invoices or cards awkwardly

Cause: the element is taller than the available page area or lacks break rules. Add appropriate break-inside: avoid and heading rules, but design a fallback for content that genuinely cannot fit on one page.

Rank #4
I Know HTML How To Meet Ladies Funny Programming Language T-Shirt
  • Programming Language Lover Code Apparel. App or Web Design and Development Expert Funny Dress. Best Valentines Idea For Coding Lover. HTML Code or Meaning Costume
  • Funny I Know HTML - How To Meet Ladies Computer Programmer Quotes
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem

The PDF passes visual inspection but fails a standard

Cause: visual similarity is not the same as PDF/A or PDF/UA conformance. Use a validator for the exact profile and treat WeasyPrint’s statement that conformance is not guaranteed as a reason to verify, not as a certification.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Browser jobs consume too many resources

Cause: launching a fresh browser for every request, leaking pages, or allowing unbounded concurrent jobs. Reuse a controlled browser process where safe, close pages and contexts in finally blocks, queue work, and enforce per-job timeouts. Measure your own workload rather than assuming a published benchmark.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server that can return a clean screenshot or PDF from one request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.

Use the API options for PDF output, paper size, margins, landscape mode, and page ranges. The same service also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, custom CSS and JavaScript, clicks before capture, selector hiding, waits for selectors, delays or network idle, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, image resizing, configurable caching, signed public-image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.

One-call example

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for the PDF output option and the complete parameter list. Python and Node.js clients can use the same endpoint:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients, so an AI agent can request captures without you maintaining browser orchestration. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Cost, performance, and operations

Browser automation carries the operational cost of browser binaries, memory, startup time, and concurrency management. A document renderer can be simpler to deploy for static HTML/CSS, while a commercial engine may reduce the engineering needed for sophisticated pagination. These are architecture trade-offs, not guarantees of speed.

For any option, cache immutable source documents, avoid downloading the same fonts repeatedly, and separate conversion from request handling with a queue when jobs can run for seconds or minutes. Record input URL or document ID, renderer version, paper settings, duration, output size, page count, and failure reason. For browser APIs, keep navigation and PDF timeouts distinct so a slow origin is distinguishable from a PDF-generation failure.

FAQ

Is HTML-to-PDF a browser problem or a CSS problem?

It is both. A browser API reproduces runtime page behavior, while a document renderer emphasizes CSS paged media. Decide which behavior is authoritative before choosing a tool.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I use WeasyPrint for a JavaScript-heavy single-page app?

Not reliably when JavaScript is required to create the final content. Render the page in a browser first, or provide WeasyPrint with already-materialized HTML and assets.

Why do two browser libraries produce different PDFs?

Browser engine versions, installed fonts, print media rules, color settings, resource timing, and locale can differ even when the API calls look similar.

What should I test before shipping?

Test representative short and long documents, missing images, web fonts, tables crossing pages, right-to-left or localized text, authenticated assets, timeouts, and the PDF conformance profile your users require.

Frequently Asked Questions

Which tool should I start with for a JavaScript-rendered website?

Start with Puppeteer or Playwright, because both drive a browser and document print-CSS behavior explicitly. Choose based on the automation stack you already operate.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do Puppeteer and Playwright use screen CSS automatically?

No. Their PDF methods use print CSS by default. Select screen media deliberately when that is the intended design.

When is a commercial renderer justified?

Prince is worth evaluating when precise paged-media composition—running headers, footers, numbering, and controlled breaks—is central to the product and licensing fits your budget.

Quick Recap

Bestseller No. 2
Bestseller No. 4
I Know HTML How To Meet Ladies Funny Programming Language T-Shirt
I Know HTML How To Meet Ladies Funny Programming Language T-Shirt
Funny I Know HTML - How To Meet Ladies Computer Programmer Quotes; Lightweight, Classic fit, Double-needle sleeve and bottom hem
$19.99
SaleBestseller No. 5

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.