ScreenshotNeo

BlogHTML to image & PDF

How to Render JavaScript Before Generating PDFs with wkhtmltopdf

wkhtmltopdf enables JavaScript by default, but its default 200 ms wait is often too short. Learn when to use a delay, a page readiness signal, or another renderer.

By the ScreenshotNeo team30 September 20268 min read

How to Render JavaScript Before Generating PDFs with wkhtmltopdf

wkhtmltopdf runs JavaScript by default, but its default wait after page load is only 200 milliseconds. That is often too short for pages that fetch data or render content asynchronously. Start by increasing the fixed wait with --javascript-delay. If you control the page, a more targeted option is to set window.status after the content needed in the PDF is ready, then make wkhtmltopdf wait for that value with --window-status.

Neither option makes wkhtmltopdf’s older rendering engine compatible with every modern site. Check the actual output using the same wkhtmltopdf build and representative pages you will use in production. The project recommends considering Puppeteer for sites that depend on dynamic JavaScript. [wkhtmltopdf command-line manual] [wkhtmltopdf project status]

1. Check your wkhtmltopdf build

Before tuning a command, find out which executable and build your environment is running. wkhtmltopdf documents features that depend on patched Qt; a distribution package compiled without those patches can behave differently from a patched-Qt build.

wkhtmltopdf --version
wkhtmltopdf --extended-help

Check the output, then compare its available options with the command-line manual and the project’s download notes. The project download page identifies 0.12.6 as a stable series release dated June 11, 2020; treat that as a dated project statement, not as a guarantee that no later build exists. [wkhtmltopdf downloads and build notes]

Run the same checks in the container, server, or job runner that creates the PDFs. A command that works on a developer’s machine may use a different package or have different options in deployment.

2. Use a fixed JavaScript delay

JavaScript is enabled by default. You can make that intent explicit with --enable-javascript, then set a delay in milliseconds using --javascript-delay. The documented default delay is 200 ms.

wkhtmltopdf \
  --enable-javascript \
  --javascript-delay 2000 \
  https://example.com/report \
  report.pdf

Replace the example address with the page you need to print. Two seconds is an example starting point, not a universal reliable setting. Measure how long the page’s data and rendering take in the environment where the command runs, then choose a delay that covers the expected work. A fixed delay always waits for that duration: if the page finishes earlier, time is wasted; if it finishes later, the PDF can still capture incomplete content.

When a fixed delay is appropriate

  • You cannot change the page to expose a readiness signal.
  • The page’s rendering time is reasonably predictable.
  • You can inspect the output and adjust the delay based on observed behavior.

Try a small range of delays on a representative page. Inspect the resulting PDF for missing charts, blank data areas, unloaded images, or elements that appear before their final layout. Do not assume that a delay which works for one URL will work for pages with different data sizes or network conditions.

3. Wait for a page-provided readiness signal

If you own the page, a readiness marker can express what the PDF actually needs: the page has finished loading the data and applying the layout changes that must appear in the output. Set a known status value only after that work is complete, and pass the same value to --window-status.

A page readiness signal lets the renderer proceed after the PDF content is prepared.
A page readiness signal lets the renderer proceed after the PDF content is prepared.
<script>
  async function preparePdf() {
    try {
      await loadReportData();
      renderReport();
      await waitForReportLayout();
    } finally {
      // The renderer can proceed after the required work has settled.
      window.status = "pdf-ready";
    }
  }

  preparePdf();
</script>
wkhtmltopdf \
  --enable-javascript \
  --window-status pdf-ready \
  https://example.com/report \
  report.pdf

loadReportData, renderReport, and waitForReportLayout above are application-specific placeholders; replace them with the functions your page uses. The important condition is that the marker is set after the content and layout required in the PDF are ready. If the page can fail while loading data, decide how the failure path should behave and set a corresponding terminal marker there too. Otherwise the renderer may wait for a value the page never sets.

The manual documents waiting for a matching status value, but does not specify an application-level timeout strategy. Do not make readiness depend on a network request that can hang forever. Apply time limits and failure handling in the page or the process that invokes wkhtmltopdf, and report a useful error when the marker is not reached.

4. Use --run-script for additional page code

--run-script runs supplied JavaScript after the page is done loading. It can help with simple adjustments or page-specific code:

wkhtmltopdf \
  --enable-javascript \
  --javascript-delay 1500 \
  --run-script 'document.body.classList.add("print-ready")' \
  https://example.com/report \
  report.pdf

This option does not turn wkhtmltopdf into a current browser, and it is not a replacement for the page’s own asynchronous readiness handling. If a script needs to wait for data, make sure the page has a reliable way to signal that the data and resulting layout are complete. Check the manual for the exact option behavior supported by your installed build. [wkhtmltopdf command-line manual]

5. Pick the approach that matches the page

