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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use html2canvas with backgroundColor: null for a transparent canvas, or set a solid fallback color with backgroundColor. Neither option captures a missing CSS background-image by itself. Background images must be supported by html2canvas, present in the cloned DOM, and permitted by browser same-origin rules. For cross-origin assets, use useCORS: true when the image host sends the required CORS headers, or route the image through a proxy you control.

What html2canvas actually captures

html2canvas does not photograph the pixels already painted by the browser. It reads the target element’s DOM and computed styles, then reconstructs a canvas representation. The official documentation warns that the result may differ from the live page because it is built from information available in the DOM rather than from a native screenshot: html2canvas documentation.

That distinction explains most background problems. A background declared in CSS can be omitted when the property syntax is not implemented, the image has not loaded, the cloned document differs from the live document, or the image violates origin rules. Every CSS property requires a manual implementation, so full CSS fidelity is not promised; check the project’s supported-features reference for the exact syntax you use: supported features.

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

Minimal capture that preserves transparency

Pass the element containing the background to html2canvas. This example asks for a transparent canvas and requests CORS-enabled image loading:

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

const canvas = await html2canvas(target, {
  backgroundColor: null,
  useCORS: true
});

document.body.appendChild(canvas);

// Save as PNG
const link = document.createElement('a');
link.download = 'capture.png';
link.href = canvas.toDataURL('image/png');
link.click();

Include the library before running the code, for example with your normal package or script setup. backgroundColor: null means the canvas itself has no forced backdrop. It does not repair a missing element background image. If the target has no usable background, the transparent areas remain transparent.

Choose a solid fallback color

Use a CSS color when you need a predictable backdrop behind the reconstructed DOM:

const canvas = await html2canvas(document.querySelector('#capture'), {
  backgroundColor: '#ffffff'
});

This option fills the canvas background. It is useful when your design intentionally has a plain color or when transparency would make the output hard to use. It is not a substitute for background-image; a gradient, photo, or texture still has to be loaded and supported separately.

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

Make CSS background images available

Verify the target and computed styles

Make sure the selector points to the element that actually owns the background. Inspect it in DevTools and check the computed background-image, background-position, background-size, and background-repeat. A pseudo-element may own the visible artwork, while your selector targets only its parent. Also check that the URL resolves from the page that runs html2canvas and that the request succeeds before capture starts.

Use a supported declaration

