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

An “Uncaught TypeError” is not one html2canvas error. The useful fix starts with the complete exception text and stack trace, then follows the failing operation: browser runtime, resource loading, DOM/CSS cloning, canvas geometry, or export. Record the browser and version, html2canvas version, element being captured, and every option before changing code. Without that information, blaming CORS, CSS, or canvas size is guesswork.

What html2canvas is—and what it is not

html2canvas runs in a browser and reconstructs an image from the target element’s DOM and CSS. It does not take a native screenshot of the rendered tab. The library reads the document, clones relevant nodes, loads resources it is permitted to read, and paints an approximation onto a canvas. Its output therefore depends on browser APIs, same-origin rules, and which CSS properties the library implements.

The html2canvas project FAQ states: “Every CSS property must be manually implemented to render correctly, so html2canvas will never have full CSS support.” An unsupported style can produce an incorrect or blank result without throwing a TypeError, so a thrown exception should be diagnosed separately from visual fidelity.

1. Capture the exact failure before changing anything

Open DevTools, reproduce the capture once, and save:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • The entire “Uncaught TypeError” message, including the expression that is undefined or not a function.
  • The complete stack trace and the first frame in your own code.
  • Browser name and version, operating system, html2canvas package version, and whether the page is local, deployed, or inside an iframe.
  • The selected element’s tag, dimensions, and relevant options such as useCORS, allowTaint, scale, windowWidth, and windowHeight.

A generic headline cannot identify a unique throwing expression or a version regression. Do not apply a blanket “upgrade html2canvas” fix; first identify the installed dependency and then check that version’s release information.

2. Verify that the code is running in a browser

html2canvas is client-side code. Calling it directly in Node.js fails because Node does not provide the normal DOM, layout, image, and canvas browser APIs. If your stack trace contains missing window, document, or browser constructors, the runtime is the cause.

Run the capture after the page has loaded, or use a real browser controlled by Puppeteer or Playwright for server-side work. A minimal browser-side call is:

import html2canvas from 'html2canvas';

const element = document.querySelector('#invoice');
if (!element) throw new Error('Cannot find #invoice');

const canvas = await html2canvas(element);
document.body.appendChild(canvas);

If you need a server-generated image, launch Chromium with Puppeteer or Playwright, navigate to the page, and execute this code in the page context—or use the automation library’s native screenshot function. Do not import html2canvas into a bare Node process and expect a DOM to appear.

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

3. Separate rendering errors from export errors

Render the canvas first, inspect it, and only then export it. This distinguishes an html2canvas failure from a security exception raised by toDataURL() or another readback API.

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

console.log({ width: canvas.width, height: canvas.height });
if (!canvas.width || !canvas.height) {
  throw new Error('html2canvas returned an empty canvas');
}

const png = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.download = 'invoice.png';
link.href = png;
link.click();

If html2canvas throws before the “canvas dimensions” log, investigate runtime, cloning, resources, and CSS. If the canvas exists but export raises a security error, investigate cross-origin images and tainting; that is not necessarily a TypeError inside html2canvas.

4. Diagnose cross-origin images correctly

Images, fonts, or other resources from another origin must be served with permission for your page to read them. Setting useCORS: true requests CORS-enabled loading; it cannot manufacture an Access-Control-Allow-Origin response on a server that does not send one.

const canvas = await html2canvas(document.querySelector('#gallery'), {
  useCORS: true,
  imageTimeout: 15000
});

Inspect the image request in DevTools Network and confirm that the response includes a suitable CORS header for your page’s origin. Also check that the image URL is not redirecting to a host with different policy. If you cannot change the image server, use a correctly configured proxy that fetches the image server-side and serves it from an origin your page may read.

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

allowTaint is not an export workaround. With the documented default of false, html2canvas avoids resources that would taint the canvas. Allowing taint can let pixels be painted, but a tainted canvas remains unreadable to toDataURL(), toBlob(), and pixel APIs. Fix the server policy or proxy instead.

For a quick isolation test, temporarily replace external images with same-origin or data URLs. If the capture then works, restore resources one at a time and correct the failing response rather than changing unrelated CSS.

5. Reduce the DOM and CSS until the failing node is obvious

Start with a small element instead of the whole page. Remove one complex component at a time—filters, masks, blend modes, transformed containers, embedded frames, custom fonts, and large background images are useful suspects—but do not assume any one property is unsupported until the reduced case demonstrates it.

const canvas = await html2canvas(document.querySelector('.card'), {
  onclone: (clonedDocument) => {
    const cloned = clonedDocument.querySelector('.animated-widget');
    cloned?.remove();
  }
});

onclone receives the cloned document, so changes there do not modify the live page. The documented default is null. You can also mark unwanted nodes in the source with data-html2canvas-ignore:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<button data-html2canvas-ignore>Close</button>

Use a minimal reproduction containing one element, one stylesheet, and one resource. If the minimal version succeeds, add components back until one addition reproduces the exception. If it never succeeds, the stack trace and dependency version are more valuable than further random option changes.

6. Check capture coordinates, dimensions, and browser canvas limits

A blank or truncated result can be a geometry problem rather than a TypeError. Compare the requested rectangle with the element’s scroll dimensions:

const element = document.querySelector('#report');
const rect = element.getBoundingClientRect();
console.log({
  client: [element.clientWidth, element.clientHeight],
  scroll: [element.scrollWidth, element.scrollHeight],
  rect: [rect.width, rect.height]
});

