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
Chromium, not QtWebKit
wkhtmltopdf's QtWebKit is frozen at WebKit 538 (circa 2013). PDFend runs the same Chromium your users browse with today.
No binary to package
No 40 MB static binary in your Docker image, no font-config headaches, no xvfb. PDFend is an HTTP call.
Actually supports Flexbox and Grid
wkhtmltopdf predates both. Modern layouts that work in every browser simply break in wkhtmltopdf — PDFend renders them correctly.
CVE-free and maintained
wkhtmltopdf has known unpatched CVEs since 2023. PDFend's rendering pipeline is patched automatically.
Scales horizontally
wkhtmltopdf leaks memory under load and needs process restarts. PDFend isolates every render and auto-scales workers.
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
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.
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.
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.
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.scaleto 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
DOMContentLoadedor skip polling for print mode.
Frequently asked questions.
01Why was wkhtmltopdf deprecated?+
02How long does migration take?+
03Will my wkhtmltopdf-specific CSS still work?+
04What about wkhtmltopdf's CLI-only features like --cookie-jar?+
05Is PDFend really cheaper than self-hosting wkhtmltopdf?+
06Can I self-host PDFend if I absolutely cannot send HTML off-prem?+
07What about footers with page numbers — wkhtmltopdf had --footer-center?+
08Does PDFend support PDF/A for archival compliance?+
Related pieces.
What PDFend's /v1/generate endpoint accepts and returns.
Another migration target if you're evaluating managed PDF APIs.
Sign up, make your first call, download the PDF — all in under a minute.
Free tier of 100 PDFs/month. Paid plans start at $19/mo.
Leave wkhtmltopdf behind
Free forever for 100 PDFs a month. Ten-minute migration. Same HTML in, a cleaner PDF out.