Start with a minimal reproduction using a straightforward declaration:

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
#capture {
  width: 640px;
  height: 360px;
  background-image: url('/images/hero.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

Then add layers, gradients, blend modes, or generated content one at a time. If the simple case works but the production style does not, compare the syntax with the current features list rather than assuming all browser CSS is implemented.

Wait for the asset before capturing

Capturing immediately after inserting an element can race the image request. Preload important images and wait for them:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function waitForImage(url) {
  const image = new Image();
  image.src = url;
  if (image.decode) {
    await image.decode();
  } else {
    await new Promise((resolve, reject) => {
      image.onload = resolve;
      image.onerror = reject;
    });
  }
}

await waitForImage('/images/hero.jpg');
const canvas = await html2canvas(document.querySelector('#capture'), {
  backgroundColor: null,
  imageTimeout: 15000,
  logging: true
});

The options reference documents imageTimeout and logging. Logging is especially useful while diagnosing whether an image timed out or was skipped.

Cross-origin backgrounds: CORS or a proxy

Same-origin hosting

The least complicated arrangement is serving the page and background image from the same origin (scheme, host, and port). Normal browser origin rules then allow html2canvas to use the resource, subject to ordinary loading failures.

CORS-enabled image hosting

For an image on another origin, try:

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

useCORS requests a CORS-compatible image load; it cannot grant permission that the image server has not provided. The image response must include suitable CORS headers, commonly an Access-Control-Allow-Origin value that permits your page. Inspect the image request and response in DevTools. If the server returns no permission header, the browser can skip the image or leave the canvas unusable for export.

A controlled proxy

When you cannot change the remote image server, configure the documented proxy option to a proxy you control:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const canvas = await html2canvas(document.querySelector('#capture'), {
  proxy: 'https://your.example.com/html2canvas-proxy',
  backgroundColor: null
});

A proxy must fetch only resources you are authorized to retrieve and must implement appropriate access controls, validation, and response handling. Do not expose an unrestricted fetch endpoint: it can become a server-side request forgery or bandwidth-abuse target. The proxy also needs to return an image response in a way the browser can use for the canvas.

Why allowTaint is not an export fix

A tainted canvas cannot be read with toDataURL() or similar export APIs. Setting allowTaint does not create CORS permission and should not be presented as a solution for exporting cross-origin backgrounds. Use permitted same-origin hosting, valid CORS, or a properly secured proxy instead.

Control the cloned document with onclone

html2canvas creates a cloned document for rendering. The onclone hook lets you make temporary, capture-only changes without altering the live page:

const canvas = await html2canvas(document.querySelector('#capture'), {
  onclone: (clonedDocument) => {
    const cloned = clonedDocument.querySelector('#capture');
    cloned.style.backgroundColor = '#111827';
    cloned.style.backgroundImage = "url('/images/hero.jpg')";
  },
  logging: true
});

Use this to remove animations, force a known state, or replace a problematic declaration while diagnosing. It cannot bypass origin restrictions; the cloned page is still subject to browser security.

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.
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

Prevent clipping and blank output

For a target whose content is larger than the viewport, set capture dimensions to the element’s scroll dimensions:

const element = document.querySelector('#capture');
const canvas = await html2canvas(element, {
  windowWidth: element.scrollWidth,
  windowHeight: element.scrollHeight,
  width: element.scrollWidth,
  height: element.scrollHeight,
  backgroundColor: null
});

Very large canvases can exceed browser or platform limits and produce blank or partial output. The html2canvas FAQ gives rough guidance rather than guaranteed specifications: Chrome/Chromium and desktop Safari are approximately 32,767 pixels on a dimension, with Chromium around 268 million pixels of total area; Firefox is approximately 32,767 pixels per dimension and around 472 million pixels of area. iOS Safari is lower and depends on device RAM. Treat these as variable limits, test on the target browser and device, and split long pages into sections when necessary: html2canvas FAQ.

Matching the capture viewport to the element helps with responsive backgrounds. A page rendered at one viewport can choose a different media-query image or crop at another, so set windowWidth and windowHeight deliberately rather than relying on incidental browser dimensions.

A diagnostic workflow

  1. Confirm the selector. Temporarily add an outline and verify that the element passed to html2canvas includes the visible artwork.
  2. Inspect computed CSS. Check whether the final cloned-style equivalent contains a usable background-image URL, not only a shorthand or a pseudo-element rule.
  3. Test same-origin first. Replace the remote image with a local asset. If that works, investigate CORS rather than CSS.
  4. Turn on logging. Review console output for skipped images, timeouts, or parsing issues.
  5. Wait for resources. Preload or decode the image and increase imageTimeout when the network is slow.
  6. Reduce the CSS. Build a small page with one element and one background declaration, then add complexity incrementally.
  7. Check export separately. If the image appears but toDataURL fails, investigate canvas tainting and response headers.
  8. Check dimensions. Reduce oversized captures or split them when the browser returns blank or partial output.

Common symptoms and fixes

Symptom Likely cause Action
Solid color appears, photo does not backgroundColor is working, but the image is unsupported, unavailable, or cross-origin. Inspect the request, test a same-origin file, verify supported CSS, then configure CORS or a proxy.
Image is absent only on production Production URL or response headers differ from development. Compare computed URLs and network response headers in the production origin.
Capture is clipped Viewport or element dimensions are smaller than the content. Use scroll dimensions and explicit windowWidth/windowHeight; avoid canvas limits.
Export throws a security error The canvas was tainted by a cross-origin resource. Use same-origin hosting, valid CORS, or a secured proxy. Do not rely on allowTaint.
Output is blank or partial Canvas dimensions exceed a browser or device limit. Capture smaller regions, lower dimensions, or split the page; test on the actual target browser.
Live page looks right, canvas differs DOM reconstruction does not reproduce a browser-painted effect or unsupported CSS. Check the supported-features list or use a native browser screenshot method when exact pixels matter.

When html2canvas is the wrong tool

Use html2canvas when a DOM-based rendering is acceptable and you can make the required resources available. It is not a native screenshot API. If you need the exact pixels produced by the browser, including effects html2canvas does not implement, use a browser automation or extension screenshot API instead. The project’s FAQ specifically points extension developers toward native screenshot APIs rather than html2canvas.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For a server-side screenshot that handles the browser session for you, ScreenshotNeo returns PNG, JPEG, WebP, or PDF from one GET request. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and the response identifies the result with X-Page-Verdict and X-Billed headers.

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)
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}`);

See the ScreenshotNeo documentation for options such as full-page lazy-image loading, CSS-selector element capture, dark mode, device presets, retina scale, custom CSS and JavaScript, waits, request blocking, cookies, headers, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, bulk capture, usage reporting, and PDF output. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Sign up free.

Performance and reliability considerations

  • Capture only the element you need when a full document is unnecessary.
  • Preload or decode large background images before starting the render.
  • Keep logging enabled during development and disable noisy diagnostics in production once the path is stable.
  • Use explicit dimensions for repeatable responsive output.
  • Cache or reuse generated images where your application permits, while ensuring stale backgrounds are invalidated.
  • Test Chromium, Firefox, desktop Safari, and iOS Safari separately for large captures because canvas limits vary.

Frequently Asked Questions

Does backgroundColor capture a CSS background image?

No. It sets the canvas backdrop. A CSS image still needs supported syntax, successful loading, and permission under browser origin rules.

Can useCORS: true bypass a remote server’s restrictions?

No. It requests a CORS-compatible load, but only the image server’s response headers can grant that permission.

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

Why does the image appear but the exported file fail?

A cross-origin resource may have tainted the canvas. Fix hosting or CORS, or use a secured proxy before calling an export method.

Is html2canvas a pixel-perfect screenshot tool?

No. It reconstructs the DOM and styles. Use a native browser screenshot API when exact rendered pixels are required.

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.