Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Wait for the data and the pixels, not an arbitrary number of milliseconds. Fetch the AJAX response, render it into the target element, mark that element ready, then wait for fonts and images before calling toPng or toJpeg. This makes the capture synchronize with application state instead of guessing when a slow request will finish.
The reliable sequence
The html-to-image package captures the DOM as it exists when its Promise-based function runs. If the request or rendering is still in progress, the output can contain a spinner, empty containers or only part of the report. Use this sequence:
- Set a loading state.
- Await the AJAX request and check its HTTP status.
- Render the response into the capture node.
- Expose a deterministic ready marker.
- Wait for fonts and image decoding that affect pixels.
- Call
toPng,toJpegor another capture function.
Browser implementation
import { toPng } from 'html-to-image';
function renderReport(data) {
return `<h1>${escapeHtml(data.title)}</h1>
<p>Total: ${data.total}</p>
<img src="${escapeAttribute(data.logoUrl)}" alt="">`;
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, c => ({
'&': '&', '<': '<', '>': '>',
'"': '"', "'": '''
}[c]));
}
function escapeAttribute(value) { return escapeHtml(value); }
export async function captureAfterAjax() {
const node = document.querySelector('#report');
if (!node) throw new Error('Missing #report element');
node.dataset.state = 'loading';
const response = await fetch('/api/report');
if (!response.ok) throw new Error(`Report request failed: HTTP ${response.status}`);
const data = await response.json();
node.innerHTML = renderReport(data);
node.dataset.state = 'ready';
if (document.fonts?.ready) await document.fonts.ready;
await Promise.all([...node.querySelectorAll('img')].map(img =>
img.decode ? img.decode().catch(() => undefined) : Promise.resolve()
));
return toPng(node);
}
Call it from an event handler and use the returned data URL as an image source or download. Set the ready marker only after the final DOM mutation. A selector such as #report[data-state="ready"] is therefore a useful contract for both browser code and hosted renderers.
Preventing stale responses
If users can request several reports, an older response may arrive after a newer one. Use an AbortController or request identifier, and only mark the currently selected report ready. Otherwise the capture can be internally consistent but show the wrong record.
#1 Best Overall
What html-to-image waits for—and what it does not
The library clones the node, copies computed styles, embeds web fonts and images, serializes HTML through SVG foreignObject, and rasterizes to a canvas for formats such as PNG. Its capture Promise represents that conversion work; it does not know that your AJAX request has finished unless your code awaits it first.
Fonts
Web fonts can change line breaks and element dimensions. document.fonts.ready waits for the document’s font-loading set before capture. If a font is optional or deliberately not loaded, capture after the fallback layout is the intended design instead.
Images
An image element can exist before its pixels are decoded. Calling img.decode() where available lets decoding finish without failing the whole capture when one optional image is broken. Verify that the final source is the one you expect before calling the library.
Free tools Windows power users keep installed
One-click scans. No signup required.
Animations and transitions
A ready marker can appear while CSS animation is still moving an element. Disable transitions for a capture-specific class, or add a short settling delay after the marker. A delay is a visual-settling tool, not a substitute for waiting on the request.
Using a hosted renderer with a readiness selector
When the page must be rendered outside the user’s browser, expose a completion element in the page and wait for it. HTML2IMG’s JavaScript integration uses waitForSelector; raw HTTP requests use wait_for_selector. The selector should identify completed content, not merely a container that exists during loading.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
await client.screenshot({
url: 'https://app.example/reports/42',
waitForSelector: '#report[data-state="ready"]',
msDelay: 400,
width: 1440,
height: 900
});
Prefer the selector whenever you control the markup: it returns as soon as the element exists, whereas a delay always waits its full duration. Keep a bounded timeout in your job system and report a clear error if the marker never appears.
Raw request spelling
For an HTTP payload, send the snake-case option:
{
"url": "https://app.example/reports/42",
"wait_for_selector": "#report[data-state="ready"]",
"ms_delay": 400
}
Do not mix the SDK’s camel-case name with the raw request name; an ignored option can result in a loading-state capture.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →AJAX content inside an iframe
A parent-page selector cannot inspect the DOM inside an iframe. If the widget is same-origin, have the outer page observe a message or callback and set its own ready marker:
window.addEventListener('message', event => {
if (event.origin !== 'https://widgets.example' || event.data?.type !== 'report-ready') return;
document.querySelector('#report').dataset.state = 'ready';
});
For a cross-origin iframe that cannot cooperate, use a bounded delay after the frame is expected to render. HTML2IMG documents a 1–5000 ms delay range for this fallback. A delay can still be too short on a slow connection, so prefer an outer-page marker whenever possible.
Cross-origin resources and canvas failures
The canvas becomes tainted when an image or other resource is fetched without suitable cross-origin permission. The result can fail when the library reads canvas pixels. Serve images with appropriate CORS headers, use same-origin assets, or proxy assets through an origin you control. Test fonts, CSS background images and SVG files as well as ordinary <img> elements.
Rank #3
Hosted renderers also need publicly reachable HTTPS resources. Private localhost URLs, authentication-only endpoints and blocked mixed-content requests cannot be loaded by a remote browser. Keep credentials in the renderer’s server-side configuration rather than exposing API keys in page JavaScript.
Why a fixed sleep is fragile
setTimeout(resolve, 2000) waits two seconds whether the response completed in 100 ms or 2.5 seconds. It wastes time on fast pages and captures incomplete content on slow ones. A state marker couples the capture to the actual completion condition. Use a delay only for animation settling, iframe limitations or another condition that cannot expose state.
Large pages, limits and operational choices
Browser-side capture
- Best when the data is already in the user’s session and no server credential should leave the browser.
- Subject to browser memory, canvas limits and data-URI limits for very large DOM trees.
- Cannot bypass cross-origin restrictions that the page itself does not satisfy.
Hosted capture
- Useful for scheduled jobs, consistent viewport sizes and server-side delivery.
- Requires public resources, careful secret management and a readiness selector or fallback delay.
- HTML2IMG documents a 30-second server-side script execution budget; design the AJAX endpoint and readiness path to finish within that limit.
For either approach, log the URL, readiness condition, viewport, response status and failure reason. Save the HTML state or request identifier when diagnosing intermittent captures, but avoid logging sensitive response data.
Troubleshooting checklist
The image shows a spinner or empty panel
The capture started before rendering completed. Await the fetch, mutate the node, and set the ready marker only afterward. For a hosted job, correct the selector spelling and verify that the marker is actually present.
The selector wait times out
Inspect the page in the same environment as the renderer. Common causes are an AJAX error, a selector that differs between success and failure markup, a private URL, or a marker set before the request finishes. Add an error state and make the job fail rather than silently returning a loading image.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Fonts or line wrapping differ
Wait for document.fonts.ready, ensure the font files are reachable with CORS, and capture at the intended device pixel ratio and viewport. A late font can change both dimensions and text placement.
Images are missing
Check each image’s final URL, wait for decoding, and inspect server response headers. A 404, blocked mixed-content request or CORS failure must be fixed at the resource origin; waiting longer cannot repair it.
Canvas or security error
Look for cross-origin images, SVGs or CSS backgrounds. Make them same-origin or configure appropriate CORS headers. Very large nodes may also exceed browser data limits; capture smaller elements or split the page.
The iframe remains blank
Selector waits do not inspect iframe contents. Add a postMessage-based outer marker, or use a bounded delay within the documented 1–5000 ms range and verify the frame’s network access.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Or skip the browser setup
ScreenshotNeo provides a hosted screenshot API and MCP server. It can wait for a selector, delay or network idle, while also handling full-page captures, lazy images, custom CSS and JavaScript, cookies, headers, viewport and device settings. Before the capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed.
One call returns an image or PDF:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for selector-wait parameters and the other 63 options. The same service can be used by AI agents through its MCP tools take_screenshot, get_page_info and capture_pdf.
Best Value
Python
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)
Node.js
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(`HTTP ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo free.
Frequently Asked Questions
Should I wait for the network request or for a DOM selector?
Wait for the request in browser code, then expose a selector that means the DOM is complete. Hosted capture can wait on that selector.
Can html-to-image capture a page by URL?
No. It captures a DOM node in the current browser context; use a hosted browser API when you need URL-based rendering.
Is a longer timeout a fix for CORS errors?
No. CORS, authentication and unreachable resources must be corrected at the resource or renderer configuration level.
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.

