wkhtmltopdf Alternative

wkhtmltopdf has been deprecated since January 2023 with unpatched CVEs and no active maintainers. PDFend is a modern, API-first replacement — same input (HTML + CSS), better output, ten-minute migration.

If you landed here, you probably already know the story: the wkhtmltopdf project was archived on GitHub in January 2023 because its QtWebKit dependency is unmaintainable. QtWebKit itself was dropped by the Qt team in 2016. The result is a binary that embeds an abandoned browser engine with multiple open CVEs, no Flexbox, no Grid, and memory leaks that get worse over time. Teams keeping wkhtmltopdf in production today are doing so with crossed fingers.

PDFend was built to be the obvious migration target. Same mental model — you send HTML, you get a PDF — but the rendering happens on current Chromium, running in our managed infrastructure, reachable with a single HTTP POST.

Head-to-head comparison

The short version: wkhtmltopdf was best-in-class in 2015 and has not meaningfully changed since. PDFend is what you would build if you started today.

wkhtmltopdf

  • Archived on GitHub (Jan 2023)
  • Based on QtWebKit (frozen at 2013 WebKit)
  • No Flexbox, no Grid, no CSS custom properties
  • Static binary dependency per platform
  • Memory leaks under load
  • Known unpatched CVEs
  • No SDK — CLI only
  • No managed infrastructure

PDFend

  • Actively maintained, patched automatically
  • Modern Chromium — same engine as Chrome and Edge
  • Full CSS3 including Flexbox, Grid, custom properties
  • No dependencies — pure HTTP
  • Horizontal scaling, per-request isolation
  • TypeScript, Python SDKs and MCP server
  • Webhooks, async mode, logs dashboard
  • Free tier with 100 PDFs/month

Migration in three steps

Most migrations are a one-function change: replace the shell-out to wkhtmltopdf with an HTTP POST, keep your existing HTML templates, verify the output. We'll show the common stacks side-by-side.

1. Get a free API key

Sign up at pdfend.com/sign-up, create an API key in the dashboard. No credit card required.

2. Replace your wkhtmltopdf call

Node.js

// Before — spawning wkhtmltopdf as a subprocess
spawnCliTool("wkhtmltopdf", ["-", "output.pdf"], html);
const pdf = await fs.readFile("output.pdf");

// After — PDFend
import { PDFend } from "@pdfend/sdk";
const pdfend = new PDFend(process.env.PDFEND_API_KEY!);
const { url } = await pdfend.generate({ html });

Python (Django)

# Before — pdfkit (wkhtmltopdf wrapper)
import pdfkit
pdf = pdfkit.from_string(html, False)

# After — PDFend
from pdfend import PDFend
client = PDFend(os.environ["PDFEND_API_KEY"])
result = client.generate(html=html)
pdf_url = result["url"]

Ruby (Rails)

# Before — wicked_pdf
pdf = WickedPdf.new.pdf_from_string(html)

# After — PDFend via net/http
uri = URI("https://api.pdfend.com/v1/generate")
req = Net::HTTP::Post.new(uri,
  "Authorization" => "Bearer #{ENV['PDFEND_API_KEY']}",
  "Content-Type" => "application/json")
req.body = { html: html }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
pdf_url = JSON.parse(res.body)["url"]

PHP (Laravel)

// Before — snappy/wkhtmltopdf
$pdf = PDF::loadHTML($html)->output();

// After — PDFend via Guzzle
$res = Http::withToken(env('PDFEND_API_KEY'))
    ->post('https://api.pdfend.com/v1/generate', ['html' => $html]);
$pdfUrl = $res->json('url');

3. Download or redirect

PDFend returns a signed URL. You can download the PDF server-side and attach it to an email, redirect the user, or store the URL in your database.

Why you should migrate now

01

Chromium, not QtWebKit

wkhtmltopdf's QtWebKit is frozen at WebKit 538 (circa 2013). PDFend runs the same Chromium your users browse with today.

02

No binary to package

No 40 MB static binary in your Docker image, no font-config headaches, no xvfb. PDFend is an HTTP call.

03

Actually supports Flexbox and Grid

wkhtmltopdf predates both. Modern layouts that work in every browser simply break in wkhtmltopdf — PDFend renders them correctly.

04

CVE-free and maintained

wkhtmltopdf has known unpatched CVEs since 2023. PDFend's rendering pipeline is patched automatically.

05

Scales horizontally

