wkhtmltopdf alternative: PDFik vs wkhtmltopdf
wkhtmltopdf served a generation of invoice generators, but its GitHub repository was archived on January 2, 2023 — no maintainers, no releases, and an unpatched critical vulnerability (CVE-2022-35583, CVSS 9.8) that will never be fixed. Its Qt WebKit engine predates CSS Grid, modern Flexbox and most of ES6. This page is an honest comparison: where the old tool still wins, and how migration actually looks.
Quick verdict
Stay on wkhtmltopdf if:
- your environment is air-gapped or offline — a hosted API cannot help there;
- you render only fully trusted input, your legacy ES5-era templates already look right, and $0 matters more than maintenance;
- documents must never leave your infrastructure for compliance reasons.
Choose PDFik if:
- your templates use modern CSS — Grid, Flexbox, web fonts, variables — which Qt WebKit silently mangles;
- you render user-supplied HTML or URLs and do not want to own an unpatched SSRF CVE: PDFik runs every job in sandboxed Chromium with request-level SSRF filtering;
- you want an async queue, signed webhooks with retries, and a status page instead of babysitting a binary.
Feature matrix
| Capability | wkhtmltopdf | PDFik |
|---|---|---|
| Rendering engine | Qt WebKit (frozen ~2015) | Headless Chromium (current) |
| CSS Grid / modern Flexbox | No | Yes |
| Modern JavaScript (ES6+) | No (ES5 era) | Yes |
| Maintained | No — archived Jan 2023 | Yes |
| Known critical CVE | CVE-2022-35583, unpatched | — |
| Runs offline / air-gapped | Yes | No |
| License cost | Free (LGPL) | Free tier, paid plans from $29/mo |
| Async queue + signed webhooks | No (build your own) | Built in, HMAC-signed, on every plan |
| Sandboxing of untrusted input | Your responsibility | Sandboxed Chromium + SSRF filtering |
| Headers / footers | Yes (flags) | Yes (HTML templates, all plans) |
| Official SDKs | Community wrappers | JavaScript/TypeScript, Python, Java |
| Existing wkhtmltopdf command lines | Native | pdfik wkhtmltopdf compatibility mode (CLI) |
| SLA | — | 99.9% on paid plans |
Pricing, honestly
wkhtmltopdf is free software — an API cannot beat $0 on license price. What you pay for is what you stop doing: patching a dead dependency, running render servers, building queues and retry logic, and carrying the security risk of an unfixable CVE. PDFik's pricing is fully published:
| Plan | Monthly | PDFs / month | Generated data | Derived $ per 1,000 PDFs* |
|---|---|---|---|---|
| Free | $0 (no card needed) | 100 | 0.5 GB | — |
| Starter | $29 ($23 annual) | 5,000 | 10 GB | $5.80 |
| Pro | $99 ($79 annual) | 50,000 | 50 GB | $1.98 |
| Business | $449 ($359 annual) | 500,000 | 300 GB (+$0.55/GB add-on) | $0.90 |
*Derived from the monthly price divided by the plan's PDF quota at full utilization. Downloads never debit the data quota. Full details on the pricing page.
The Free plan needs no credit card. Sign up, create a key, and render 100 PDFs and 0.5 GB of output a month on the same engine and the same signed webhooks as every paid plan — and test mode exercises the whole pipeline for free without touching that quota.
Migration guide: flags → options
| wkhtmltopdf flag | PDFik request option |
|---|---|
-s A4 / --page-size | options.format: "A4" |
-O Landscape / --orientation | options.landscape: true |
-T/-B/-L/-R 10mm (margins) | options.margin: { top, bottom, left, right } |
--background / --no-background | options.print_background: true|false |
--header-center / --footer-html … | options.header_template / options.footer_template (HTML, with pageNumber/totalPages classes) |
--javascript-delay | render block: timeouts and wait selectors (Pro+) |
Before — a cron job shelling out to a binary:
wkhtmltopdf -s A4 -O Landscape -B 10mm -T 10mm \
https://example.com invoice-42.pdfAfter — one HTTP call, then a signed webhook (or polling):
curl -X POST https://api.pdfik.net/url-to-pdf \
-H "X-API-Key: sk_live_YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"options": { "format": "A4", "landscape": true,
"margin": { "top": "10mm", "bottom": "10mm" } },
"webhook_url": "https://your.app/webhooks/pdf"
}'
# => { "job_id": "…", "status": "queued", "detail": "…" }The quickstart walks through the full submit → webhook → download cycle in about 60 seconds, and test mode exercises the whole pipeline for free — it never debits your quota.
Keep your command lines: pdfik wkhtmltopdf
Often the blocker is not the engine but the interface — cron jobs, deploy scripts and wrappers (pdfkit, wicked_pdf, snappy) that all speak wkhtmltopdf's flags, and nobody wants to rewrite them just to retire a binary. The PDFik CLI (one static binary, MIT-licensed, open source) ships a compatibility mode that takes wkhtmltopdf's own command line, so for most scripts the migration is a single alias:
export PDFIK_API_KEY=sk_live_YOUR_API_KEY
alias wkhtmltopdf='pdfik wkhtmltopdf'
# your existing command lines keep working, unchanged:
wkhtmltopdf -s A4 -O Landscape --footer-center 'Page [page] of [topage]' \
https://example.com invoice-42.pdfEvery wkhtmltopdf flag falls into one of three classes: mapped to an API option with the same meaning, accepted with a warning because it has no effect in this pipeline, or refused with a reason because it would change your output. Nothing is quietly ignored, and an unknown flag stops the run before anything is submitted — a bad invocation never costs a render. --version and -h are answered anywhere in the argument list, which is exactly what the wrappers probe for, so pdfkit and wicked_pdf keep calling it the way they always did. The full lists live in COMPATIBILITY.md.
There is a container image too — a few megabytes, with no browser inside:
docker run --rm -e PDFIK_API_KEY --user "$(id -u):$(id -g)" \
-v "$PWD:/work" -w /work ghcr.io/pdfik/cli \
wkhtmltopdf -s A4 https://example.com invoice-42.pdfBe clear about what this is: rendering happens in PDFik's cloud, so it is a hosted API wearing a familiar face. It needs network access and an API key, and it is the wrong answer for air-gapped environments for all the reasons above. The engine is sandboxed Chromium rather than Qt WebKit, so your golden files still need re-approval, and toc / --outline are refused rather than emulated. Exit codes are the CLI's own, not wkhtmltopdf's — see the FAQ below if a script branches on them. You do need a key: the Free plan issues one with no credit card, and --test runs are free on every plan.
FAQ
Is wkhtmltopdf still maintained?
No. The GitHub repository was archived on January 2, 2023 and is read-only. There have been no releases, bug fixes, or security patches since.
Is there a newer wkhtmltopdf release, or a patched build?
No. The last packaged release is 0.12.6.1-3 from May 22, 2023, and the packaging repository that produced it is archived and read-only as well. There is nothing to upgrade to — which is why a scanner flagging wkhtmltopdf has no remediation other than migration.
Is CVE-2022-35583 fixed?
No. The SSRF vulnerability CVE-2022-35583 (CVSS 9.8) affecting wkhtmltopdf 0.12.6 has no patched release, because the project was archived. If your wkhtmltopdf instance ever renders user-supplied HTML or URLs, this risk is permanent.
wkhtmltopdf prints "not found" on Alpine even though the binary is right there. Why?
That message comes from the kernel failing to load the binary's dynamic loader, not from PATH. Official wkhtmltopdf builds link against glibc; Alpine ships musl, so the interpreter the binary asks for does not exist on the image. Running ldd on it shows that in one line. There is no supported fix on Alpine — build on a glibc base, or move off the binary.
The install fails with "Depends: libssl1.1 but it is not installable". What now?
The Dockerfile you copied is fetching a package that links OpenSSL 1.1 onto a base image that ships OpenSSL 3 and no longer carries libssl1.1. Installing the last release on a base it was actually built for is the workaround. Pinning an end-of-life base image, or hand-installing an old libssl, means running an archived renderer on top of an unpatched TLS stack.
Is there a wkhtmltopdf build for Ubuntu 24.04 or Debian 13?
No, and there will not be: the last packaged release is from May 2023 and the packaging repository is archived, which is why apt answers "Unable to locate package wkhtmltopdf". Older .debs may keep installing on a newer base for as long as the dependency chain happens to line up, but every base-image bump is now a gamble on a binary nobody maintains. That is usually the moment to plan the migration instead of the next workaround.
Will my existing templates render identically on PDFik?
Not pixel-for-pixel — and usually that is the point. wkhtmltopdf uses a Qt WebKit engine frozen around 2015; PDFik renders with sandboxed headless Chromium, so modern CSS (Grid, Flexbox, web fonts) works instead of being silently ignored. Test your real templates first: test mode is free on every plan, and the homepage sandbox renders without an account.
Can I keep my existing wkhtmltopdf command lines, pdfkit or wicked_pdf?
Mostly, yes. The PDFik CLI has a wkhtmltopdf compatibility mode that takes wkhtmltopdf's own flags and its input/output arguments, so for most scripts the migration is one shell alias. Every flag is either mapped to an API option, accepted with a warning that it has no effect here, or refused with the reason — never silently ignored — and an unknown flag stops the run before anything is submitted, so a bad invocation never costs a render. The --version and -h probes the wrappers send are answered anywhere in the argument list.
What replaces toc and --outline?
Nothing, honestly. Generated tables of contents and PDF outlines have no first-class equivalent in this pipeline, so the compatibility mode refuses those flags with a reason rather than quietly rendering a document without them. If you depend on them, plan a post-processing step that rebuilds the bookmarks, or drop the feature deliberately — that decision belongs inside the migration, not after it.
What exit codes will my scripts see?
Zero on success and non-zero on failure, as before, but with more detail than wkhtmltopdf gave you: 2 for a usage error caught before anything was submitted, 3 when the render failed on the server (the error code is printed), 4 when the job did not finish within the timeout (the job id is printed, so you can fetch the file later), 1 for request, network or file failures, and 130 on interrupt. These are the CLI's own numbers, not wkhtmltopdf's, so any script branching on a specific non-zero code needs a second look.
Do I need a credit card to try it?
No. The Free plan issues a working API key without a card — 100 PDFs and 0.5 GB of generated data a month, on the same engine and the same signed webhooks as every paid plan. Test-mode runs exercise the whole pipeline for free on every plan and never touch that quota.
Does PDFik have an offline or self-hosted version?
No. PDFik is a hosted API. If your environment is air-gapped or documents may not leave your infrastructure, a hosted API is the wrong tool — that is a legitimate reason to stay on a local renderer.
How do webhooks work compared to running wkhtmltopdf synchronously?
You submit a job and get a job id immediately; rendering happens asynchronously. When the job finishes, PDFik POSTs a signed (HMAC) notification with the download link to your webhook — retried on a 2/5/15/30/60-second ladder (6 attempts) and then parked in a dead-letter queue. Polling endpoints exist too if you prefer.
Further reading
- wkhtmltopdf is archived with an open CVE — a field guide to moving off it — the full decision tree across WeasyPrint, Playwright/Puppeteer, Gotenberg and hosted APIs, including where each of them beats PDFik, plus an eight-step migration checklist.
- wkhtmltopdf in Docker in 2026: musl, libssl1.1, and the ways out — the three container errors in detail, the Dockerfile that still works on amd64 and arm64, fonts, and the exits.
Competitor facts last verified: CVE status 2026-08-07, archive and packaging status 2026-09-07. Found something outdated? Tell us and we'll fix it.