Why wkhtmltopdf needs replacing
For years wkhtmltopdf was the default way to turn HTML into PDF from a command line. It is open source under the LGPL-3.0 licence, and it still runs on many servers. But the project has stopped.
- The repository is archived. It became read-only on GitHub on 2 January 2023, so no fixes are coming.
- The engine is old. It uses Qt WebKit. The project itself says its Qt 4 base has been unsupported since 2015 and its WebKit was last updated in 2012.
- Untrusted HTML is a risk. The project advises against using it with HTML you do not fully control, such as content your users can edit.
The old engine is why flexbox and grid layouts often come out wrong, and why web fonts can be hard to get right. The safety warning matters most if your invoices or reports include text that customers type.
Prices side by side
The cheapest monthly plan that includes each volume, from each vendor's public pricing page (checked October 2026, before tax). Where a vendor sells extra documents on a smaller plan, that can cost less than the plan shown; the text below works it out where it matters. CastPDF counts one PDF per document, whatever its page count.
| PDFs a month | CastPDF | wkhtmltopdf | Puppeteer | Gotenberg | PDFShift | DocRaptor |
|---|---|---|---|---|---|---|
| 1,000 | $19 (Starter) | Free software; you run the servers | Free software; you run the servers | Free software; you run the servers | $24 (Boost) | $75 (Premium) |
| 10,000 | $49 (Growth) | Free software; you run the servers | Free software; you run the servers | Free software; you run the servers | $99 (Business) | $399 (Bronze) |
| 50,000 | $129 (Pro) | Free software; you run the servers | Free software; you run the servers | Free software; you run the servers | $149 (Shift 50k) | Custom price |
| Free plan | 100 PDFs a month | Free software | Free software | Free software | 50 credits a month | 5 documents a month, plus unlimited watermarked test documents |
PDFShift: One credit is one document per 5 MB of output.
How this list is ordered
wkhtmltopdf is free and runs on your own machines, so we start with replacements that keep that model. Self-hosted tools come first, from the most flexible to the most focused. Hosted APIs follow, ordered by entry price for 1,000 documents a month.
CastPDF is our product. By that rule it sits fourth, as the first hosted option, because its plan for 1,000 PDFs is the cheapest of the three hosted APIs listed.
Six maintained alternatives
1. Puppeteer or Playwright
- Best for: Node.js teams that want full control and already run servers.
- Strength: a current browser engine. Puppeteer (Apache-2.0) controls Chrome or Firefox; Playwright drives Chromium, Firefox and WebKit, and prints PDFs with Chromium.
- Weakness: you run the browsers. Memory, crashes, fonts in containers and browser upgrades are your job.
- Price at 1,000 PDFs a month: Free software; you run the servers.
2. Gotenberg
- Best for: teams in any language that want an HTTP service on their own infrastructure.
- Strength: a ready Docker container (MIT licence) with Chromium, LibreOffice and other engines behind one API.
- Weakness: it is still a service to deploy, scale, monitor and update.
- Price at 1,000 PDFs a month: Free software; you run the servers.
3. WeasyPrint
- Best for: Python projects that print documents from HTML and CSS without JavaScript.
- Strength: a Python library with its own layout engine and solid support for CSS paged media, such as page margins and page counters.
- Weakness: it does not run JavaScript, so pages that build content or charts in the browser need another tool.
- Price at 1,000 PDFs a month: free software; you run it.
4. CastPDF
- Best for: invoices, statements and reports where page breaks have to be right, without running any rendering servers.
- Strength: Chromium with a print mode that repeats table headers, keeps rows whole and fills
@pagemargin boxes with page numbers. Templates with Liquid are optional. - Weakness: it is a hosted service, so documents leave your network for servers in Germany. It cannot read local files.
- Price at 1,000 PDFs a month: $19 (Starter), with 100 free live PDFs a month.
5. PDFShift
- Best for: converting finished HTML or a live URL, the way wkhtmltopdf converts a page.
- Strength: a Chromium converter with nothing to set up beyond an API key.
- Weakness: no templates, and each credit covers up to 5 MB of output, so large PDFs count more than once.
- Price at 1,000 PDFs a month: $24 (Boost).
6. DocRaptor
- Best for: complex print layouts and documents that need accessibility tagging.
- Strength: the Prince engine, made for print layout, with tagging aimed at WCAG 2.0, Section 508 and PDF/UA.
- Weakness: the highest price of the hosted options at most volumes.
- Price at 1,000 PDFs a month: $75 (Premium).
Comparison table
| Tool | Runs where | Engine | Runs JavaScript |
|---|---|---|---|
| wkhtmltopdf | Your servers | Qt WebKit (last updated 2012) | Yes, old engine |
| Puppeteer or Playwright | Your servers | Current Chromium | Yes |
| Gotenberg | Your servers (Docker) | Chromium, LibreOffice and others | Yes, in Chromium |
| WeasyPrint | Your servers | Its own layout engine | No |
| CastPDF | Hosted (Germany) | Chromium, with Paged.js in print mode | Yes, within render limits |
| PDFShift | Hosted | Chromium | Not stated on the pricing page |
| DocRaptor | Hosted | Prince | Yes, through Prince |
Picking the right one
- Documents must never leave your servers: Gotenberg for an HTTP service, Puppeteer or Playwright inside a Node.js app, WeasyPrint inside a Python app.
- You want to stop running rendering servers altogether: a hosted API. CastPDF and PDFShift both run Chromium, so modern CSS works.
- Your documents are long, with tables and page numbers: CastPDF print mode or DocRaptor. Test your longest file in both.
- You render HTML that users can edit: move first, whatever you pick. The archived engine is the weakest link.
One point in favour of hosted services: CastPDF’s renderer refuses requests to private and loopback addresses, and caps downloads per document. With a self-hosted browser, that filtering is yours to build.
Workarounds you can usually delete
Templates that have lived with wkhtmltopdf for years tend to collect fixes for its old engine. When you move to a current engine, most of them stop being needed, and some get in the way.
- Prefixed flexbox. Old
display: -webkit-boxrules were often added because modern flexbox was not supported. Plaindisplay: flexandgridwork in Chromium. - Tables split by hand. Some teams cut long tables into chunks of a fixed number of rows to fake a repeating header. In CastPDF print mode, one table with a
<thead>does the job. - Scripts in the header file. Header and footer files often read the page number from the URL with JavaScript. Margin boxes with
counter(page)replace that script. - Zoom and shrink tweaks. Flags that scale the page to correct its size can go. Set the page size and margins and let the CSS decide the rest.
- Delays for slow content. Long waits for charts or fonts can usually be shortened, since the renderer waits for fonts before it prints.
Remove these one at a time and compare the output after each change. A cleaner template is also easier for the next person to edit.
Mapping wkhtmltopdf flags to CastPDF
Most wkhtmltopdf commands use a handful of flags. Each one has a direct equivalent in the request body or in your CSS.
| wkhtmltopdf | CastPDF |
|---|---|
--page-size A4 (or -s) | "format": "A4" (also A5, Letter, Legal or a custom width and height) |
--orientation Landscape | "orientation": "landscape" |
--margin-top, --margin-bottom, --margin-left, --margin-right | One "margins" string in CSS order, such as "25mm 15mm 20mm" |
--header-html, --footer-html | @page margin boxes in your CSS, with "mode": "print" |
[page] and [topage] in a header or footer | counter(page) and counter(pages) |
--enable-local-file-access | No local files: use public https URLs or embed files as data: URLs |
| Input file and output file | The html field in, the PDF in the response body out |
Before and after
Here is a typical invoice command with a header file and a numbered footer.
wkhtmltopdf \
--page-size A4 \
--margin-top 25mm --margin-bottom 20mm \
--margin-left 15mm --margin-right 15mm \
--header-html header.html \
--footer-center "Page [page] of [topage]" \
--footer-font-size 8 \
invoice.html invoice.pdfIn CastPDF, the header and footer move into a small stylesheet. The page counters replace the bracket placeholders.
@page {
@top-right { content: "Northwind Traders, Invoice"; font-size: 8pt; color: #334155; }
@bottom-center { content: "Page " counter(page) " of " counter(pages); font-size: 8pt; }
}
.totals { break-inside: avoid; }Then one curl command replaces the binary. It uses jq to put both files into the JSON body.
jq -n --rawfile html invoice.html --rawfile css print.css \
'{html: $html, css: $css, mode: "print", format: "A4", margins: "25mm 15mm 20mm"}' |
curl https://api.castpdf.com/v1/pdf \
-H "Authorization: Bearer $CASTPDF_API_KEY" \
-H "Content-Type: application/json" \
--data @- \
--fail-with-body \
--output invoice.pdf- Create a test key. Sign up free and create a test key; the quickstart shows where. Test PDFs are watermarked and never billed.
- Move header and footer into CSS. Rewrite
header.htmland the footer flags as margin boxes, as inprint.cssabove. - Replace local file paths. Point images and fonts at public
httpsURLs, or embed them asdata:URLs. - Run the curl command. Compare the new PDF with the old one. Expect flexbox and grid to look better, since the engine is current.
- Check long tables. Put header rows in a
<thead>so print mode repeats them. The guide to page breaks in HTML to PDF covers the rest.
Once the output matches, switch to a live key and remove wkhtmltopdf from your servers. Plans start at $19 a month for 2,500 PDFs; the pricing page lists them all. Renders time out after 30 seconds, so give your HTTP client at least 60.
Sources
Every fact about another product on this page comes from that product's own pages, checked October 2026. CastPDF's prices and limits come from our pricing page.
| wkhtmltopdf | What it says | Source |
|---|---|---|
| Status | The GitHub repository was archived (read-only) on 2 January 2023 | github.com/wkhtmltopdf/wkhtmltopdf |
| Engine | Qt WebKit; the project says its Qt 4 base is unsupported since 2015 and its WebKit was last updated in 2012 | wkhtmltopdf.org/status.html |
| Security note | The project advises against using it with untrusted HTML | wkhtmltopdf.org/status.html |
| Licence | LGPL-3.0 | github.com/wkhtmltopdf/wkhtmltopdf |
| Puppeteer | What it says | Source |
|---|---|---|
| What it is | A JavaScript library that controls Chrome or Firefox | pptr.dev |
| Licence | Apache-2.0 | github.com/puppeteer/puppeteer |
| Headers and footers | page.pdf() takes headerTemplate and footerTemplate with pageNumber and totalPages classes (needs displayHeaderFooter) | pptr.dev/api/puppeteer.pdfoptions |
| Gotenberg | What it says | Source |
|---|---|---|
| What it is | A self-hosted API you run as a Docker container | gotenberg.dev |
| Engines | Chromium, LibreOffice and other PDF engines | gotenberg.dev |
| Licence | MIT | gotenberg.dev |
| PDFShift | What it says | Source |
|---|---|---|
| Free plan | 50 credits a month | pdfshift.io/pricing |
| How usage counts | One credit per document, counted per 5 MB of output | pdfshift.io/pricing |
| Extra credits | From $40 per 1,000 (Starter) down to $15 per 1,000 (Shift 50k) | pdfshift.io/pricing |
| Engine | Chromium | pdfshift.io |
| Templates | None: you send finished HTML or a URL | pdfshift.io/pricing |
| DocRaptor | What it says | Source |
|---|---|---|
| Free plan | 5 documents a month, plus unlimited watermarked test documents | docraptor.com/signup |
| Extra documents | A per-document price tied to your plan (the rates are not on the page) | docraptor.com/signup |
| Above 40,000 a month | Enterprise, custom price | docraptor.com/signup |
| Engine | Prince, a commercial engine made for print layout | docraptor.com |
| Accessibility | Automatic and CSS-based tagging, aimed at WCAG 2.0, Section 508 and PDF/UA | docraptor.com |
| JavaScript | Runs JavaScript through Prince, with several layout passes | docraptor.com |