How to Fix Increased Font Sizes After Updating wkhtmltopdf
Find why fonts changed after a wkhtmltopdf update, then restore predictable PDF scale with explicit DPI, zoom, fonts, and reproducible builds.

Short answer: do not start by changing your CSS font-size. wkhtmltopdf 0.12.4 changed its rendering DPI behavior; the changelog says it standardized rendering DPI to 96. A reported macOS comparison between 0.12.3 and 0.12.4 showed a large output difference, and the issue was marked for a 0.12.5 milestone. Treat DPI as the first variable to investigate, then verify zoom, smart shrinking, page size, fonts, and the exact binary build.
The change is version-linked, but it is not proof that every 0.12.4 installation makes every document larger. Platform, package source, patched-Qt status, runtime fonts, and command-line options can all change the result. The goal is to make those inputs explicit and compare the same HTML under controlled conditions.
1. Capture the environment before changing anything
Save the details from the machine that produced the old PDF and the machine that produces the new one:
wkhtmltopdf --version, including whether it sayswith patched qt- operating system, architecture, and package source
- installed font packages and fontconfig configuration
- the complete wkhtmltopdf command, including page size, margins, DPI, zoom, print-media, and smart-shrinking flags
- the exact HTML, CSS, images, and web fonts used for the comparison
wkhtmltopdf --version
uname -a
fc-match Arial
fc-match "Your Web Font"
Keep the old binary available if possible. Render one minimal fixture with both versions and compare the PDF page dimensions, text size, line wrapping, and number of pages. The macOS report in issue #3241 demonstrates why the binary identity matters.
2. Reproduce the problem with a minimal fixture
Remove application templates, JavaScript, remote assets, and dynamic data until only the scale question remains.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
@page { size: Letter; margin: 20mm; }
html { font-size: 16px; }
body { font-family: Arial, sans-serif; line-height: 1.4; }
h1 { font-size: 24px; margin: 0 0 12px; }
p { font-size: 16px; margin: 0 0 12px; }
</style>
</head>
<body>
<h1>wkhtmltopdf scale fixture</h1>
<p>This paragraph is deliberately long enough to expose wrapping and scale changes.</p>
</body>
</html>
wkhtmltopdf fixture.html fixture.pdf
pdfinfo fixture.pdf | sed -n '1,12p'
Run the same command with each binary. If the fixture changes, the cause is in the renderer, options, or runtime. If it does not, inspect your application CSS, loaded fonts, viewport assumptions, and content-specific scripts.
3. Make DPI and zoom explicit
The 0.12.4 changelog records “standardize rendering DPI to 96.” That is the strongest documented lead for a 0.12.3-to-0.12.4 scale change, but it should be tested rather than assumed to be a universal conversion. The release notes are available in the project releases.

wkhtmltopdf \
--dpi 96 \
--zoom 1 \
--print-media-type \
--page-size Letter \
--margin-top 20mm --margin-right 20mm \
--margin-bottom 20mm --margin-left 20mm \
fixture.html fixture-96.pdf
For a comparison, change one setting at a time:
- Hold CSS, HTML, page size, margins, and fonts constant.
- Set
--dpiexplicitly. - Set
--zoom 1explicitly. - Compare with and without
--print-media-type. - Compare smart shrinking behavior only after the previous checks.
A historical report showed a 9pt CSS value appearing as 11.52pt under a particular combination of DPI, zoom, print-media, and shrinking settings. That is a case report, not a guaranteed conversion formula.
4. Check smart shrinking, viewport, and page geometry
wkhtmltopdf can shrink a wide layout to fit the printable page. A change in page width or shrinking can make text appear smaller or larger even when CSS is unchanged.
| Setting | What to verify | Diagnostic action |
|---|---|---|
--disable-smart-shrinking |
Whether automatic scaling changed between builds | Render once with the flag and once without it |
--viewport-size |
CSS layout width used before pagination | Set an explicit width such as 1280x1024 |
--page-size / --page-width |
Printable geometry | Use one fixed paper size for every comparison |
--margin-* |
Available content area | Keep all four margins explicit |
--zoom |
Final content scale | Start at 1, then tune only if required |
wkhtmltopdf \
--viewport-size 1280x1024 \
--disable-smart-shrinking \
--dpi 96 --zoom 1 \
--page-size A4 \
--margin-top 15mm --margin-right 15mm \
--margin-bottom 15mm --margin-left 15mm \
fixture.html controlled.pdf
Do not blindly add --disable-smart-shrinking to production. It can change pagination and create overflow. Use it as a controlled experiment, then choose the behavior your layout actually requires.
5. Verify fonts and font loading
Different fonts have different metrics. A fallback font can make text wider, alter line breaks, and increase page count. The project’s packaging notes say static builds still depend on fontconfig, freetype2, and installed runtime fonts; Linux distribution packages can therefore behave differently.

