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

For HTML that already looks like a document—such as an invoice, report, or certificate—use WeasyPrint: install its Python package and native dependencies, then render an HTML document with HTML(...).write_pdf(). If the page must run JavaScript or depends on browser APIs, use Puppeteer to print it with Chromium instead. Both are open-source options, but they use different rendering models, so the right choice depends on what the page needs.

Choose a renderer for the page you have

“HTML to PDF” can mean either laying out document-oriented HTML as pages or printing a live web application. Those are different jobs. WeasyPrint is a Python library designed for HTML and CSS document rendering; Puppeteer controls a browser and is a better fit when the page needs JavaScript execution or browser behavior. wkhtmltopdf is best treated as a legacy compatibility choice rather than the default for a new project.

Tool Rendering model Best fit Important trade-off
WeasyPrint HTML/CSS paged-media renderer Python projects producing reports, invoices, certificates, and similar documents Requires Python and native Pango-related dependencies; verify the CSS features your documents use.
Puppeteer Controls Chromium Pages that need JavaScript, browser APIs, or Chromium-compatible CSS Requires a compatible Chromium installation and intentional handling of page readiness and print versus screen styles.
wkhtmltopdf Qt WebKit command-line renderer Maintaining an existing workflow that depends on its behavior The project lists 0.12.6 as its stable series, released June 11, 2020; its security notice warns against untrusted HTML/JavaScript.

Do not choose based only on a page looking correct in a browser. CSS support differs between renderers. Test the layout features, fonts, images, links, and pagination that matter to your output.

Convert document-style HTML with WeasyPrint

Install and verify the prerequisites

Install Python and the native libraries required by WeasyPrint on the operating system where the conversion will run. The project’s installation guidance calls out Pango-related dependencies. Once those are available, install the package and check that its command-line tool can report its environment:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
python -m pip install weasyprint
weasyprint --info

If the install fails because a native library is missing, installing the Python package again will not fix the underlying system dependency. Follow the installation instructions for your operating system and runtime environment, then rerun weasyprint --info.

Render a local HTML file

Save this as convert.py beside report.html. Passing a base URL gives relative image, stylesheet, and font references a location to resolve against. The generated PDF is written to report.pdf.

from pathlib import Path
from weasyprint import HTML

html_file = Path(__file__).with_name("report.html")
output_file = Path(__file__).with_name("report.pdf")

HTML(filename=str(html_file), base_url=str(html_file.parent)).write_pdf(
    str(output_file)
)

print(f"Wrote {output_file}")

For HTML already held in a Python string, use HTML(string=html_text, base_url=...) instead. Set base_url to the directory or URL that should anchor relative asset paths. Without a useful base URL, a relative reference such as images/logo.png may not resolve as intended.

Set page size, margins, and print rules

Use print CSS to define the document’s page geometry and hide elements that belong only in an interactive screen view. For example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
@page {
  size: A4;
  margin: 18mm 16mm;
}

@media print {
  .screen-only {
    display: none;
  }

  h1, h2 {
    break-after: avoid;
  }

  .keep-together {
    break-inside: avoid;
  }
}

Change A4 to the paper size your recipients need; do not assume the renderer’s default matches your business requirement. Inspect long tables and sections that can cross page boundaries. A rule that keeps a block together can still produce awkward whitespace if the block is taller than the printable area.

Check document features before committing

WeasyPrint supports features beyond basic page output, including hyperlinks, bookmarks, attachments, forms, and PDF/A or PDF/UA output. Confirm the exact feature and output requirements against the WeasyPrint documentation and validate the resulting PDF; a feature being supported does not guarantee that a particular document is structured correctly for your workflow.

Use Puppeteer when the page needs a browser

Choose Puppeteer if the content appears only after application JavaScript runs, depends on browser APIs, or relies on Chromium-compatible rendering. The following Node.js example opens a page, waits for its fonts, and writes a PDF. Install Puppeteer in your project with npm install puppeteer; Puppeteer needs a compatible Chromium installation available to it.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });

  try {
    const page = await browser.newPage();
    await page.goto('https://example.com/report', {
      waitUntil: 'networkidle0',
    });

    // Wait for web fonts before calculating and printing the layout.
    await page.evaluate(() => document.fonts.ready);

    // Page.pdf() uses print CSS media by default.
    await page.pdf({
      path: 'report.pdf',
      format: 'A4',
      printBackground: true,
      margin: {
        top: '18mm',
        right: '16mm',
        bottom: '18mm',
        left: '16mm',
      },
    });
  } finally {
    await browser.close();
  }
})();

Replace the example URL with your page. For a page whose content is populated asynchronously, add an application-specific readiness condition before printing; reaching a network-idle state alone does not prove that the report data is complete. If the screen stylesheet—not the print stylesheet—is the desired source, call await page.emulateMediaType('screen') before page.pdf(). Otherwise, Puppeteer’s PDF method uses print media by default.

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

Or skip the browser setup

