wkhtmltoimage vs wkhtmltopdf for Capturing Web Pages
Choose wkhtmltopdf for PDF documents and wkhtmltoimage for image captures. Compare their commands, options, limitations, security, and alternatives.
wkhtmltopdf is for PDF output; wkhtmltoimage is for image output. Both are headless command-line tools from the same project and use Qt WebKit to render web pages. Choose based on the file your workflow needs, then check whether the page’s JavaScript, your installed build, and the input’s trust level are suitable for this older rendering stack. The project describes the tools and their purpose.
1. Choose by the output you need
| Need | Use | Why |
|---|---|---|
| A document to print, archive, or pass to a PDF workflow | wkhtmltopdf |
It renders HTML to PDF and supports documents assembled from webpage, cover, and table-of-contents objects. |
| A raster snapshot for an image workflow | wkhtmltoimage |
It renders HTML to an image file. |
| A dynamic site whose content appears after substantial client-side JavaScript runs | Consider a browser automation tool such as Puppeteer | The wkhtmltopdf project status page suggests Puppeteer or a wrapper for dynamic JavaScript sites. |
The tools share a rendering lineage, but their outputs are different kinds of artifacts. A PDF is a document format; an image is a raster capture. Do not choose one because it is universally “better.” Choose based on what consumes the result.
2. Install and identify the build
Install a package for your operating system or use the project’s download page, then record the exact version and source of the binary. The project download page lists 0.12.6 as its stable version, released June 11, 2020. GitHub marks the source repository archived on January 2, 2023. These are project facts; a distribution package or fork may differ.
wkhtmltopdf --version
wkhtmltoimage --version
wkhtmltopdf --extended-help
wkhtmltoimage --extended-help
Use the version-matched manual for the complete options. The generated manual cited here documents PDF options; do not assume it documents every image option. Some features require the project’s patched Qt, and distribution builds may omit those patches.
3. Convert a URL to PDF with wkhtmltopdf
The basic form is a source followed by an output path:
wkhtmltopdf https://example.com page.pdf
For a long document, set a page size or orientation with options supported by your installed build. This example requests A4 portrait output:
wkhtmltopdf --page-size A4 --orientation Portrait https://example.com report.pdf
PDF input is organized as objects. The manual describes webpage, cover webpage, and table-of-contents objects. Objects appear in command-line order; options can apply globally or to an individual object. Consult the manual for the precise syntax and option scope for your version before composing a multi-object document.
wkhtmltopdf \
cover https://example.com/cover \
https://example.com/report report.pdf
For example, this places a cover before the report webpage. A table of contents can also be included as an object; its availability and details depend on the installed build and options.
4. Convert a URL to an image with wkhtmltoimage
The corresponding image command takes a source and an image output path:
wkhtmltoimage https://example.com page.png
The project describes the output as image formats, but the available research does not establish a complete authoritative format list. Check your binary’s help and the version-matched documentation for the supported output formats and image-specific options.
In either command, use a fully qualified URL and ensure the machine running the process can resolve the hostname and reach the page. Save the result to a path writable by the process.
5. Rendering behavior and practical limits
- Headless operation: the project describes both programs as headless tools, so a display service is not required.
- JavaScript-heavy sites: a page may depend on browser behavior or client-side rendering that this older engine does not handle as expected. The project status page points to Puppeteer or a wrapper for dynamic JavaScript sites.
- Build differences: package source and patched Qt availability can affect features and output. Record the executable path, version, and package source when reproducing an issue.
- No reliable speed or fidelity ranking: the available sources do not provide comparative benchmarks. Measure with your own pages and environment if runtime or visual matching matters.
For controlled HTML report generation, the project status page also suggests considering WeasyPrint or Prince. Treat these as project-page recommendations, not as a verified ranking or claim about their current support, licensing, or performance.
6. Security and input trust
The project download page explicitly warns against using wkhtmltopdf with untrusted HTML and says user-supplied HTML or JavaScript should be sanitized. The status page explains concerns related to the age of its Qt/WebKit base. Treat rendering untrusted content as a security boundary: do not expose a privileged server environment to arbitrary HTML or scripts. Sanitization is not a substitute for reviewing isolation, network access, permissions, and the renderer’s execution environment.
This matters especially when generating files on a server from user-submitted content. Prefer a controlled input set and a constrained execution environment, and follow your organization’s security review process.
7. Reliability, performance, and cost
- Reliability: pin and document the exact build. Package variants may omit patches or behave differently, so do not assume identical behavior across operating systems.
- Performance: no benchmark in the cited project material establishes which command is faster. Measure representative pages, output size, and resource use on the deployment target.
- Failure handling: treat a missing or malformed output as a failed conversion; check the process exit status and logs, and verify the output file before passing it downstream.
- Cost: the tools are downloadable software in the project’s open-source distribution. This does not make operation free: account for the machine, maintenance, isolation, and engineering effort required to run and update a renderer.
8. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| Command not found | The executable is not installed or is not on the process PATH. | Install the package for the target environment, check the executable path, and run --version. |
| Output is blank or missing expected content | The page may need JavaScript, external resources, or access to a URL unavailable from the renderer. | Check network and DNS access, inspect page dependencies, and consider a browser automation tool for dynamic pages. |
| PDF option or feature is unavailable | The installed package may differ from the build expected by the documentation; some features require patched Qt. | Record the package source and version, inspect extended help, and consult the matching manual. |
| Output differs between machines | Different package builds, patched Qt support, or runtime environments can produce differences. | Compare executable versions, package sources, fonts, and accessible page resources. |
| Conversion fails on a server | Permissions, missing runtime dependencies, network restrictions, or an unwritable destination can prevent output. | Check process logs and exit status, destination permissions, dependencies, and outbound access. |
| Security review rejects the workflow | User-controlled HTML or JavaScript reaches an older renderer. | Keep untrusted input out of the process or redesign the isolation and trust boundary; follow the project’s warning. |
9. Or skip the browser setup
If you need a screenshot without installing and maintaining a renderer, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. See the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed; response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free account and get 1,000 screenshots a month with no card.
10. FAQ
Do both tools need a graphical desktop?
No. The project describes both as headless command-line tools.
Can wkhtmltopdf combine more than one page?
Its PDF model supports webpage, cover, and table-of-contents objects, ordered on the command line. Check the version-matched manual for syntax and option scope.
Is wkhtmltoimage the right choice for a web page that builds its content in JavaScript?
It may not be. The project status page suggests Puppeteer or a wrapper for dynamic JavaScript sites.
Are package builds interchangeable?
No guarantee of identical behavior is established. The project notes that some features require patched Qt, and distribution builds can omit those patches.
