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 problemsIf html2canvas logs Finished rendering, its renderer has reached the point where it returns a canvas; look next at your code after the call, such as canvas export, upload, or UI updates. If that message never appears and the Promise stays pending, instrument the work before the return boundary and check resource loading, the cloned DOM, and render dimensions. There is no single established cause for an unspecified “stalling after rendering” report.
First establish whether html2canvas has returned
html2canvas returns a Promise for an HTMLCanvasElement. Its source logs Finished rendering before returning the canvas (after optional cleanup of the temporary cloned container). That gives you a useful dividing line: the log appearing means the next step is to inspect your caller; its absence means the renderer has not reached that boundary.
Start by timing the call and reporting failed resources:
console.time('html2canvas');
const canvas = await html2canvas(element, {
logging: true,
onError: (error) => console.warn('html2canvas resource failed:', error.message),
});
console.timeEnd('html2canvas');
console.log('canvas returned', canvas.width, canvas.height);
Run this in an async function or other valid async context. With logging enabled, compare the library’s last message with Finished rendering and with your own “canvas returned” message. The onError callback helps expose resource failures; html2canvas can continue rendering after one.
Recommended Free Tools
#1 Best Overall
If the completion message appears
Temporarily remove or instrument each operation after the awaited call. Common next steps to inspect include canvas.toDataURL(), canvas.toBlob(), inserting an image into the DOM, uploading the result, or triggering a large UI/state update. This is a diagnostic sequence, not a claim that any one of those operations is inherently faulty.
If the completion message does not appear
Time the work you control before and around the call: when the target’s resources become ready, how large the target is, and what your onclone callback does. Try a small target element as a comparison. A smaller target that completes while the full page does not narrows the investigation toward the target, its resources, or the rendering work; it does not by itself identify a root cause.
Check canvas dimensions, scale, and memory demand
A long or large target can produce a canvas that exceeds a browser or platform’s limits. The html2canvas FAQ warns that such limits vary and that an oversized canvas may be blank or partially rendered without a clear error. Dimensions are therefore worth checking, but the available documentation does not establish large dimensions as the cause of every apparent hang.
For a long element, the FAQ documents setting the rendering window from the element’s scroll dimensions:
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 →Clear out junk files and repair common Windows errorsFree Scan →Rank #2
await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
The configuration reference also documents explicit width and height, plus scale, which defaults to the browser’s device pixel ratio. As a practical diagnostic, try a lower scale or a smaller capture region and compare both completion and output. A lower scale reduces the output’s pixel dimensions; it can also affect visual sharpness, so use it only if the result remains suitable for your purpose.
windowWidth and windowHeight set the window dimensions used for rendering. Because those dimensions can affect CSS media queries, changing them can change the layout as well as the capture size. Confirm that the resulting layout is the one you intended.
Inspect cross-origin images and other resources
By default, allowTaint is false. html2canvas skips images that would taint the canvas. To include an image hosted on another origin, useCORS: true can be used only when that host permits the request with the required CORS headers; otherwise, use a proxy you control. The library cannot bypass the browser’s content security rules.
const canvas = await html2canvas(element, {
logging: true,
useCORS: true,
onError: (error) => console.warn('Resource failed:', error.message),
});
Use useCORS only when cross-origin assets are relevant and their servers allow CORS. Inspect the browser’s network panel for failed requests, redirects, and response headers. A resource URL that starts on your own origin may redirect to a CDN, so check the final request destination rather than assuming the original URL tells the whole story. A single 2023 GitHub issue describes a user’s difficulty with a same-origin URL redirecting to a CDN while using useCORS; it is an individual report, not proof of a general library bug or a confirmed fix.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Review cloned-document work and cleanup options
html2canvas works from a cloned representation of the document. The onclone callback lets you make changes to that cloned document without modifying the live page. If your callback runs custom code, log its start and end and make sure it does not wait indefinitely on an event or resource.
removeContainer: true cleans up the temporary cloned DOM. It is a cleanup option, not a general-purpose remedy for a capture that never finishes. Keep it if you want that cleanup, but do not treat toggling it as evidence that you have fixed the underlying cause.
Consider repeated captures and shared image caching
If the issue occurs only after many captures in a long-lived page, review image-cache use as well as dimensions and resource readiness. The current configuration reference documents clearImageCache for releasing shared image-cache memory and maxCacheSize for limiting the shared cache.
Take care with clearImageCache: the documentation cautions against clearing a cache shared by concurrent captures. Coordinate cache changes with your capture lifecycle rather than clearing shared state while other jobs may be using it. Cache pressure is a possibility to investigate in repeated-capture cases, not an established explanation for a particular application without evidence.
Rank #4
Know when DOM reconstruction is the wrong capture method
html2canvas does not take a native screenshot of the browser window. It reconstructs an image from DOM information and the CSS features it implements, so its output is not guaranteed to be pixel-identical to what the browser displays. Unsupported CSS may render incorrectly. It also cannot read the contents of cross-origin iframes because of browser security restrictions.
- For a browser extension: the html2canvas FAQ points to native extension screenshot methods such as
chrome.tabs.captureVisibleTab()orbrowser.tabs.captureVisibleTab()when you need a screenshot from the extension context. - For server-side capture: the project’s getting-started material points to Puppeteer or Playwright, which drive a real headless browser. These are alternatives when capture needs to run server-side, not proven fixes for a specific html2canvas stall.
- For an in-page capture: html2canvas may still fit when a DOM-derived rendering is acceptable and you need to capture an element in the user’s browser.
Or skip the browser setup
If your actual goal is to request a screenshot of a URL from an application or script, rather than render an element in the current page, ScreenshotNeo offers a website screenshot API and MCP server. It is a different capture path, not a fix for a hung html2canvas call that your page still needs to make.
One GET request returns an image or PDF. This cURL example requests WebP for Stripe; see the ScreenshotNeo API documentation for request options and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
For 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}`);
ScreenshotNeo accepts cookie and 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 and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and whether the request was billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Free tools Windows power users keep installed
One-click scans. No signup required.
Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.
Best Value
Troubleshoot by symptom
| Symptom | What to check | Next action |
|---|---|---|
Finished rendering appears, but the page seems stuck |
Whether your own next log runs; export, upload, image insertion, and UI-update code | Temporarily remove each post-render operation, then time them individually. |
| No completion message; one or more images fail | Network errors, redirects, final host, and CORS response headers | Use onError; enable useCORS only if the host permits it, or use an appropriate proxy. |
| Blank or partial output | Canvas dimensions, target size, scale, and browser/platform limits | Try a smaller region or lower scale; for long elements, set window dimensions from scroll dimensions. |
| It fails after repeated captures | Whether calls overlap and whether they share the image cache | Review maxCacheSize and cache lifecycle; do not clear a cache while concurrent captures share it. |
| Output differs from the visible browser page | Unsupported CSS, cross-origin iframe content, or cross-origin image policy | Decide whether DOM reconstruction is sufficient or whether a native extension or headless-browser capture better fits. |
What to include in a useful bug report
“Stalling after rendering” does not identify a universal defect. To make the behavior diagnosable, include the html2canvas version, browser and platform, a minimal reproduction, timing/log output, target dimensions, and whether Finished rendering appears. Also note which resources fail and whether the problem occurs on the first capture or only after repeated or concurrent captures. These details distinguish an unfinished render from work performed after the Promise resolves.
Frequently Asked Questions
Does removeContainer: false make html2canvas finish faster?
The option controls cleanup of the temporary cloned DOM. Its documentation does not establish changing it as a general hang fix or speed improvement.
Can html2canvas capture the contents of a cross-origin iframe?
No. Browser security restrictions prevent it from accessing cross-origin iframe contents.
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.