If your input is a public webpage and you need a captured PDF rather than control over a local renderer, ScreenshotNeo can return a PDF from its screenshot API. Its API also removes known consent banners, newsletter popups, and chat widgets before capture; only clean shots are billed, while bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. An MCP server offers screenshot tools for AI clients, and the free plan includes 1,000 shots per month without a card. See the ScreenshotNeo website and API documentation for the PDF output options.

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

This one-call example saves a WebP capture of the example page. The API can also return a PDF; use the output settings documented for the endpoint when you need PDF rather than an image. It is a hosted service, not a local open-source HTML renderer, so use WeasyPrint or Puppeteer when you need to own the rendering environment or process local HTML.

For a quick test, the Free plan provides 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo to try it.

Make pagination and assets predictable

  • Resolve assets deliberately. Use absolute asset URLs or a valid base URL. Ensure images and fonts are accessible to the renderer in the environment that runs the conversion.
  • Define print-specific styling. Set page size and margins with @page, and decide what should be hidden, repeated, or broken across pages.
  • Wait for content, not just navigation. Browser-rendered pages may require data fetching or client-side rendering after initial page load. Wait for a selector or application readiness signal when appropriate, then wait for fonts.
  • Validate representative documents. Review page breaks, table splits, font rendering and embedding, links, bookmarks, and any accessibility or archival requirements. Recheck when content length or styles change.
  • Keep renderer versions and dependencies controlled. WeasyPrint depends on native libraries; Puppeteer depends on compatible Chromium. A working development machine does not guarantee the same dependencies exist in a production container.

Protect the renderer from untrusted input

HTML and CSS can cause a renderer to access resources. If users can submit markup, templates, or styles, treat that content as potentially hostile. WeasyPrint documents security concerns with untrusted sources. The wkhtmltopdf project gives a particularly strong warning: “Do not use wkhtmltopdf with any untrusted HTML – be sure to sanitize any user-supplied HTML/JS, otherwise it can lead to complete takeover of the server it’s running on!”

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.
  • Sanitize or constrain user-supplied HTML and CSS rather than assuming a PDF conversion is passive.
  • Restrict access to local files and network resources so a document cannot read sensitive files or reach internal services.
  • For browser-based conversion, control script execution and the pages the browser can load; do not run arbitrary user content with broad server permissions.
  • Run conversion in an appropriately isolated environment and avoid exposing credentials or sensitive files to the renderer.

The required controls depend on your application and threat model. A renderer choice by itself does not make unsafe input safe.

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

Troubleshoot common conversion failures

WeasyPrint reports missing libraries

Cause: A required native dependency is absent or unavailable in the runtime environment. Fix: Install the documented operating-system dependencies, including the Pango-related libraries, and run weasyprint --info again before testing the conversion.

Images, stylesheets, or fonts are missing

Cause: Relative paths have no correct base, or assets are unavailable to the conversion process. Fix: Supply an appropriate base_url for WeasyPrint, use absolute URLs where appropriate, and verify that the renderer can access each asset.

The PDF differs from the browser view

Cause: The selected renderer has different CSS support, or the browser is using a different media stylesheet. Fix: Test the CSS features you rely on in the chosen renderer. With Puppeteer, remember that PDF output uses print media by default; switch to screen media only if that is the intended layout.

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

The first page is incomplete or uses fallback fonts

Cause: The application had not finished rendering or web fonts were not ready when the PDF was created. Fix: Wait for an application-specific condition and for document.fonts.ready before calling page.pdf().

Tables or sections split badly

Cause: The document’s page-break rules do not suit its content or page dimensions. Fix: Adjust print CSS and page margins, then inspect both short and long examples. Avoid forcing an oversized element to stay on one page.

The conversion hangs or is unsafe to expose

Cause: A page may wait indefinitely on resources, or supplied markup may trigger unwanted file or network access. Fix: Set appropriate operational time limits in your application, restrict renderer access to resources, sanitize untrusted content, and isolate the conversion process. Do not treat wkhtmltopdf as safe for arbitrary HTML/JavaScript.

Performance, reliability, and cost considerations

The authoritative project information cited here does not establish a comparative speed benchmark, so there is no responsible basis for declaring one of these renderers universally faster. Measure with your own representative templates, assets, page lengths, runtime environment, and concurrency. Large images, remote assets, JavaScript work, and font loading can all affect completion time.

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

For reliability, make dependencies explicit and test the exact environment that will run conversions. Validate output files rather than assuming that a successful process exit means the document is visually or semantically correct. If conversion is part of a user-facing request, handle failures and timeouts in your application and avoid unbounded access to remote resources.

WeasyPrint and Puppeteer are open-source libraries/tools; the referenced project information provides no comparative pricing or performance figures for them. Your deployment costs depend on the infrastructure, dependency management, and operational controls you choose. wkhtmltopdf’s listed stable 0.12.6 series dates to June 11, 2020, so compatibility needs should be weighed against its age and the project’s security warning.

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.