First identify which stage is failing: the page itself may not load, an image or stylesheet may be unreachable, JavaScript may not have finished rendering, or the renderer may be waiting on the same server that is waiting for the PDF. The fix depends on the Ruby wrapper and rendering engine—especially whether you use PDFKit or Wicked PDF with wkhtmltopdf, or Grover with Puppeteer and Chromium.
Check the exact gem and renderer versions deployed before applying an option: similarly named wrappers do not share every setting. The wkhtmltopdf settings described here are from its documentation for version 0.12.6 with patched Qt.
Identify the failure before changing settings
A Ruby exception alone does not show whether navigation, an individual request, JavaScript, or PDF generation failed. Capture the full exception and renderer output, then classify the symptom:
- The page fails to load: the top-level URL returned an error or could not be reached. For wkhtmltopdf, page-load handling is separate from media handling.
- The PDF opens, but assets are missing: inspect the CSS, image, font, or script URLs from the renderer’s environment. A browser on your workstation may resolve a path that a subprocess in a container cannot.
- Content is absent or stale: the page may depend on JavaScript that has not populated the DOM when the renderer captures it.
- The request hangs: check whether the renderer is making HTTP requests back to the same single-thread server that is occupied waiting for the PDF operation.
- The page looks complete but no PDF is returned: distinguish navigation or launch timeouts from a timeout during PDF conversion.
Record the Ruby gem, renderer or browser version, operating system or container image, full error text, and command-line options. With wkhtmltopdf, verbose output and stderr can help expose which URL failed.
Recommended Free Tools
#1 Best Overall
Set wkhtmltopdf error handling deliberately
PDFKit and Wicked PDF use wkhtmltopdf; the Ruby wrapper does not change the renderer’s underlying resource-loading behavior. In wkhtmltopdf 0.12.6 with patched Qt, the documented page-load default is abort, while the media-load default is ignore. The command-line options --load-error-handling and --load-media-error-handling each document abort, ignore, and skip. Confirm those options exist in the binary actually deployed using the wkhtmltopdf command-line documentation.
Do not start by ignoring every error. If a logo, a legal notice, or a chart is missing, a successful conversion with incomplete content may be worse than a failed job. First identify the failing URL and decide whether omission is acceptable. Then choose handling for that class of failure, and validate the resulting PDF.
Make page resources reachable from the renderer
When the HTML works in a browser but the PDF lacks CSS, images, or scripts, test each generated URL from the machine or container running the renderer. Check whether it is relative, whether the host resolves there, whether authentication is needed, and whether the process has permission to read the relevant file.
Rank #2
PDFKit and raw HTML
The PDFKit README recommends absolute paths for resources and complete file paths or domain-qualified URLs for raw HTML. Its root_url setting may help when the external hostname is not available from the server. Use a path that is valid in the renderer’s execution context, not merely one that works in a developer’s browser.
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 →Rails assets with Wicked PDF
For Rails views, use Wicked PDF’s asset helpers where appropriate, verify the configured asset host and paths in production, and precompile assets referenced by PDF views. Development and production can serve assets differently, so a view that works locally may produce missing resources after deployment. Consult the Wicked PDF README for the configuration supported by your installed version.
Test resources separately
- Save the exact HTML passed to the renderer.
- List its referenced stylesheets, images, fonts, and scripts.
- Open or request each URL from the renderer’s host, using the same scheme, credentials, and network access the job has.
- Fix incorrect URLs, permissions, asset-host configuration, or container networking before changing error handling.
Check for a self-request deadlock
A PDF request can stall when the Ruby web server has one worker or thread: the server is handling the PDF request and waiting for wkhtmltopdf, while wkhtmltopdf requests an image, stylesheet, or script from that same server. The server cannot answer the resource request until it finishes the original PDF request. PDFKit documents this cycle and identifies a server with multiple workers or embedding resources to avoid extra HTTP requests as workarounds in its troubleshooting documentation.
Rank #3
To diagnose it, inspect the requested asset host and server logs while the job is stuck. If the renderer is calling back into the application, test with embedded resources or a server configuration that can service the additional request concurrently. Avoid treating a longer timeout as a fix for a request cycle that cannot make progress.
Wait for JavaScript content using the right engine controls
wkhtmltopdf-backed wrappers
wkhtmltopdf enables JavaScript by default and documents a JavaScript delay whose default is 200 milliseconds. That fixed delay is not evidence that an asynchronous application has finished rendering. If PDF content depends on JavaScript, determine what condition indicates readiness; increasing the delay can be a diagnostic or a known timing workaround, but an arbitrary wait can still capture too early or waste time. Disable JavaScript only when the required PDF content does not depend on it. See the wkhtmltopdf usage documentation for the exact options supported by the documented version.
Grover with Puppeteer and Chromium
Grover exposes separate launch, request, and PDF-conversion timeouts. Its README also documents waits for selectors, functions, or timeouts, plus options to raise errors for failed requests and uncaught JavaScript errors. For dynamic content, prefer waiting for a meaningful selector or function over adding a long fixed sleep. When the failure is unclear, enabling request- or JavaScript-error raising can make the underlying issue visible. Check the Grover README for the API and option names that match your installed version.
Rank #4
Keep renderer access secure
Do not enable broad local-file or internal-network access just to make an asset error disappear. wkhtmltopdf documents local-file access as disabled by default unless explicitly allowed. Wicked PDF advises sanitizing user-generated HTML, CSS, and JavaScript or disallowing requests to internal IP addresses and hostnames.
Grover’s README warns that enabling file URIs improperly can expose sensitive files. It also describes local-network access as disabled by default for Puppeteer v24.16.0+/Chrome 139+ behavior; that version-specific statement should not be generalized to other installed versions. For user-controlled HTML, sanitize input and restrict which resources the rendering job can reach. See the wkhtmltopdf usage documentation, Wicked PDF README, and Grover README.
Choose diagnostics that match your wrapper
PDFKit and Wicked PDF delegate to wkhtmltopdf, so their troubleshooting includes executable availability, command options, and the subprocess’s filesystem and network view. Grover uses Puppeteer and Chromium, so browser launch, page request, readiness, and PDF-conversion errors have their own timeout and reporting controls. The cited project documentation describes capabilities, not comparative performance results; neither wrapper is universally faster or more reliable based on that evidence.
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 problemsBest Value
- For a wkhtmltopdf-backed job: capture stderr, confirm the executable version and options, then isolate the page URL from media URLs.
- For Grover: separate browser-launch problems from page requests and conversion timeout; enable relevant error reporting and wait on actual content readiness.
- For either: confirm that deployment permits the subprocess or browser to run and that required resources are accessible without opening unintended local or network access.
Troubleshooting checklist
- Reproduce the failure: save the HTML and record the wrapper gem, renderer/browser version, operating system or container, exception, and settings.
- Separate page from media: test the main page and then each stylesheet, image, font, and script independently.
- Check the execution context: verify absolute URLs, file paths, host resolution, credentials, permissions, asset precompilation, and container network access.
- Investigate hangs: look for renderer requests back to a single-thread server occupied by the original PDF request.
- Check readiness and timeout stage: determine whether JavaScript content is ready and whether time expires at launch, navigation/request, wait, or conversion.
- Use tolerant handling only intentionally: select page or media error behavior based on whether missing output is acceptable, then inspect the PDF for omissions.
- Limit access: keep local-file and internal-network access restricted for untrusted HTML; allow only required resources.
- Escalate with a minimal case: include wkhtmltopdf’s version, OS/version, and compact reproducible HTML/CSS/JS when reporting a wkhtmltopdf issue, as requested by its reporting guidance.
Or skip the browser setup
If your source is a publicly reachable page and a rendered-page PDF is suitable, ScreenshotNeo can return a PDF from a single GET request. It is a website screenshot API, not a drop-in Ruby HTML-to-PDF gem for arbitrary local HTML; this route requires a URL the service can fetch.
For the API options and response details, see the ScreenshotNeo documentation. This cURL example saves a PDF response:
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
ScreenshotNeo accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to try it with 1,000 screenshots a month and no card.
Frequently asked questions
What should I include in a bug report for wkhtmltopdf?
Include a minimal reproducible HTML/CSS/JavaScript example and the wkhtmltopdf version and operating-system version, along with the failure details and relevant options.
Is a missing image a page-load error?
Not necessarily. wkhtmltopdf distinguishes failure to load the page from failure to load media, so identify the particular request before choosing handling behavior.
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.