Use a known installed font first
fc-match Arial
fc-list | grep -i "Liberation Sans\|DejaVu Sans" | head
Temporarily change your fixture to a font you know exists on the rendering host. If the scale stabilizes, install and configure the intended family in the same container or VM used for PDF generation.
Check web fonts and network access
- Make sure the renderer can reach the font URL.
- Prefer local, versioned font files for reproducible builds.
- Wait for font loading before capture when JavaScript controls the page.
- Inspect PDF metadata or extract text with your PDF tooling to confirm the expected family is embedded or referenced.
An old Stack Overflow report describes OTF as a workaround for a Qt font-rendering problem and serving a separate browser font format. Treat that as a limited experiment only when evidence points to font parsing or embedding; it is not an official fix for the 0.12.3-to-0.12.4 regression.
6. Compare PDFs systematically
Record objective differences instead of judging only by visual scale:
- page width and height
- number of pages
- text bounding boxes and line wrapping
- font names and embedded subsets
- image dimensions and raster resolution
- margins and header/footer positions
pdfinfo old.pdf > old.info
pdfinfo new.pdf > new.info
diff -u old.info new.info
pdftotext -layout old.pdf old.txt
pdftotext -layout new.pdf new.txt
diff -u old.txt new.txt
Change one variable per run and keep the resulting command and PDF. This prevents a CSS “fix” from hiding a DPI or font configuration problem.
7. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Everything is larger after 0.12.4 | DPI behavior changed | Set --dpi 96 and --zoom 1; compare with the old binary |
| Everything is smaller or content is quarter-size | Page geometry, viewport, or shrinking changed | Set page size, viewport, margins, and test smart shrinking explicitly |
| Only one host differs | Fallback or missing fonts | Use fc-match, install the same fonts, and pin the package |
| Line breaks changed but nominal sizes match | Different font metrics or available content width | Compare font family, viewport, margins, and page size |
| CSS media rules changed output | Print media mode differs | Choose --print-media-type deliberately |
| Web fonts or images are missing | Network, TLS, or timing failure | Use local assets where possible and wait for required selectors or resources |
| Command works locally but fails in a container | Missing fontconfig, freetype2, shared libraries, or fonts | Install runtime dependencies and log the exact binary and package |
| Results vary between runs | Dynamic content, late fonts, or JavaScript timing | Freeze data, wait for a selector, and remove animations |
8. When to pin, upgrade, or migrate
If you need the old appearance immediately, pin the known-good binary and its runtime fonts while you investigate. The downloads page lists 0.12.6 as the stable series released June 11, 2020, but upgrading does not guarantee that every rendering mismatch is resolved. Re-baseline representative PDFs after any version change.
The maintainer’s project status page describes the legacy foundation: Qt 4 was unsupported since 2015 and its WebKit had not been updated since 2012. If reproducibility and maintenance matter more than compatibility with this renderer, evaluate alternatives such as WeasyPrint or Prince against your actual CSS, JavaScript, deployment, and licensing requirements.
9. Or skip the browser setup
If your goal is a reliable screenshot or PDF of a web page rather than maintaining a wkhtmltopdf runtime, ScreenshotNeo provides a single HTTP request. Its capture flow accepts cookie and consent banners, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and lets you turn each cleanup step off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; the response identifies the result with X-Page-Verdict and X-Billed headers.
See the ScreenshotNeo API documentation for all options, including full-page capture, PDF paper size and margins, custom CSS and JavaScript, waits, headers, cookies, user agents, timezone, geolocation, caching, async jobs, bulk capture, and signed links.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
An MCP server also lets Claude, Cursor, and other MCP clients use take_screenshot, get_page_info, and capture_pdf. 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account and start with the 1,000 included screenshots.
10. Practical checklist
- Record both versions and whether patched Qt is enabled.
- Save OS, architecture, package source, fonts, and the complete command.
- Render a minimal fixture with identical HTML and CSS.
- Set DPI, zoom, page size, margins, viewport, and print-media behavior explicitly.
- Test smart shrinking as a separate variable.
- Verify font resolution and loading on the rendering host.
- Compare page geometry, text wrapping, font metadata, and page count.
- Pin a known-good build while deciding whether to upgrade or migrate.
FAQ
Does wkhtmltopdf 0.12.4 always increase font sizes?
No. The documented DPI change and issue reports make it a strong lead, but output also depends on platform, fonts, viewport, zoom, and shrinking.
Should I reduce every CSS font-size value?
No. First make DPI, zoom, fonts, page geometry, and runtime dependencies comparable.
Is --zoom 0.8 the official fix?
No. Zoom is a scaling control. Choose it only after measuring the target output with a controlled fixture.
Will installing 0.12.6 guarantee identical PDFs?
No. Treat every renderer or package change as a new baseline and compare representative documents.
When is migration sensible?
Consider it when you need maintained rendering components, repeatable builds across platforms, or CSS and JavaScript behavior beyond this legacy WebKit stack.


