wkhtmltopdf vs WeasyPrint for CSS and Page Layout Support
Compare CSS paged-media support, JavaScript handling, security, and deployment tradeoffs to choose between wkhtmltopdf and WeasyPrint.
Short answer: Choose WeasyPrint when your document depends on CSS Paged Media features such as @page, named pages, page-margin boxes, running elements, or footnotes. Consider wkhtmltopdf when you have a legacy pipeline that relies on its page settings, headers and footers, print-media selection, or JavaScript loading controls. Neither choice guarantees fidelity for every template: render representative documents using the exact versions, builds, fonts, and deployment environment you plan to use.
This comparison is based on the cited documentation and project statements, not a controlled rendering test. There is no universal speed or fidelity winner established by the sources here.
1. Quick decision guide
| Your requirement | Starting point | What to verify |
|---|---|---|
| CSS page-margin boxes, named pages, page selectors, running elements, or footnotes | WeasyPrint | Check the exact properties you use against its documented limits. |
| Existing wkhtmltopdf pipeline with explicit paper, header/footer, print-media, or JavaScript settings | wkhtmltopdf may fit | Record the binary build and verify behavior on the target OS. |
| Untrusted or user-submitted HTML or JavaScript | Do not treat wkhtmltopdf as safe for this input | The project maintainer explicitly warns against using it with untrusted HTML/JS. Sanitize input and isolate rendering; assess a different renderer and threat model. |
| PDF/A or PDF/UA output requirements | Review WeasyPrint’s documented variants | Validate the generated files; the guide cautions that valid output is not guaranteed when chosen features exceed limitations. |
| Highly dynamic JavaScript page capture rather than designed print layout | Evaluate a browser-based workflow against your page | Test timing, network access, fonts, and the exact page state to capture. |
2. CSS and page-layout support
WeasyPrint: designed page layout through CSS
WeasyPrint’s API reference describes CSS 2.1 as well supported and documents CSS Paged Media Level 3 features including @page, :left, :right, :first, and :blank; page-margin boxes; page-based counters with known limitations; page size, bleed and marks; named pages; page selectors; running elements for page margins; and footnotes. This makes it a strong candidate when the page itself is designed with print-specific CSS.
That feature list is not a promise of full browser CSS parity. Documented limitations include the start parameter of element(), compact footnote display, the unset keyword, and parts of multi-column layout. In particular, constrained column height, spanning columns, and column breaks are unsupported, and pagination and overflow behavior for columns have not been seriously tested. Check the reference for every CSS feature your template depends on. See the WeasyPrint API reference.
WeasyPrint’s use-case guide recommends configuring page size and margins with CSS @page. Its example sets A3 landscape with a 3 cm margin. The guide also covers PDF/A and PDF/UA variants and warns that output validity depends on whether the chosen HTML, CSS, and PDF features fit the implementation’s limits. See the WeasyPrint common use cases.
wkhtmltopdf: useful command-line page controls
wkhtmltopdf uses Qt WebKit and exposes practical controls for paper size or dimensions, portrait or landscape orientation, page margins, DPI, page offsets, outlines, headers and footers, and print-media selection. Its settings also include JavaScript enablement, a JavaScript delay, and handling for slow scripts. These are useful controls for an existing workflow, but the existence of a setting does not imply broad support for modern CSS paged media. See the wkhtmltopdf settings reference.
A 2023 Parson AG comparison tested a finite set of paged-media features and marked wkhtmltopdf unsupported for many cases in its table, including the general @page rule and the shown page-size, margin, named-page, page-margin-box, and running-header cases. That is historical evidence about the tested tools and cases, not an evergreen compatibility score. See the 2023 Parson AG comparison.
3. Runnable starting points
These examples create a small local HTML file and render it to PDF. They are starting points, not assertions that every CSS feature will work in every installed build. Install each renderer using its current official instructions and check the installed version before comparing results.
WeasyPrint with print CSS
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Quarterly report</title>
<style>
@page {
size: A4;
margin: 22mm 18mm 20mm;
@top-center { content: "Quarterly report"; }
@bottom-right { content: counter(page); }
}
body { font: 11pt sans-serif; }
h1 { page-break-before: avoid; }
.chapter { page: chapter; }
@page chapter { margin-top: 30mm; }
</style>
</head>
<body>
<h1>Quarterly report</h1>
<p>Replace this text with your report content.</p>
</body>
</html>
weasyprint report.html report.pdf
To render a URL or use the Python API, consult the current WeasyPrint API reference. Confirm that the syntax and features in your actual stylesheet are supported by the installed version.
wkhtmltopdf with command-line settings
cat > report.html <<'HTML'
<!doctype html>
<html>
<head><meta charset="utf-8"><title>Quarterly report</title></head>
<body><h1>Quarterly report</h1><p>Replace this text with your report content.</p></body>
</html>
HTML
wkhtmltopdf --page-size A4 --orientation Portrait --margin-top 20mm --margin-bottom 20mm --print-media-type report.html report.pdf
For a URL, the input can be a URL instead of report.html. Header/footer and JavaScript options are documented in the usage reference. Verify option names with the exact executable you deploy: distribution and patched builds can differ.
4. Compare the tools against your real documents
- Define the required output. List paper size, margins, page numbering, running headers, footnotes, links, PDF/A or PDF/UA constraints, and any required scripts or external assets.
- Build a representative corpus. Include long tables, page-break boundaries, long unbreakable strings, special glyphs, images, SVG, right-to-left text if relevant, and the largest realistic document.
- Pin the environment. Record renderer version, binary source, OS and libraries, installed fonts, locale, and the exact HTML, CSS, and assets. For wkhtmltopdf, note whether the build uses patched Qt.
- Render both candidates. Keep command options, inputs, font installation, and network conditions documented. Save the PDFs and renderer logs.
- Inspect output page by page. Look for clipping, blank pages, changed line wraps, broken glyphs, missing assets, unexpected breaks, incorrect page counters, lost links, and metadata differences.
- Repeat after upgrades. Treat a binary, package, font, or template change as a reason to rerun the same corpus.
This procedure is project-specific validation guidance inferred from documented feature boundaries and build caveats; the cited sources do not provide a current controlled benchmark for your templates.
5. Security, maintenance, and deployment
Untrusted HTML is a serious boundary
The wkhtmltopdf maintainer warns against processing untrusted HTML or JavaScript and advises sanitizing user-supplied input. Treat this as a design constraint if users can control markup, scripts, CSS, or referenced URLs. Sanitization alone may not address every threat in a renderer that can access local files or network resources; use an isolated, least-privilege rendering environment and review the current threat model. The warning is the maintainer’s stated guidance, not an independently measured exploit report. See the official wkhtmltopdf status page.
Check actual maintenance and binary provenance
The wkhtmltopdf downloads page identifies 0.12.6, released June 11, 2020, as the stable series. The project also notes that some capabilities require patched Qt and that distribution builds can differ. These project pages may be stale, so verify current release history and the package you intend to install rather than assuming the reported version describes every available binary. See the downloads page.
For reproducible deployment, pin the renderer and dependencies, install the same font set in development and production, and make remote asset access deliberate. If rendering runs in a service, set resource limits and control which local files and network hosts it can reach. These are deployment practices; they do not imply that either renderer supplies a particular sandbox.
6. Performance, reliability, and cost
The research sources establish no general speed, memory, throughput, or visual-fidelity winner. Measure your own corpus and workload on the target machine. Record cold and warm runs, document size, pages, wall time, peak memory, failure rate, and output differences; do not compare results from different fonts or builds.
For reliability, make rendering jobs observable: preserve renderer errors, input identifiers, version/build information, and output validation results. Apply timeouts and bounded retries only to transient failures; a deterministic layout error will not be fixed by repeating the same render. For large batches, measure queue time and resource use as well as render time.
Both are software renderers you run and package, so budget for integration, deployment, updates, fonts, validation, and maintenance. The dossier provides no comparable license, hosting, or operating-cost figures; check the current project terms and estimate costs from your own workload.
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| WeasyPrint page header or margin box is missing | Unsupported or incorrectly applied paged-media feature, or CSS not loaded | Check the API reference for the exact feature and inspect the rendered PDF with a minimal reproduction. |
| WeasyPrint columns overflow or break unexpectedly | Multi-column pagination has documented limitations | Simplify the layout or use a layout approach within the supported feature set; validate long pages separately. |
| wkhtmltopdf ignores a page layout rule | The requested modern paged-media behavior may not be supported, or the build differs | Check the exact binary and Qt patch state; compare a minimal case with the documented settings and consider a renderer whose documented model matches the requirement. |
| Output differs between a laptop and a server | Different builds, libraries, fonts, locale, or asset access | Record and align package provenance, dependencies, fonts, locale, and network access. |
| Images or styles are absent | Relative paths resolve differently, remote resources are inaccessible, or local-file access differs | Use explicit asset paths or URLs, check renderer logs and network permissions, and include required assets in the deployment. |
| JavaScript-dependent content is missing in wkhtmltopdf | Scripts are disabled, load timing is insufficient, or page behavior is incompatible | Review JavaScript and delay settings in the usage reference; avoid assuming a delay guarantees completion. Prefer static input when possible. |
| PDF has unexpected page count or clipped content | Font substitution, different line wrapping, unsupported CSS, or break behavior | Install the intended fonts, inspect page boundaries, reduce dependence on unsupported features, and add the case to the regression corpus. |
| Rendering user content creates a security concern | Untrusted HTML/JS may access resources or exploit the rendering process | Do not feed untrusted input to wkhtmltopdf as-is; sanitize and isolate rendering, and select a renderer and sandbox appropriate to your threat model. |
8. ScreenshotNeo as an alternative to try first
If your goal is a PDF or screenshot of a live web page rather than rendering your own report template, ScreenshotNeo is a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP, or PDF. It is a different workflow from choosing a local HTML-to-PDF library, so check that its capture output fits your needs.
For a live page PDF, ScreenshotNeo supports paper size, margins, landscape orientation, and page ranges. Other relevant options include full-page capture with lazy images loaded, selector-based element capture, viewport and device presets, custom CSS and JavaScript, wait conditions, cookies and headers, and async jobs with signed webhooks. See the ScreenshotNeo API documentation for parameters and configuration.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.pdf
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com", "format": "pdf"},
timeout=90,
)
r.raise_for_status()
open("shot.pdf", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
format: 'pdf'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.pdf', Buffer.from(await res.arrayBuffer()));
Check the response headers and status for the page verdict and billing outcome. ScreenshotNeo says bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; responses include X-Page-Verdict and X-Billed. Its consent handling accepts cookie banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture, with each step configurable. The MCP server exposes take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 shots a month without a card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month, with no card required.
9. FAQ
Does WeasyPrint support CSS paged media?
Its API reference documents many paged-media features, including page selectors, margin boxes, named pages, running elements, and footnotes, with feature-specific limits.
Does wkhtmltopdf support @page?
Do not infer modern @page support from its paper-size and margin command-line options. Check the exact requirement against your build; the cited 2023 comparison marked the shown @page and related cases unsupported for the tested wkhtmltopdf configuration.
Which one supports CSS headers and footers?
WeasyPrint documents page-margin boxes and running elements for CSS-controlled page furniture. wkhtmltopdf offers header and footer controls through its settings. The mechanisms and resulting layout behavior differ.
Can wkhtmltopdf render JavaScript?
Its settings include JavaScript enablement and load controls such as a delay. That does not guarantee every modern JavaScript application will finish rendering correctly.
Which is safer for untrusted HTML?
The wkhtmltopdf maintainer explicitly warns not to use it with untrusted HTML/JS. Treat user-controlled input as a security boundary and assess a suitably isolated rendering design.
