If a PDF looks right on a developer laptop but wrong in production, do not start by changing CSS at random. First prove that both systems run the same wkhtmltopdf binary, with the same Qt build, command-line options, HTML/data, fonts, and readable assets. Capture stderr and the exit code, then reduce the difference to the smallest input that still fails. This workflow distinguishes renderer drift from missing resources, timing differences, and deliberate error-handling behavior.
1. Identify the renderer you are actually running
wkhtmltopdf is a headless HTML-to-PDF command-line tool built on Qt WebKit; the project documentation says it runs without a display or display service (official project description). The command name alone does not prove equivalence: package builds can use different Qt patches, compile options, operating systems, or architectures.
Capture both binaries
Run these commands as the same user that performs production conversion, not only from an interactive shell:
command -v wkhtmltopdf
wkhtmltopdf --version
readlink -f "$(command -v wkhtmltopdf)"
uname -a
Save the complete output with your deployment record. A typical official release string identifies version 0.12.6 and may include “with patched qt”; record that marker verbatim. The upstream repository is archived (owner-marked on January 2, 2023). Its releases page lists 0.12.6 on June 11, 2020, while the changelog labels 0.12.7 unreleased (release history). These are repository facts, not proof that a distribution or fork has not changed.
#1 Best Overall
Compare the runtime envelope
- Base image or operating-system release and architecture.
- Executable path, package source, checksum, and container image digest.
- Environment variables affecting proxies, locale, timezone, DNS, and certificate stores.
- The service account, working directory, sandbox profile, and filesystem mount points.
Install the same known binary in both environments where possible. If policy requires distribution packages, document the package name and build revision and test that exact artifact in a staging container.
2. Freeze the command, inputs, and timing
Rendering is a function of the effective options and the bytes presented to the converter. Put the complete invocation in source control or a captured log. Include global options (before input URLs) and per-page options (between a page and its output), because their scope differs. The CLI reference documents a 96 DPI default and a 200 ms JavaScript delay; make these explicit rather than depending on build or wrapper defaults (CLI usage documentation).
Use an explicit diagnostic command
wkhtmltopdf
--dpi 96
--enable-javascript
--javascript-delay 200
--load-error-handling abort
--load-media-error-handling abort
--enable-local-file-access
--log-level info
input.html output.pdf 2>render.stderr
status=$?
printf 'exit_code=%sn' "$status"
Only enable local-file access when required, and restrict the allowed paths in a production design. The documented version disables local-file access by default; an HTML file that works locally may therefore lose CSS, images, fonts, or scripts in production.
Make dynamic content deterministic
- Save the exact HTML sent to wkhtmltopdf, including generated markup.
- Save API responses, images, stylesheets, and scripts or serve them from a versioned fixture host.
- Use the same locale, timezone, clock inputs, and feature flags. Date formatting and conditional content can legitimately differ when these values change.
- Keep URL redirects, authentication headers, cookies, and proxy settings identical.
- Run both captures against the same fixture at the same revision before changing renderer settings.
A browser preview is not an oracle: a browser may have a warm cache, different credentials, newer JavaScript, or network access unavailable to the wkhtmltopdf process.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #2
3. Verify fonts, CSS, scripts, and images from production
Inspect resources from the converter’s actual runtime. Check every absolute URL for DNS, proxy, TLS, authentication, and redirect behavior. For relative URLs, confirm the base URL and working directory. For local files, verify Unix permissions, container mounts, symlinks, and the configured local-file policy.
Check files and HTTP responses
# Run as the service account
sudo -u pdfworker test -r /srv/templates/assets/site.css
sudo -u pdfworker test -r /srv/templates/fonts/Inter-Regular.woff2
curl -I --fail https://example.test/assets/site.css
curl -L --fail --silent --show-error https://example.test/assets/logo.svg -o /tmp/logo.svg
Record status codes, final URLs, content types, and response sizes. A 200 response can still be the wrong HTML (for example, a login page), and a blocked font can silently trigger a fallback with different metrics and line breaks.
Compare installed fonts, not declarations
List the font files visible to each runtime and compare checksums. Ensure the CSS family, weight, and style map to files actually installed or reachable through permitted URLs. Font-face behavior has been reported to vary across platforms in an issue report, but that report is anecdotal and version-specific (issue 2884). Treat it as a lead to test, not a universal defect.
fc-match "Inter:style=Regular"
fc-list | sort > production-fonts.txt
sha256sum /usr/share/fonts/.../Inter-Regular.woff2
For a controlled test, temporarily embed a known font or point both systems at the same local font files, then compare pagination. Do not ship a broad font installation change without checking licensing and image size.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems4. Read stderr and exit status as diagnostic data
Always preserve stderr, stdout (if your wrapper uses it), and the numeric exit code. A nonempty PDF is not proof of a complete render. Resource failures can be ignored, skipped, or treated as fatal depending on --load-error-handling and --load-media-error-handling. During diagnosis, use abort so the first missing dependency is visible; after you understand the failure, choose a deliberate production policy.
wkhtmltopdf --log-level info page.html out.pdf 2>stderr.log
code=$?
if [ "$code" -ne 0 ]; then
cat stderr.log >&2
exit "$code"
fi
Search logs for DNS, SSL, “not found,” blocked local-file, JavaScript, and font messages. Increase logging only as supported by your packaged binary; do not assume a wrapper’s “quiet” mode removes the underlying failure.
5. Reduce the discrepancy to a minimal reproducible case
Once the environments are aligned, isolate one variable at a time. Start with a document containing a heading, one paragraph, one image, one web font, and a fixed-size box. Use explicit CSS dimensions and the same options. If it differs, the renderer/runtime is implicated. If it matches, add the real stylesheet, scripts, remote assets, and data in small groups until the first change appears.
- Copy the failing HTML and local assets into a clean directory.
- Replace live APIs with saved fixtures and remove analytics, ads, and chat code.
- Disable JavaScript, then re-enable it with a fixed delay to identify timing sensitivity.
- Remove fonts, images, and CSS one class or resource at a time.
- Run the smallest case through both binaries and archive PDFs, stderr, exit codes, and hashes.
This method avoids attributing every mismatch to a single “magic” flag. It also gives maintainers a reproducible report containing binary version, OS, command, input, expected output, and first differing resource.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #4
- Funny saying for any front-end developer, web developer, computer programmer, computer systems engineer, mobile app developer, software developer, or code lover who likes to code, make funny programming jokes, and take memorable photos.
- Wear it proudly at International Programmers' Day, school, coding classes, or coding communities! It also makes a funny present for a computer programming lover friend.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
6. Common symptoms and targeted fixes
| Symptom | Likely evidence | Next action |
|---|---|---|
| Different line breaks or page count | Font lists, checksums, or DPI differ | Align font files and make --dpi explicit; compare computed widths in a minimal case. |
| Images or CSS missing | stderr shows 404, TLS, DNS, or permission errors | Test the URL/file as the service account; fix mounts, credentials, proxy, or URL base. |
| JavaScript content absent | Different delay, disabled script, or console/load errors | Set --enable-javascript and an explicit --javascript-delay; replace live data with a fixture. |
| Local files work in development only | Production denies local-file access | Prefer served assets; otherwise enable access only for required paths and verify permissions. |
| PDF exists but is incomplete | Nonzero exit code or ignored load errors | Capture stderr, use abort handling while debugging, and fail the job on the documented exit status. |
| Only one platform differs | OS, architecture, Qt build, or font-face behavior differs | Run the same container/binary or reduce to a cross-platform minimal case. |
7. Reliability, performance, and operational controls
Make failures observable
- Log renderer version, executable checksum, options, input fixture identifier, start/end time, exit code, and stderr.
- Store a sample PDF and a hash for regression comparisons; review visual diffs rather than relying only on hashes when metadata changes.
- Set an outer process timeout and terminate stuck workers; investigate the URL or script causing the wait before increasing it.
- Limit network egress and local-file permissions. Allowlisting required hosts is safer than granting unrestricted access.
Control throughput
Reuse a warmed worker only if you can reset its environment and prevent state leakage between jobs. Otherwise isolate jobs in short-lived containers. Cache immutable assets and fixtures, but never let a developer’s browser cache hide missing production dependencies. Measure conversion time with the same input before tuning JavaScript delays or concurrency.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.8. An evidence-based comparison checklist
- Renderer: exact version, patched-Qt marker, path, package source, OS, architecture.
- Invocation: full command, option scope, DPI, JavaScript, delay, local-file policy, error handling.
- Inputs: identical HTML, data, URLs, cookies, headers, locale, timezone, and timing.
- Resources: fonts, CSS, images, scripts, DNS/TLS, proxy, redirects, permissions, mounts.
- Evidence: stderr, exit code, output PDF, hashes, and a minimal failing fixture.
If all five groups match and the minimal case still differs, the remaining explanation is usually a renderer/build or platform behavior that must be reproduced with the same artifact, not papered over with unrelated CSS changes.
Or skip the browser setup
For a separate screenshot or visual-check step, ScreenshotNeo provides a single HTTP request and an MCP server for AI agents. It is not a drop-in replacement for wkhtmltopdf’s HTML-to-PDF semantics, but it can remove browser-environment setup when you need a clean capture of a URL.
One call returns an image (PNG, JPEG, or WebP) or a PDF:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchBest Value
- Programming Language Lover Code Apparel. App or Web Design and Development Expert Funny Dress. Best Valentines Idea For Coding Lover. HTML Code or Meaning Costume
- Funny I Know HTML - How To Meet Ladies Computer Programmer Quotes
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for options. Cookie and consent banners are accepted and removed before capture, along with more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—work with Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account to try it.
Frequently Asked Questions
Does matching the wkhtmltopdf version guarantee identical PDFs?
No. Qt build, operating system, fonts, assets, options, locale, and runtime permissions can still differ. Compare the complete environment and a frozen input.
Should I always enable local-file access?
No. The documented version disables it by default. Prefer served or embedded assets; if local files are required, allow only the necessary paths and verify service-account permissions.
Why is a PDF produced when an image or stylesheet failed?
wkhtmltopdf can continue or skip load failures according to its error-handling options. Check stderr and the exit code instead of treating file existence as success.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