wkhtmltopdf leaks memory under load and needs process restarts. PDFend isolates every render and auto-scales workers.

06

Modern developer experience

Typed SDKs for TypeScript and Python, Mintlify-style docs, a dashboard, API keys, webhooks, logs. wkhtmltopdf has a CLI.

Common migration scenarios

case · 01

A PHP app shelling out to wkhtmltopdf

Replace the shell call with a single Guzzle POST. No more process supervision, no more /tmp file cleanup, no more CPU contention with your web workers.

case · 02

A Rails app using the wicked_pdf gem

wicked_pdf wraps wkhtmltopdf and inherits all its problems. Swap it for a Ruby HTTP client calling PDFend — the same ERB templates, a more reliable render.

case · 03

A Python service on an old Ubuntu image

Apt-installed wkhtmltopdf is stuck on a patched-until-2020 package. Move to PDFend and you can ship a 50 MB Alpine image with just your code.

case · 04

A Kubernetes cluster running wkhtmltopdf sidecars

You're paying for Chromium replacements every time a pod OOMs. PDFend runs the renderer fleet for you — your cluster goes back to running your product.

Migration gotchas

A handful of wkhtmltopdf behaviors differ from browsers enough that pixel-exact migrations need attention. None are blockers.

  • Inline-block margin rounding. wkhtmltopdf rounded sub-pixel margins differently from Chromium. A layout that looked perfect in wkhtmltopdf may shift by 1-2px in the migrated version.
  • --disable-smart-shrinking.wkhtmltopdf's “smart” content-aware scaling is off by default on PDFend. Use options.scale to adjust.
  • Header/footer HTML passed via files. wkhtmltopdf expected separate HTML files; PDFend takes them inline as strings. Inline your templates into the request body.
  • JavaScript timing. PDFend waits for network idle before printing, so async charts render correctly — but if your page has an infinite polling loop, it will hit the 30-second sync timeout. Use DOMContentLoaded or skip polling for print mode.
FAQ

Frequently asked questions.

01Why was wkhtmltopdf deprecated?
+
The project was archived in January 2023 due to its unmaintainable QtWebKit dependency. QtWebKit itself has been abandoned since 2016 and carries multiple unpatched CVEs. Running wkhtmltopdf in production today means running unpatched browser code with network access.
02How long does migration take?
+
Usually 30 to 90 minutes. Most migrations are one function — the one that calls wkhtmltopdf — replaced with an HTTP POST. The HTML templates themselves need no changes. Integration testing is the slowest part: verify a dozen representative documents render identically.
03Will my wkhtmltopdf-specific CSS still work?
+
The opposite — PDFend handles modern CSS that wkhtmltopdf could not render correctly, so Flexbox, Grid, CSS variables, and modern selectors all start working. A handful of wkhtmltopdf quirks (odd rounding, broken inline-block margins) go away, which may shift pixel-exact layouts slightly.
04What about wkhtmltopdf's CLI-only features like --cookie-jar?
+
PDFend supports custom request headers, and for authenticated fetches you typically render the HTML in your own app (with your cookies/session) and send the finished HTML string to PDFend. That is usually simpler than replaying cookies.
05Is PDFend really cheaper than self-hosting wkhtmltopdf?
+
For most teams, yes. A kubernetes pod running wkhtmltopdf costs $20–40/month including ops overhead, and does not cover the engineer time fixing zombie processes at 3am. PDFend starts at $0 (100 PDFs free) and $19/month for 2,000 PDFs.
06Can I self-host PDFend if I absolutely cannot send HTML off-prem?
+
Yes. Enterprise plans include on-prem deployment with the same API surface. Point the SDK at your internal URL and it behaves identically to the hosted service.
07What about footers with page numbers — wkhtmltopdf had --footer-center?
+
PDFend supports HTML footers with {{page}} and {{pages}} tokens, plus full CSS styling — more flexible than wkhtmltopdf's fixed --footer-center strings. You can have different content on the first page, right-align, include logos, anything you would do in normal HTML.
08Does PDFend support PDF/A for archival compliance?
+
PDF/A conversion is on our roadmap for 2026. If you need it today, talk to us — we can post-process with Ghostscript in the pipeline for enterprise customers, which wkhtmltopdf required setting up manually anyway.
Keep reading

Related pieces.

Leave wkhtmltopdf behind

Free forever for 100 PDFs a month. Ten-minute migration. Same HTML in, a cleaner PDF out.