How to Capture JavaScript-Rendered Pages with wkhtmltoimage
Use wkhtmltoimage’s JavaScript and wait options to capture client-rendered pages. Learn how to choose a delay, signal readiness, and troubleshoot incomplete images.
wkhtmltoimage can capture JavaScript-rendered pages if the scripts run before the image is taken. JavaScript is enabled by default; the main timing controls are --javascript-delay, which waits a fixed number of milliseconds, and --window-status, which waits for a page-set readiness value. Start with a delay, inspect the output, and use a readiness signal when you control the page and have confirmed that your installed build honors it.
This guide covers the command-line workflow, page-side readiness code, relevant options, diagnostics, and the limitations that matter when rendering modern pages. The exact behavior can vary by packaged build, so verify against the binary and target URL you will use.
1. Check the installed build
Different distributions may package different wkhtmltoimage builds. Record the version before debugging timing behavior:
wkhtmltoimage --version
Keep the command output with your deployment notes. The upstream GitHub repository was archived in January 2023; its documentation and issue tracker are useful references, but do not imply ongoing upstream fixes. [project repository]
2. Capture with a fixed JavaScript delay
JavaScript is on by default, so do not add --disable-javascript. The documented default JavaScript delay is 200 milliseconds. That is a default, not a guarantee that an application has finished rendering. Set a longer delay when the page needs time to fetch data or paint client-rendered content:
wkhtmltoimage --javascript-delay 2000 https://example.com/page capture.png
The number is milliseconds: 2000 means two seconds. Replace the URL and output filename with your target and desired format. Use an appropriate extension such as .png or .jpg; inspect the resulting file rather than assuming that a successful process exit means the target content appeared.
When a fixed delay is a good fit
- You cannot modify the page to expose a readiness signal.
- You have measured a reasonable render time for the target in the environment where capture runs.
- A small amount of extra waiting is acceptable.
A fixed delay can still capture too early when the page is slow, or waste time when the page is fast. It also cannot repair JavaScript exceptions, failed network requests, authentication failures, or unsupported browser behavior.
3. Wait for a page-controlled readiness signal
If you control the page, it can set window.status after the content you need is ready. Then request that exact value:
wkhtmltoimage --window-status ready https://example.com/page capture.png
The command-line option is documented to wait until window.status equals the supplied string. The page must set the same value, including capitalization. For example, add a signal after your application has rendered the target content:
<script>
renderApplication().then(() => {
window.status = 'ready';
});
</script>
renderApplication() here represents your own app’s render or data-loading completion. Do not copy it as a browser API; connect the assignment to the event or promise your application already uses to know that the relevant content is ready.
Test this with the exact installed binary and page. Archived issue reports record both wait-option problems and variability in observed behavior, including reports of waiting indefinitely. Those reports are historical and do not establish that the option fails in every build. Avoid assuming that combining --javascript-delay and --window-status has a portable timeout or “whichever comes first” behavior; verify the combination in your environment. [wait-option report] [window-status report] [delay and status discussion]
4. Diagnose missing or incomplete content
Check these causes in order:
- JavaScript was disabled. Remove
--disable-javascript; JavaScript is enabled by default unless disabled. - The page had not finished rendering. Increase
--javascript-delayand compare captures at different waits. A delay only helps if the page is still progressing. - Scripts or resources failed. Check the target page’s scripts, data requests, and assets in its normal browser context. Waiting longer does not fix blocked or failing requests.
- The status value was not set or did not match. Confirm the page assigns
window.statusafter the needed content is ready and that it exactly matches the--window-statusargument. - The packaged build behaves differently. Reproduce with a minimal page and the same binary, then verify the wait option with that build. A historical project issue records a wait-option regression and a fix associated with milestone 0.12.2.1; build provenance still matters. [issue #2142]
- The page relies on behavior the renderer cannot reproduce. If a minimal page still fails because of browser-feature compatibility, use a current browser automation renderer suited to the page and verify its output.
For script errors, enable JavaScript diagnostics:
wkhtmltoimage --debug-javascript --javascript-delay 2000 https://example.com/page capture.png
Reduce failures to a minimal page where possible. This helps distinguish a timing problem from a script error, unavailable resource, or build-specific behavior.
5. Relevant options and practical choices
| Option | What it does | Use it when |
|---|---|---|
--javascript-delay <milliseconds> |
Waits the configured number of milliseconds for JavaScript. The documented default is 200 ms. | You need a straightforward wait and cannot change page code. |
--window-status <string> |
Waits until the page’s window.status equals the supplied string. |
You control the page and can set a signal after the required content is ready. |
--debug-javascript |
Enables JavaScript debugging output. | You need to investigate script errors during capture. |
--disable-javascript |
Disables JavaScript. | Generally avoid it for client-rendered pages; it defeats their rendering. |
These controls are documented by the wkhtmltoimage command-line usage documentation; the Debian manpage also lists the image command’s JavaScript and wait options.
6. Performance, reliability, and cost
A longer fixed delay increases capture time whether the page needs it or not. A page-controlled signal can avoid choosing one large delay, but only if it is set reliably and the installed binary responds to it. For repeatable jobs, record the binary version, use a representative target page, and validate the output after changing the package or environment.
Neither wait option guarantees that every resource loaded successfully or that all page content is correct. Treat rendering completion and capture success as separate checks in automated workflows. Cost depends on your own compute and hosting; the research sources do not establish a universal runtime, success rate, or cost per capture for wkhtmltoimage.
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. For a one-call capture, use the API; see the ScreenshotNeo API documentation for options and setup.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/page -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/page"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/page' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Replace YOUR_API_KEY with your API key. The Node.js example uses Bun’s file writer; with Node.js, save the response body using your preferred filesystem API. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. 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.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Is JavaScript enabled by default?
Yes. The documented default is enabled. Do not pass --disable-javascript when the page needs client-side rendering.
Is 200 milliseconds enough?
It is the documented default delay, not a guarantee. Applications that fetch data or render asynchronously may need more time or a page-controlled readiness signal.
Can I rely on --window-status for every installation?
No single command-line option removes the need to verify your packaged build. Confirm that the page sets the exact value and test the capture with the binary you will run.
What if I cannot change the target page?
Use a fixed delay and inspect the image. If the page still cannot render correctly in your installed build, choose a renderer that supports the page’s required browser behavior.


