What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If html2canvas captures a div but leaves its images blank, check the image request and origin before changing CSS. The usual cause is a cross-origin image: html2canvas defaults to allowTaint: false and will skip an image that would taint the canvas. Set useCORS: true only when the image server returns an appropriate Access-Control-Allow-Origin header. If you do not control that server, serve the image from your own origin or use a controlled proxy.

Start with a minimal, observable capture

Pass the actual element you intend to render, turn on logging, and inspect the result in the browser console:

const target = document.querySelector('#capture');

if (!target) {
  throw new Error('The #capture element was not found');
}

const canvas = await html2canvas(target, {
  useCORS: true,
  logging: true,
});
document.body.appendChild(canvas);

This code does not bypass a server’s CORS policy. It succeeds for a remote image only when that host permits the browser’s cross-origin request. If the image host sends no suitable header, the image can still be omitted even though useCORS is enabled.

Work through the failure in the right order

1. Confirm the element and image exist

Verify that document.querySelector('#capture') returns the div you expect. In the Elements panel, inspect every <img> inside it, including the final value of src after any framework or lazy-loading code has run. A selector aimed at a wrapper that is empty, hidden, or different from the visible component cannot capture an image that is not in that subtree.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Also inspect computed styles. Check display, visibility, opacity, dimensions, and whether an ancestor clips or hides the image. html2canvas renders a cloned document, so the clone—not only the original DOM—is what ultimately matters.

2. Verify that the browser actually loaded the resource

Open the image URL directly and use the Network panel while running the capture. Look for failed requests, redirects, 401/403 responses, authentication requirements, mixed-content blocking, and requests that remain pending. An image that has not loaded by capture time cannot be reconstructed.

Enable diagnostics and give slow resources a bounded window:

const canvas = await html2canvas(document.querySelector('#capture'), {
  logging: true,
  imageTimeout: 30000,
  onclone: (clonedDocument) => {
    const clonedTarget = clonedDocument.querySelector('#capture');
    console.log('Clone used for capture:', clonedTarget);
  },
});

The documented default for imageTimeout is 15,000 milliseconds. Increasing it helps only when logs show a slow load; it cannot grant cross-origin permission.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Compare the page and image origins

Origins differ when the scheme, host, or port differs. A page at https://app.example.test and an image at https://cdn.example.test are cross-origin even though they share a parent domain. The same is true for an HTTP/HTTPS mismatch or a different port.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

For a cross-origin <img>, html2canvas can attempt a CORS load:

const canvas = await html2canvas(document.querySelector('#capture'), {
  useCORS: true,
  logging: true,
});

The image server must answer with an appropriate Access-Control-Allow-Origin value (your exact origin, or a policy suitable for your deployment). A client-side option cannot add that response header. If credentials are involved, the server and request must also follow the browser’s credentialed-CORS rules; otherwise remove the credential requirement or use a same-origin delivery path.

4. Choose a delivery route you control

  • Configure the image host: return the required CORS response header and keep useCORS: true.
  • Serve the asset same-origin: copy or reverse-proxy approved assets through the application’s own origin.
  • Use a private proxy: set html2canvas’s proxy option to an endpoint you operate and secure.

A proxy must retrieve only resources your application is authorized to access. Do not point production code at a public arbitrary-URL proxy: it can become a server-side request-forgery, data-exfiltration, or abuse service. Validate destination hosts, restrict protocols, apply size and time limits, and avoid forwarding sensitive cookies.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Inspect the cloned document

onclone receives the cloned document before rendering. Use it to log the cloned image URLs, remove a transient overlay, or make a capture-only style adjustment without changing the live page:

await html2canvas(document.querySelector('#capture'), {
  useCORS: true,
  onclone: (clonedDocument) => {
    clonedDocument.querySelectorAll('img').forEach((img) => {
      console.log('Cloned image:', img.currentSrc || img.src);
    });
    clonedDocument.querySelector('#loading-spinner')?.remove();
  },
});

This hook diagnoses clone differences; it does not bypass browser security.

Common image-specific cases

Remote images with no CORS header

Symptoms include a missing image while the rest of the div renders, and console or html2canvas log messages associated with a cross-origin resource. Fix the response policy on the image server, move the file to the page’s origin, or use your secured proxy. Setting allowTaint: true is not an export fix: it permits a tainted canvas, which cannot be safely read with APIs such as toDataURL() or getImageData().

Images loaded lazily

Scroll the image into view or otherwise trigger the application’s lazy-loader before calling html2canvas. Confirm in Network and Elements that the real URL has replaced a placeholder such as data-src. If your capture needs a long page, wait for the application’s own loading condition rather than relying on an arbitrary short delay.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CSS background images

A background-image is not an <img>. Inspect the target in the computed-style panel and verify that background-image resolves to the expected URL in the clone. Apply the same origin and loading checks. A background can also be absent because the relevant CSS property or effect is not implemented by html2canvas.

Redirects, protected files, and expiring URLs

