Skip to content

HTML to PDF library vs API: when to stop self-hosting Puppeteer

The library is free until you own the headless Chrome fleet behind it. Here is the real bill: memory leaks, font drift, on-call pages, and the point where an API wins.

Every HTML to PDF library looks free on the day you install it. npm install puppeteer takes thirty seconds, the first invoice renders perfectly on your laptop, and the ticket gets closed. The real bill arrives later, in production, spread across memory graphs, Docker font packages, and on-call pages at 2 a.m. This post lays out what the major libraries actually do well, where they break, and the point where paying for an API stops being a luxury and starts being cheaper than your own time.

To be clear up front: libraries are the right answer for plenty of teams. If you render a handful of simple documents a day and someone on the team enjoys owning the stack, self-hosting is fine. The problem is that most teams make the decision once, at toy scale, and never re-run the math when volume grows.

The HTML to PDF library landscape in 2026

There are really three families of tools, and they fail in different ways.

Headless browsers: Puppeteer and Playwright

Puppeteer and Playwright drive a real Chromium instance and call its print-to-PDF function. This is the gold standard for fidelity: real CSS grid, real flexbox, real web fonts, real JavaScript. If the page looks right in Chrome, the PDF looks right too. That is exactly why an API built on the same engine can promise the same output; the hard part was never the rendering, it was running the browser fleet behind it.

The cost is that you are now operating browsers as infrastructure. A single Chromium instance idles around 100 to 300 MB and can spike far past that on a heavy page. Chromium processes leak and zombie under load, so every serious deployment ends up with a process reaper, a restart-after-N-renders policy, and a queue in front of the whole thing to cap concurrency.

Standalone engines: wkhtmltopdf and WeasyPrint

wkhtmltopdf wraps an ancient Qt WebKit build. It is fast and light, but its engine froze years ago: no CSS grid, shaky flexbox, and page-break bugs that slice table rows in half. The upstream project announced it is no longer maintained (the full picture, including the unpatched SSRF vulnerability and the migration paths per stack, is in our wkhtmltopdf alternative breakdown), which means every new CSS feature widens the gap between what your designers write and what the PDF shows. WeasyPrint is a much healthier choice for paginated documents, with genuinely good support for print CSS like page-break-inside and running headers, but it deliberately does not execute JavaScript. If your template is a React page or pulls data client-side, WeasyPrint sees an empty shell. If avoiding a browser process is the actual goal, rather than a side effect, the trade between a pure-code engine and a hosted renderer is laid out in HTML to PDF without headless Chrome.

In-browser generators: jsPDF and friends

jsPDF builds a PDF in the user's browser by drawing text and shapes onto a canvas-like API. It is great for small client-side jobs, and it is the honest way to build a no-backend demo (our own in-browser HTML to PDF converter works this way, free, no signup). But it does not print your actual DOM with your actual stylesheet; anything complex has to be re-described by hand, and selectable text, accessibility, and pagination all get worse the harder you push it.

Library comparison at a glance

Library Engine JS support Fidelity Biggest operational risk
Puppeteer Bundled Chromium Full Excellent Memory leaks, zombie processes, fleet ops
Playwright Chromium / WebKit / Firefox Full Excellent Same fleet ops, plus browser version churn
wkhtmltopdf Frozen Qt WebKit Partial, dated Poor on modern CSS Unmaintained; page-break and layout bugs
WeasyPrint Own layout engine None Very good for print CSS Cannot render JS-driven pages
jsPDF Client-side drawing N/A Low for real pages Hand-built layout drifts from the site

What self-hosting an HTML to PDF library really costs

The license fee is zero. Everything else is not. These are the failure modes that show up on almost every self-hosted Chromium deployment we have seen or run ourselves.

  • Memory leaks and OOM kills. Long-lived browser processes accumulate memory until the kernel kills them mid-render. The standard fix, recycling browsers every N pages, is code you write, test, and maintain forever.
  • Font and emoji drift. Your laptop has every font; your Alpine container has almost none. Missing fonts-liberation, fonts-noto-cjk, or an emoji font turns customer names into tofu boxes. Nobody notices until a customer in Tokyo opens their invoice.
  • Render drift after Chrome releases. Chromium ships a new major version roughly every four weeks. Line-height rounding, form control styling, and font metrics shift just enough that a table that fit on one page now spills onto two. Pinning the browser fixes drift and creates a security-patching problem instead.
  • Page-break bugs. CSS fragmentation is the least-tested corner of every engine. Headers orphaned at the bottom of a page, table rows split through the middle, backgrounds that vanish after page one: each is an afternoon of trial and error with break-inside: avoid.
  • Cold starts and concurrency. Launching Chromium takes real seconds. Keep a warm pool and you pay for idle memory around the clock; launch on demand and your p99 latency is ugly. In serverless environments, browser binary size alone pushes you into workarounds.
  • Security surface. A headless browser that renders untrusted HTML is a remote-code-execution target that can also reach your internal network unless you sandbox and egress-filter it. That is firewall work, not a config flag.

Put rough numbers on it, framed as the generic estimate it is: if the stack eats a few engineer-days a month in patching, debugging, and incident response, that is easily four figures of loaded cost monthly before you count servers. A typical mid-tier rendering API costs less than one of those engineer-days. The math is rarely close once volume is real; what keeps teams self-hosting is that the cost is invisible, smeared across sprints instead of appearing on one invoice.

When a library is still the right call

Honesty cuts both ways, so here is the case for staying self-hosted:

  • Volume is tiny and stable, and renders are simple enough that wkhtmltopdf or WeasyPrint quirks never bite.
  • Your data cannot leave your network for regulatory reasons, full stop.
  • You already run a browser farm for testing or scraping and PDF rendering rides along on paid-for infrastructure.
  • You need exotic control deep inside the browser that no API exposes.

If none of those describe you, and you are generating invoices, reports, receipts, or contracts on a growth curve, the fleet will win eventually. It always does.

When an API wins, and what to demand from one

An HTML to PDF API earns its fee when it removes the whole operational layer: browser patching, font management, queueing, scaling, and the on-call rotation. When you evaluate one, ask for real Chromium rendering (so output matches what Chrome shows), both URL to PDF and raw-HTML input, control over page size, margins, headers and footers, a wait-for-selector option for JS-heavy pages, and transparent per-render pricing you can forecast.

Then ask the question most vendors cannot answer: what happens to the page after the render? For a lot of PDF use cases, invoices, terms at time of signup, published prices, the document is also evidence, and evidence needs a dated, retrievable copy, not just a file emailed into the void. We wrote up why in how to convert a web page to PDF and keep a dated copy, and the compliance angle in more depth in our post on website archiving for compliance.

What we are building at Sitepdf

Sitepdf is our answer to both halves of that problem: an HTML to PDF API where every render is also archived as a timestamped, retrievable snapshot of the source page. One call returns the PDF and stores the record, so engineering gets rid of the Chromium fleet and compliance gets an archive without a second tool. It is in early access, not launched: there are no live API keys yet, and we will not pretend otherwise. What is live today is the free in-browser converter, and early-access signups lock in the planned launch pricing. If you are mid-migration off a self-hosted library and want the render and the record from one endpoint, that is exactly the team we want to hear from.

Written by the team building Sitepdf, an HTML to PDF API that archives every page it renders. The in-browser converter is free to try; early access locks the launch pricing.

§ Early access

Get on the early-access list

The API opens to the list first, in order. Early access locks the planned launch rates for 12 months. No card required, launching soon.

Render + archive, one API