Situation Approach What to check
You do not control the page Use --javascript-delay as a measured buffer Test slow and typical page loads; inspect for incomplete content.
You control the page and its rendering code Set a readiness marker and use --window-status Set the marker after required data and layout are ready, including failure handling.
You need a small post-load adjustment Consider --run-script Confirm the script runs in the installed build and does not rely on unsupported APIs.
The site depends on modern browser behavior Evaluate Puppeteer’s browser-based PDF generation Render a representative page and compare the PDF’s content and layout.
You generate reports from HTML you control Evaluate WeasyPrint or Prince as alternatives Confirm their supported features match your report’s requirements.

The wkhtmltopdf project status page says its Qt 4 base has been unsupported since 2015 and describes its bundled WebKit as not updated since 2012. It recommends considering Puppeteer for converting sites that use dynamic JavaScript, and mentions WeasyPrint or commercial Prince for controlled report generation. Those are project status notes and recommendations; test the actual features your documents need. Puppeteer documents PDF creation through its Page.pdf() API. [wkhtmltopdf status and alternatives] [Puppeteer Page.pdf API]

Choose a full-page PDF workflow when the complete document matters, and an element capture when only one region is needed.
Choose a full-page PDF workflow when the complete document matters, and an element capture when only one region is needed.

6. Or skip the browser setup

If your goal is a screenshot or PDF of a web page and you do not want to manage a browser renderer, ScreenshotNeo provides a website screenshot API and MCP server. Its one-call endpoint can return a screenshot or PDF. See the ScreenshotNeo API documentation for the available parameters.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.pdf

For a PDF response, use the PDF output option documented by ScreenshotNeo and select the desired PDF settings. The example above illustrates the request shape; consult the API documentation for the output parameter and its current supported values.

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before the capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents and MCP clients. The free plan includes 1,000 shots per month with no card, and paid plans start at $5 for 3,000 shots.

Sign up for 1,000 free screenshots a month, with no card required.

7. Troubleshooting

Symptom Likely cause What to try
PDF contains a loading message or missing data The page’s asynchronous work outlasted the fixed delay. Increase --javascript-delay based on measured rendering time, or use a page-provided readiness marker.
Conversion waits too long or never finishes The requested window.status value is never set, perhaps because a request failed or the code path was skipped. Check the marker spelling and make success and failure paths set an intentional terminal value. Add timeout handling in the calling process.
--window-status or another option is unknown The installed build or package may not expose that option. Check wkhtmltopdf --version and --extended-help; compare the result with the project manual and build notes.
JavaScript errors or incorrect layout persist after increasing the wait The site may depend on browser APIs or behavior the older rendering engine does not support. Inspect the page’s errors and compatibility requirements. Evaluate Puppeteer for dynamic sites rather than increasing the delay indefinitely.
Output differs between local and production runs The environments may use different wkhtmltopdf builds, patched-Qt support, or page conditions. Record the executable version in both places and reproduce using the deployment build and representative URLs.
Untrusted HTML causes security concern wkhtmltopdf can process supplied HTML and JavaScript in a way that exposes the server. Follow the project’s warning: do not use it with untrusted HTML; sanitize user-supplied HTML and JavaScript, and consider containment such as AppArmor or SELinux. These measures do not constitute a universal sandbox guarantee.

The security recommendation comes from the wkhtmltopdf project status page. Treat HTML and JavaScript supplied by users as untrusted input, and design sanitization and process isolation for your application’s threat model. [wkhtmltopdf project security guidance]

8. Performance, reliability, and cost

A fixed JavaScript delay adds at least that much waiting to each conversion after page loading, even when the page is ready sooner. A page readiness marker can avoid choosing one universal sleep, but it still needs robust failure handling and a timeout in the calling process. The manual documents the wait options; these operational tradeoffs follow from how fixed waits and condition-based waits behave.

For reliability, test more than one page state: a typical response, a slower response, empty or missing data, and a failed data request. Verify the content in the PDF, not just that the command exited successfully. Keep the wkhtmltopdf build consistent across development and production, and retain enough logs to identify the URL, executable version, wait strategy, and conversion error.

Cost depends on the runtime and infrastructure you operate; the research sources do not provide a wkhtmltopdf price or a comparative cost benchmark. Include time spent maintaining the rendering environment and investigating compatibility issues in your own estimate. If you compare a managed API, check its billing rules and response status directly. ScreenshotNeo states that only clean shots are billed and identifies non-billed outcomes in response headers; its published plans include a free tier and paid tiers starting at $5.

FAQ

Is JavaScript disabled by default in wkhtmltopdf?

No. The manual says JavaScript is enabled by default. You can pass --enable-javascript to make that explicit.

What is the default JavaScript delay?

The documented default for --javascript-delay is 200 milliseconds. That may not be enough for asynchronous page work.

Can --run-script make a modern site render correctly?

Not by itself. It runs additional code after page load, but it does not add browser APIs or update wkhtmltopdf’s rendering engine.

When should I switch to Puppeteer?

Consider it when the page depends on dynamic JavaScript or browser behavior that wkhtmltopdf cannot render as needed. Validate the output with your actual pages and PDF requirements.

Is wkhtmltopdf safe for user-supplied HTML?

The project explicitly warns against using it with untrusted HTML. Sanitize user-supplied HTML and JavaScript, and consider operating-system containment as part of your security design.