Test the final URL shown in the Network panel, not only the URL in your source code. A redirect can land on another origin; a signed URL can expire between page load and capture; and a protected endpoint may require headers or cookies unavailable to the cloned request. Resolve those conditions at the delivery layer or capture after valid authentication is established.

What html2canvas can and cannot reproduce

html2canvas rebuilds the image from the DOM and supported CSS; it is not a native, pixel-perfect browser screenshot. The project’s FAQ states: “Every CSS property must be manually implemented to render correctly, so html2canvas will never have full CSS support.” Consequently, an asset may load successfully yet still look different or disappear when its layout depends on an unsupported property, filter, blend mode, pseudo-element, or complex effect.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • 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

Use a reduced test case to separate origin problems from rendering support:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<div id="capture" style="background:#fff;padding:16px">
  <img src="/images/test.png" alt="Test" style="display:block;width:200px;height:auto">
</div>

If this same-origin, simple image works, add the original styles and assets one at a time. That identifies the first unsupported or incorrectly loaded feature instead of changing several options at once.

Option reference and trade-offs

Option or technique Use it when What it does not solve
useCORS: true The remote host can send a suitable CORS header. It cannot change the host’s response policy.
proxy You operate a controlled endpoint that can fetch the asset. It does not make an unsafe public proxy acceptable.
Same-origin serving You can store or reverse-proxy the image through your origin. It requires ownership or authorization to redistribute the asset.
allowTaint: true You only need a visual canvas and will not read or export its pixels. A tainted canvas cannot be read; it is not a general CORS repair.
imageTimeout Logs show the image is slow to load. It cannot fix CORS, a 404, authentication, or unsupported CSS.
onclone The live and cloned DOM differ or needs capture-only edits. It cannot bypass browser security or implement missing CSS support.
logging and onError You need evidence about loading and rendering failures. Diagnostics report a problem; they do not repair the resource.

Troubleshooting by symptom

The whole div is blank

  • Confirm the selector returns an element with nonzero dimensions.
  • Check whether an ancestor is hidden, detached, or covered by a capture-time style.
  • Look for JavaScript exceptions before the html2canvas call.
  • Reduce the case to a same-origin text block and one local image.

Only remote images are missing

  • Compare origins and inspect the image response headers.
  • Enable useCORS and configure the image server, or choose same-origin delivery.
  • Check redirects and credentials in Network.

The image appears intermittently

  • Capture only after the image’s complete state and natural dimensions indicate it loaded.
  • Wait for the app’s lazy-loader or use a justified imageTimeout increase.
  • Check expiring signed URLs and cache behavior.

The canvas is present but export fails

One or more images probably tainted it. Do not rely on allowTaint: true when you need an export. Make every exported image same-origin or CORS-authorized, then create the canvas again.

The image loads but styling is wrong

Inspect computed styles in onclone, simplify the CSS, and test the property in isolation. html2canvas’s DOM/CSS reconstruction has incomplete CSS coverage, so a native browser capture may be required for effects it does not implement.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and security notes

Capture the smallest element that satisfies the requirement instead of an entire document. Large full-page clones consume more memory and take longer, especially when images are high-resolution. Set an explicit image timeout appropriate to your network, but avoid unbounded waits. Keep logging enabled while diagnosing and disable verbose logging in normal production use.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Preload critical images through your application’s normal loading path, then capture after they report success. Cache headers and signed-URL lifetimes should cover the capture window. A proxy should enforce an allow-list, maximum response size, timeout, content-type checks, and rate limits. Never expose private cookies or authorization headers to an untrusted image host.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP, or PDF, so you do not need to debug html2canvas’s DOM reconstruction in your application. Before capture it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

See the parameter reference and options in the ScreenshotNeo documentation. The API supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or a custom viewport, retina scale, PDF paper and page controls, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for a selector, delay or network idle, request and resource blocking, custom headers, cookies, user agent and Authorization, timezone and geolocation, transparent backgrounds, resizing, a chosen cache TTL, signed public-image links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API, and an OpenAPI specification.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

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(`${res.status} ${res.statusText}`);
const bytes = Buffer.from(await res.arrayBuffer());
require('node:fs').writeFileSync('shot.webp', bytes);

Every feature is on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots. Yearly billing provides two months free. Create a free ScreenshotNeo account to try the capture without a card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does html2canvas work in Node.js by itself?

No. It runs in a browser and depends on browser APIs. A Node.js script needs a browser environment, or you can use a browser-based screenshot service.

Can I fix a missing image by adding an HTML crossorigin attribute?

Only when the image server is configured for the matching CORS request. The attribute changes how the browser requests the resource; it cannot add permission to the server response.

Why does opening the image URL in a new tab succeed while capture fails?

Direct navigation does not prove that the image is permitted for a canvas. Canvas use requires the image response and request mode to satisfy CORS, and redirects or credentials can change the result.

Should I wait for network idle before calling html2canvas?

It can help an application finish loading, but it is not a universal readiness signal. Confirm the specific image request completed and that lazy-loading code has assigned its final URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.