How to Use Verbose Output to Debug wkhtmltopdf
Learn how wkhtmltopdf log levels, JavaScript diagnostics, load errors, and local-file access reveal why HTML-to-PDF jobs fail.
Use wkhtmltopdf’s normal information output first. The documented default for --log-level is info. Remove -q or --quiet, capture the complete command and output, then add --debug-javascript only when scripts are involved. The available log levels are none, error, warn, and info; there is no documented debug level.
The examples below use the 0.12.6 manual with patched Qt. Confirm the executable and build installed on your machine before interpreting a message.
1. Check the exact wkhtmltopdf build
Different operating-system packages can expose different features. Record the executable version and your operating-system version before changing flags.
wkhtmltopdf --version
# Linux
cat /etc/os-release
# macOS
sw_vers
# Windows PowerShell
Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber
Keep this information with the failing command, the input HTML, and the full diagnostic output. The wkhtmltopdf support guidance asks for the version, operating system and version, a detailed description, and a test case that duplicates the issue.
2. Turn on the useful output
Run the smallest failing example without quiet mode:
wkhtmltopdf --log-level info input.html output.pdf
info is already the default, so this is equivalent to omitting --log-level info. The explicit flag makes the diagnostic intent clear in scripts and bug reports.
Capture output in a file
wkhtmltopdf writes diagnostics to the terminal. Redirect both standard output and standard error so warnings are not lost.
# POSIX shells
wkhtmltopdf --log-level info input.html output.pdf >wkhtmltopdf.stdout.log 2>wkhtmltopdf.stderr.log
# Keep one combined log
wkhtmltopdf --log-level info input.html output.pdf >wkhtmltopdf.log 2>&1
# PowerShell
wkhtmltopdf --log-level info input.html output.pdf *> wkhtmltopdf.log
Preserve the exact command line, timestamps if your wrapper adds them, exit status, and the generated file. Avoid redacting the message text when asking for help; redact secrets in URLs, headers, cookies, and HTML separately.
Choose a narrower level when the question is specific
| Level | Meaning | Use it when |
|---|---|---|
none |
No log output | You are deliberately suppressing diagnostics after the issue is understood. |
error |
Errors only | You need a compact production log. |
warn |
Warnings and errors | You want likely problems without routine information. |
info |
Information, warnings and errors | You are diagnosing a conversion. This is the documented default. |
-q and --quiet are compatibility shorthands for --log-level none. Remove them during diagnosis. Adding an undocumented debug value will not provide an extra supported level.
3. Separate general logging from JavaScript debugging
General logging reports conversion and resource-loading activity. JavaScript diagnostics are enabled with a separate switch:
wkhtmltopdf --log-level info --debug-javascript input.html output.pdf
Use this when the page depends on script execution, delayed rendering, or a client-side error. It does not turn wkhtmltopdf into a modern browser debugger and does not guarantee that a web application will render correctly.
Wait for delayed or status-driven content
# Wait 2 seconds after page loading
wkhtmltopdf --log-level info --debug-javascript --javascript-delay 2000 input.html output.pdf
# Wait until page JavaScript sets window.status to "ready"
wkhtmltopdf --log-level info --debug-javascript --window-status ready input.html output.pdf
The documented default for --javascript-delay is 200 milliseconds. A longer delay can expose timing problems, but it also increases conversion time. --window-status is useful when your page can explicitly signal that rendering is complete.
4. Read the log as a diagnostic sequence
- Confirm the input. Make sure the command points to the HTML file or URL you intended and that the output path is writable.
- Classify the first useful message. Decide whether it concerns the main document, a media resource, JavaScript, or a local file.
- Re-run with the matching option family. Use JavaScript diagnostics for script messages, load-error controls for fetch failures, and local-file controls for filesystem access.
- Compare the PDF with the log. Missing content can result from a resource that failed, was skipped, or loaded after capture.
- Reduce the reproduction. Remove unrelated HTML, CSS, scripts and external resources while keeping the same installed build.
A warning is evidence about what wkhtmltopdf observed, not proof of one universal root cause. The reviewed documentation does not define a mapping from every warning string to a single fix.
5. Diagnose resource-loading failures
Page loading and media loading have separate error policies.
# Main-page or subresource load failures
wkhtmltopdf --log-level info --load-error-handling abort input.html output.pdf
# Continue while ignoring a main-page load error
wkhtmltopdf --log-level info --load-error-handling ignore input.html output.pdf
# Skip a failing page/resource according to wkhtmltopdf's policy
wkhtmltopdf --log-level info --load-error-handling skip input.html output.pdf
# Media-resource failures use a separate option
wkhtmltopdf --log-level info --load-media-error-handling ignore input.html output.pdf
--load-error-handling accepts abort, ignore, and skip; abort is the documented default. --load-media-error-handling is separate and defaults to ignore. Changing a policy can let a conversion continue while omitting content. It does not repair the failed resource, so first save the original failure evidence.
Typical clues and next checks
| Observed result | What to inspect | Next action |
|---|---|---|
| PDF is not produced | Main document load or write failure | Re-run at info, verify the input and output paths, and keep the original abort behavior while isolating the failing resource. |
| PDF exists but images, fonts or styles are absent | Media/resource messages | Check URLs, certificates, redirects and the media error policy. Test the resource directly. |
| HTML shell appears but application content is missing | JavaScript timing or script errors | Add --debug-javascript; test a delay or --window-status signal. |
| Only local assets are missing | Local-file access restrictions | Review the local-access switches and the paths passed to --allow. |
6. Debug local HTML and filesystem access
Local HTML often references CSS, images, fonts or scripts with relative filesystem paths. Inspect whether local access is disabled or whether the needed directory was not allowed.
# Explicitly permit local-file access
wkhtmltopdf --enable-local-file-access input.html output.pdf
# Allow only a required directory (repeat --allow for additional paths)
wkhtmltopdf --disable-local-file-access --allow /path/to/assets input.html output.pdf
Use the narrowest access that satisfies the reproduction. If a local resource is still absent, use an absolute path temporarily to prove whether path resolution is the issue, then restore a controlled --allow configuration.
7. Build a minimal reproducible test case
- Copy the failing HTML into a new directory.
- Keep one external resource or script at a time.
- Replace dynamic data with fixed values.
- Use the same command-line flags and installed build as the failure.
- Run once with
--log-level infoand again with--debug-javascriptif scripts are involved. - Record which change makes the message or missing output disappear.
mkdir wkhtmltopdf-repro
cp input.html wkhtmltopdf-repro/
cd wkhtmltopdf-repro
wkhtmltopdf --version
wkhtmltopdf --log-level info --debug-javascript input.html repro.pdf >repro.log 2>&1
When reporting the issue, include the executable version, operating system and version, a detailed description, and the smallest test case that duplicates it. Do not claim a diagnosis until the same input reproduces the behavior on the same build.
8. Security when debugging HTML
The wkhtmltopdf project warns: “Do not use wkhtmltopdf with any untrusted HTML.” Sanitize user-supplied HTML and JavaScript before passing it to the converter. Treat local-file access, cookies, headers and network access as sensitive capabilities.
9. Performance and reliability notes
- Use
infowhile investigating and a narrower level only after you know which evidence you need. - JavaScript debugging and long delays increase log volume or conversion time; remove them from normal production commands when they are no longer needed.
ignoreandskipcan produce a PDF with missing content. Keepabortduring root-cause analysis when you need failures to remain visible.- Reproduce with the same 0.12.6 patched-Qt build where possible. Do not assume another operating-system package has identical options.
- Persist logs with the output artifact so an incomplete PDF can be correlated with the exact run.
10. Or skip the browser setup
If your goal is a clean website screenshot or PDF rather than maintaining a wkhtmltopdf environment, ScreenshotNeo provides a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP or PDF. 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; response headers identify the page verdict and whether the request was billed.
See the ScreenshotNeo API documentation for the complete option list.
# cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
# Python
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)
# Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, clicks, hidden selectors, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage reporting and an OpenAPI specification. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan.
Sign up for 1,000 free screenshots a month with no card.
11. Troubleshooting checklist
- Remove
-qand--quiet. - Confirm
wkhtmltopdf --versionand the operating-system version. - Run at documented
infolevel and capture both output streams. - Add
--debug-javascriptonly for script-related behavior. - Check
--javascript-delayand--window-statusfor delayed rendering. - Separate main-page and media failures with their respective load-handling options.
- Inspect
--enable-local-file-access,--disable-local-file-access, and repeatable--allowpaths. - Reduce the input to a reproducible test case.
- Sanitize all untrusted HTML and JavaScript.
FAQ
Is there a --debug log level?
No documented debug level exists. Use info for general diagnostics and --debug-javascript for JavaScript output.
Should I always use --load-error-handling ignore?
No. It can hide a failed resource and produce incomplete output. Identify the failure first and change the policy only when continuing is an intentional part of your workflow.
Why does --debug-javascript not fix a blank PDF?
It exposes script diagnostics but does not make unsupported browser features work. Use the messages to isolate timing, script errors or missing resources.
What should accompany a bug report?
Provide the executable version, operating system and version, a detailed description, and a small test case that duplicates the issue.


