wkhtmltopdf Page Is Blank When Rendering a JavaScript Website
Diagnose blank wkhtmltopdf PDFs with JavaScript debugging, readiness checks, and resource inspection. Learn when to switch to a modern browser renderer.
Short answer: wkhtmltopdf uses Qt WebKit, and its documented JavaScript delay defaults to just 200 milliseconds. If your page needs more time to render, configure a wait or signal readiness with --window-status. If it remains blank, investigate JavaScript errors, browser compatibility, and resources the renderer cannot load. A longer delay is not a universal fix.
This guide gives you a diagnostic sequence, commands you can run, and a decision rule for when to keep wkhtmltopdf or move to a modern browser renderer. The actual cause cannot be determined without the page URL or a reproducible sample, the wkhtmltopdf build, operating system, command, and any errors.
1. Capture the exact environment and command
Before changing options, record the renderer version, operating system and version, full command, and a small reproducible HTML and JavaScript example. These details are needed to distinguish a timing issue from a build, resource, or compatibility issue.
wkhtmltopdf --version
uname -a
On Windows, use ver to record the OS version. Keep the full command, including any configuration file and flags. If possible, save a minimal page that reproduces the behavior without application secrets.
2. Check whether JavaScript runs and inspect errors
JavaScript is enabled by default in wkhtmltopdf’s documented command-line options. Check that your invocation or configuration does not disable it, then enable JavaScript diagnostics and capture stderr:
wkhtmltopdf --debug-javascript https://example.com ./output.pdf 2>wkhtmltopdf.log
Replace the example URL with the page you need to render. Inspect wkhtmltopdf.log for script errors, failed resource loads, redirects, and other clues. A blank PDF alone does not identify which part failed. The documented options include --debug-javascript, --run-script, --window-status, and --javascript-delay. See the wkhtmltopdf usage documentation.
3. Check the page’s content and dependencies
Verify that the meaningful content exists in the rendered page and that everything it depends on is reachable from the machine running wkhtmltopdf. Check:
- The main HTML and DOM content, including whether the page requires a client-side app to populate an initially empty root element.
- JavaScript bundles and stylesheets, including their URLs, redirects, and access controls.
- API calls, authentication, cookies, and session state needed to populate the page.
- Fonts and images, including resources hosted on a different domain.
- Whether the renderer can reach the page from its network environment, including any proxy, firewall, or TLS constraints.
Try the same URL from the renderer host, with the same relevant authentication and network setup. If a required request fails, waiting longer cannot supply its missing response. A diagnostic change such as --load-error-handling ignore changes how certain load errors are handled; it does not repair the failed request and can still leave an empty document.
4. Wait for application readiness
The --javascript-delay option waits a fixed number of milliseconds. Its documented default is 200 ms. It is a time-based delay, not evidence that an application has finished rendering. The library documentation describes the wait after page load until printing, or until JavaScript calls window.print().
If the content appears after a known delay, try a modest increase and compare the resulting PDF:
wkhtmltopdf --javascript-delay 1500 https://example.com ./output.pdf
Choose a delay based on observed page behavior, not guesswork. A historical project issue reports a blank white page even after a delay was increased, so this option should not be treated as a guaranteed repair.
When you control the page, a readiness signal is usually more meaningful than a fixed timer. Set window.status after the content needed for the PDF is ready, then ask wkhtmltopdf to wait for that value:
<script>
async function renderPage() {
// Populate the content and await the data this document needs.
await loadReportData();
document.querySelector("#report").textContent = "Report is ready";
window.status = "pdf-ready";
}
renderPage();
</script>
wkhtmltopdf --window-status pdf-ready https://example.com/report ./report.pdf
Replace loadReportData() with your application’s real data-loading work. Set the status only after required content is ready. This is a documented control, not a guarantee that every script or resource will succeed.
5. Decide whether the installed WebKit can render the page
wkhtmltopdf renders HTML into PDF using Qt WebKit. A page that depends on browser APIs or JavaScript behavior unavailable in the installed WebKit build may fail even when its scripts and resources load. The project status account describes the tool’s dependence on WebKit1 and gives historical context about the age of that engine; treat that as maintainer commentary, not a formal current end-of-life notice.
Use timing and debug checks when the page is otherwise compatible and its content merely appears late. Consider a Chromium-based renderer when the required page features do not run in the installed engine, or the same minimal reproduction remains blank after you confirm resource access and readiness.
6. Render with Playwright when a modern browser is needed
Playwright can generate PDFs with page.pdf(). Its documentation supports waiting for a page-specific selector or condition and recommends checking the application’s actual state instead of treating networkidle as a general readiness signal. PDF generation uses print CSS by default, so verify print styles, fonts, headers and footers, and page breaks against the output you need.
Runnable Node.js example using a page-specific readiness selector:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com/report', { waitUntil: 'load' });
await page.locator('#report[data-ready="true"]').waitFor({ state: 'visible' });
await page.pdf({ path: 'report.pdf', format: 'A4', printBackground: true });
} finally {
await browser.close();
}
})();
Replace the selector with a condition your application sets only after the report is ready. Install Playwright and its browser runtime according to the Playwright installation documentation. Do not assume that a generic network quiet period proves a client-side application has finished its work.
7. Troubleshooting checklist
| Symptom | Likely cause to investigate | Next step |
|---|---|---|
| Blank PDF and JavaScript errors in stderr | A script failed or relies on behavior the installed engine does not support. | Read the first relevant error, check the script and its dependencies, and reproduce with a minimal page. If it depends on unsupported browser behavior, try a modern renderer. |
| Content appears if you wait in a normal browser, but not in the PDF | The fixed delay is shorter than the page’s render time, or readiness is not signaled. | Try a measured increase to --javascript-delay. If you control the page, set window.status after required content is ready and use --window-status. |
| Longer delay still produces a blank page | The issue may be a failed resource, script error, redirect or authentication problem, or engine incompatibility. | Inspect stderr and resource access from the renderer host. Do not keep increasing the delay without new evidence. |
| Images, fonts, or styles are missing | Those resources may be inaccessible, redirected, or not yet available when printing. | Check their URLs and access from the renderer machine. Wait for required resources in an application-controlled readiness condition. |
| Page content depends on an API or login | The renderer may lack the needed cookies, headers, or authenticated session, or the request may fail. | Reproduce with the same relevant credentials and network conditions. Avoid placing secrets in shared logs or reproducible samples. |
| Only the production build fails | Production may load different bundles, endpoints, policies, or redirects. | Compare the production page’s requests and runtime errors with the working environment from the same host that runs wkhtmltopdf. |
| Blank output after ignoring load errors | Ignoring a failure does not create the content that the failed request should have supplied. | Find and fix the underlying resource or navigation failure, or use a compatible renderer. |
| Results vary between runs | Content or resource timing may vary, or the page may depend on asynchronous state. | Wait for an explicit application condition and check required resources before printing. Keep a minimal reproduction for comparison. |
8. Reliability, performance, and cost considerations
With wkhtmltopdf, longer fixed waits can increase render time for every invocation, including pages that were already ready. An application-controlled readiness signal can avoid guessing a single delay, but it still depends on the page setting the signal correctly and the renderer supporting the page’s features.
For repeatable output, record the wkhtmltopdf version and OS, keep a reproducible input, and verify the PDF’s content and print layout when the page or runtime changes. If moving to Playwright, account for the browser runtime and deployment setup, and validate the intended print CSS, headers and footers, fonts, and page breaks. The sources here provide no controlled performance comparison, so choose based on compatibility and your output requirements rather than an assumed speed advantage.
Or skip the browser setup
If your goal is a PDF of a live web page, ScreenshotNeo offers a one-call website screenshot and PDF API. For PDF output, see the API documentation for the PDF options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -d format=pdf -o page.pdf
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Create a free account and get 1,000 screenshots a month with no card.
FAQ
Does a blank PDF prove JavaScript is disabled?
No. JavaScript is enabled by default in the documented options. Check the actual invocation and debug output before concluding that it is disabled.
Should I always switch to Chromium?
No. First establish whether the page is compatible and whether required scripts and resources load. Move when the installed engine cannot run required page features or a reproducible blank output persists after readiness and resource checks.
Can I tell the exact cause from the PDF alone?
Usually not. You need the command, version and OS, a reproducible page, and diagnostics such as stderr and resource access to narrow it down.
References
- wkhtmltopdf project homepage describes its Qt WebKit rendering engine.
- wkhtmltopdf command-line usage documentation lists JavaScript and waiting options.
- wkhtmltopdf issue #2200 is a historical report of a blank page despite an increased delay.
- wkhtmltopdf status account provides project-maintainer context on the WebKit dependency.
- Playwright page.pdf() documentation covers PDF generation and print behavior; see also its page waiting documentation.


