A wkhtmltopdf alternative for modern HTML

wkhtmltopdf served a generation of apps well. But its GitHub repository was archived in January 2023, and it renders with a QtWebKit engine from the mid-2010s. Flexbox is unreliable, CSS grid and CSS variables don't work, modern JavaScript fails silently, and nobody ships security fixes anymore.

Symptoms you've outgrown it

The replacements, honestly compared

OptionGood forTrade-off
Puppeteer / Playwright page.pdf()Full control, same engine as ChromeYou run and patch headless Chromium (~300MB, memory spikes, fonts)
Gotenberg (Docker)Self-hosted HTTP API around Chromium and LibreOfficeOne more service to deploy, scale and update
WeasyPrint (Python)Excellent CSS paged media: running headers, page countersIts own engine: no JavaScript, some layout differences from browsers
A hosted API (Shotmint, PDFShift, …)No browser to operate, one HTTP callYour HTML goes over the network to a third party; costs per document

If you need JavaScript-rendered content and browser-identical layout, choose a Chromium option. If you need advanced print features (running headers, footnotes, counter(page)), WeasyPrint is hard to beat.

Before and after

# Before: wkhtmltopdf
wkhtmltopdf --page-size A4 -O Landscape --print-media-type input.html out.pdf

# After: one HTTP call (Chromium)
curl -X POST https://shotmint.creasework.com/v1/pdf \
  -H "X-API-Key: $SHOTMINT_KEY" -H "Content-Type: application/json" \
  --data-binary @<(jq -Rs '{html: ., format: "A4", landscape: true}' input.html) \
  -o out.pdf

Python (replacing pdfkit)

# Before
import pdfkit
pdfkit.from_string(html, "out.pdf", options={"page-size": "Letter", "margin-top": "15mm"})

# After
import os, requests
r = requests.post("https://shotmint.creasework.com/v1/pdf",
    headers={"X-API-Key": os.environ["SHOTMINT_KEY"]},
    json={"html": html, "format": "Letter", "margin": "15mm"}, timeout=60)
r.raise_for_status()
open("out.pdf", "wb").write(r.content)

Node.js (replacing wkhtmltopdf / html-pdf wrappers)

const r = await fetch("https://shotmint.creasework.com/v1/pdf", {
  method: "POST",
  headers: { "X-API-Key": process.env.SHOTMINT_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ html, format: "A4", margin: "10mm" }),
});
if (!r.ok) throw new Error(await r.text());
require("fs").writeFileSync("out.pdf", Buffer.from(await r.arrayBuffer()));

Option mapping

wkhtmltopdfShotmint /v1/pdf
--page-size A4format=A4 (A3, A4, A5, Letter, Legal, Tabloid)
-O Landscapelandscape=true
-T -B -L -R 10mmmargin=10mm (all sides). For different sides, pass margin=0mm and set @page { margin: … } in CSS
--no-backgroundprint_background=false
--zoom 0.8scale=0.8
default (screen CSS)screen_media=true
--print-media-typedefault (print CSS)
--javascript-delay 1000delay=1000, or wait_until=networkidle
--custom-header User-Agent …user_agent=…
--header-html, --footer-html, --tocNot supported. Put the header in your HTML; a <thead> repeats on every page

Migration gotchas

Want to see the output first? Paste HTML into the free HTML to PDF converter (no key needed).

What it costs

One PDF = one credit, whatever the page count. €5 buys 2,000 PDFs, credits never expire and there's no subscription. Failed renders are refunded automatically. Compare that with running a Chromium container around the clock for a few hundred documents a month.

Try it with 100 free renders

No signup, no card. Get a key in one click, then buy credits only if you need more (from €5 for 2,000, never expire).

Get a free API key Full API reference