For a page whose content extends beyond the viewport, pass dimensions that match the document you intend to capture:

const canvas = await html2canvas(document.querySelector('#report'), {
  windowWidth: document.documentElement.scrollWidth,
  windowHeight: document.documentElement.scrollHeight,
  scale: 1
});

The official FAQ gives rough, evergreen-browser guidance—not guarantees: Chrome/Chromium about 32,767 pixels maximum dimension and about 268 million pixels maximum area; Firefox about 32,767 pixels maximum dimension and about 472 million pixels maximum area; desktop Safari about 32,767 pixels maximum dimension. iOS Safari limits are lower and depend on device RAM. Values vary by browser, platform, GPU, and operating system.

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

If a large capture fails, reduce scale, capture sections separately, or lower the requested width and height. A high-DPI scale multiplies both dimensions and therefore multiplies pixel area. Test the same page on the target browser and device; there is no universal canvas threshold.

7. Use the options as diagnostic controls

Option Documented behavior Useful diagnostic
logging Defaults to true in the options reference. Leave it enabled while reducing the case; its messages show where loading or cloning stops.
imageTimeout Defaults to 15,000 milliseconds. Increase it only when a slow, permitted image is the demonstrated cause; it does not fix CORS.
allowTaint Defaults to false. Do not use it to make a canvas exportable. Correct origin policy instead.
onclone Defaults to null; edits the cloned document. Disable animations or remove one problematic node without changing the live UI.
x, y, width, height Capture a region. Use a small rectangle to determine whether the failure is tied to one area.
scale Controls output resolution. Set 1 while testing oversized captures, then increase deliberately.

These settings are versioned library defaults and examples, not universal TypeError remedies. Record the package version whenever you report a result.

8. Choose the capture method that matches the job

  • DOM reconstruction: use html2canvas when you need a canvas generated in the page and can accept its CSS and resource constraints.
  • Browser extension: use the browser’s native extension screenshot API for a visible-tab capture; the html2canvas FAQ recommends this path.
  • Server-side automation: use Puppeteer or Playwright to drive a real browser under Node.js when you need rendered pixels, authenticated navigation, or scheduled captures.

The deciding questions are whether you need DOM reconstruction or native pixels, whether execution must happen in an extension or on a server, whether browser security permits the resources, and whether incomplete CSS support is acceptable.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP, or PDF, so your code does not need to recreate the page with html2canvas:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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)
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}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));

See the ScreenshotNeo documentation for authentication and options. Before capture, it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

Every plan includes the features. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Other available plans are Growth ($15/15,000), Pro ($39/60,000), Scale ($99/250,000), and Business ($249/1,000,000); yearly billing gives two months free. Create a free ScreenshotNeo account to try the 1,000 monthly shots without a card.

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

Common symptoms and targeted fixes

“Cannot read properties of undefined” in html2canvas internals

Reproduce with one element and note the exact stack frame. Check that the call receives a real, attached element, that it runs after the DOM exists, and that the runtime is a browser. Then test the installed version against a minimal page.

The canvas is empty, but no exception appears

Log dimensions, inspect external images, and compare the element’s scroll size with the requested window size. Remove cross-origin resources and reduce the capture area to distinguish resource policy from canvas limits.

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

Export fails after a successful render

Treat this as a tainted-canvas/readback problem. Verify CORS headers or use a proxy; do not rely on allowTaint to enable export.

Only one component breaks the capture

Use onclone or data-html2canvas-ignore to omit it, then add its children and styles back incrementally. The result may be an unsupported CSS feature rather than a JavaScript TypeError.

The full-page result is cut off

Measure scroll dimensions, set suitable windowWidth and windowHeight, lower scale, or split the page into sections. Browser limits are device-dependent.

Final diagnostic checklist

  1. Save the exact exception, stack, browser, html2canvas version, element, and options.
  2. Confirm the call runs in a browser or in Puppeteer/Playwright—not bare Node.js.
  3. Log canvas dimensions before calling an export API.
  4. Verify CORS responses for every cross-origin image and avoid treating allowTaint as a cure.
  5. Reduce the DOM, remove resources and complex styles, and use onclone or ignore attributes to isolate the trigger.
  6. Match window dimensions to scroll dimensions and account for browser canvas ceilings.
  7. Use a native extension API or real-browser automation when the requirement is an actual rendered screenshot rather than DOM reconstruction.

Frequently Asked Questions

Why does the title alone not identify my html2canvas error?

“Uncaught TypeError” describes a JavaScript exception class, not the failed expression. The message and stack trace are required to distinguish runtime, resource, cloning, geometry, and export failures.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Can html2canvas capture a cross-origin iframe?

Same-origin policy and iframe access rules still apply. If the document is on another origin, html2canvas cannot freely inspect and reconstruct it; use permitted resources or a browser automation/native screenshot approach.

Should I disable logging in production?

The options reference documents logging as enabled by default. Keep it enabled while diagnosing; disable it only after you have confirmed that the capture is stable and you no longer need diagnostic output.

Is a native browser screenshot always better than html2canvas?

Neither is universally better. Native screenshots reproduce rendered pixels, while html2canvas is useful when you need a canvas generated in the page and can accept its DOM, CSS, and security constraints.

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.

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