How to Create a Transparent Canvas With html2canvas
Set html2canvas’s background to transparent, preserve alpha in PNG exports, and fix white backgrounds, CORS errors, and blank output.

To create a transparent canvas with html2canvas, pass backgroundColor: null when you capture the element, then export the result as a format that supports alpha, usually PNG:
const canvas = await html2canvas(element, {
backgroundColor: null
});
const pngDataUrl = canvas.toDataURL('image/png');
The null value makes the canvas background transparent when html2canvas needs to supply a background. It does not remove opaque backgrounds declared by the captured element or any of its descendants. If a white panel, section, or child element still appears, change that element’s CSS or modify the cloned document in onclone.
This guide explains the complete implementation, alpha-preserving export, CSS edge cases, cross-origin images, canvas size limits, and production considerations.
1. Install and capture an element
Install html2canvas from npm:

npm install html2canvas
Then import it and capture a DOM element. This example assumes an element with the ID badge already exists in the page.
import html2canvas from 'html2canvas';
const element = document.querySelector('#badge');
if (!element) {
throw new Error('The #badge element was not found');
}
const canvas = await html2canvas(element, {
backgroundColor: null
});
document.body.appendChild(canvas);
Appending the canvas temporarily is useful while developing because you can see whether transparent regions are actually transparent. A white-looking result in an image viewer is not proof that the canvas has an opaque background; place it over a dark or checkerboard surface to inspect it.
Complete browser example
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Transparent html2canvas example</title>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@latest/dist/html2canvas.min.js"></script>
<style>
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #263238;
}
#badge {
padding: 32px;
border-radius: 20px;
color: #102027;
background: transparent;
font: 700 32px/1.2 system-ui, sans-serif;
}
.checker {
padding: 24px;
background: repeating-conic-gradient(#fff 0 25%, #d7dee2 0 50%) 50% / 24px 24px;
}
</style>
</head>
<body>
<div class="checker">
<div id="badge">Transparent badge</div>
</div>
<script>
async function run() {
const element = document.querySelector('#badge');
const canvas = await html2canvas(element, { backgroundColor: null });
const link = document.createElement('a');
link.download = 'badge.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
run().catch(console.error);
</script>
</body>
</html>
The checkerboard belongs to the preview page, not the captured element. Because #badge has no opaque background, the corresponding pixels in the PNG retain alpha.
2. Why backgroundColor: null works
html2canvas creates a canvas and paints a representation of the DOM into it. Its backgroundColor option controls the fallback background supplied by the renderer. The documented default is white, and the configuration documentation specifies null for a transparent background. See the html2canvas configuration documentation.
| Setting | Effect | Use when |
|---|---|---|
backgroundColor: null |
Leaves the renderer’s fallback background transparent | You need transparent pixels around the rendered content |
backgroundColor: '#ffffff' |
Paints an opaque white fallback | You explicitly need a white image |
backgroundColor: 'rgba(0,0,0,0)' |
Requests a fully transparent color | You prefer an explicit CSS color value; null is the documented route |
The option cannot make an opaque descendant transparent. For example, this remains white:
<div id="card">
<section style="background: white">Opaque section</section>
</div>
Set the relevant CSS to background: transparent, or use onclone to change styles only in html2canvas’s cloned document.
3. Removing opaque backgrounds safely
Change the source CSS
If the element is always intended to be transparent, the simplest approach is CSS:
.export-surface,
.export-surface * {
background-color: transparent;
}
Use this carefully. Applying it to every descendant can remove intentional colored regions, gradients, or images. Prefer selectors for the specific containers that should disappear.
Use onclone for export-only changes
The onclone callback receives the cloned document before rendering. It lets you remove backgrounds for the export without changing the live page:
const canvas = await html2canvas(document.querySelector('#card'), {
backgroundColor: null,
onclone: (clonedDocument) => {
const card = clonedDocument.querySelector('#card');
card.style.backgroundColor = 'transparent';
card.querySelector('.export-shadow')?.remove();
}
});
Keep the callback deterministic. Do not depend on a user interaction that may not exist in the cloned document, and check that selectors can be absent without throwing.
4. Export PNG while retaining alpha
Use PNG for an exported image with transparency. The project examples use canvas.toDataURL('image/png'):
const pngDataUrl = canvas.toDataURL('image/png');
const download = document.createElement('a');
download.href = pngDataUrl;
download.download = 'transparent.png';
download.click();
You can also convert the canvas to a binary Blob, which is preferable for uploads because it avoids keeping a long base64 string in memory:
const blob = await new Promise((resolve, reject) => {
canvas.toBlob((value) => {
if (value) resolve(value);
else reject(new Error('PNG encoding failed'));
}, 'image/png');
});
const form = new FormData();
form.append('file', blob, 'transparent.png');
await fetch('/upload', { method: 'POST', body: form });
JPEG does not preserve an alpha channel. WebP can support alpha, but confirm that the receiving application and its encoding settings preserve it. PNG is the safest default for logos, icons, cutouts, and composited assets.
5. Relevant html2canvas options
| Option | What it controls | Transparent-canvas guidance |
|---|---|---|
backgroundColor |
Renderer fallback background | Set to null |
onclone |
Changes to the cloned document before rendering | Remove export-only backgrounds or overlays |
useCORS |
Attempts CORS-enabled image loading | Use when remote servers send a suitable CORS header |
allowTaint |
Allows drawing images that may taint the canvas | It does not make a tainted canvas readable for export |
proxy |
Same-origin proxy for resources | Use when you cannot configure the image server’s CORS policy |
scale |
Output pixel density | Increase for sharper output, while watching memory and size |
windowWidth, windowHeight |
Viewport dimensions used during rendering | Match the element’s scroll dimensions when output is blank or clipped |
logging |
Diagnostic logging | Enable while investigating resource or rendering issues |
ignoreElements |
Skips selected DOM nodes | Exclude controls or opaque overlays from the export |
Option names and behavior can change between releases. Pin the html2canvas version in production and check the versioned documentation when browser compatibility matters.
6. Cross-origin images and tainted canvases
Browser content policy can prevent html2canvas from drawing remote images. The html2canvas FAQ recommends useCORS: true when the remote server provides an appropriate Access-Control-Allow-Origin header, or loading the image through a same-origin proxy. Read the official FAQ for the project’s explanation.
const canvas = await html2canvas(element, {
backgroundColor: null,
useCORS: true
});
The server must opt in to the browser request; setting useCORS in your code cannot add a missing response header. allowTaint is false by default. Enabling it may allow drawing, but a tainted canvas cannot safely be read with toDataURL or toBlob. If export fails, fix the resource policy or use a same-origin proxy instead.
7. Blank, clipped, or unexpectedly large output
Browsers impose maximum canvas dimensions. Very tall pages, large scale factors, and high device pixel ratios can exceed those limits and produce blank or truncated output. The html2canvas FAQ suggests setting windowWidth and windowHeight to the captured element’s scroll dimensions where appropriate:
const width = element.scrollWidth;
const height = element.scrollHeight;
const canvas = await html2canvas(element, {
backgroundColor: null,
windowWidth: width,
windowHeight: height
});
For a large capture, reduce scale, capture smaller sections, or export several images and compose them elsewhere. A transparent background does not reduce the memory required for the rendered pixels.
8. Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| Entire image is white | Default fallback background is being used | Set backgroundColor: null and export PNG |
| Some areas remain white | A captured element or child has an opaque CSS background | Change that CSS or remove it in onclone |
| Remote image is missing | CORS policy blocks the image | Use useCORS: true with server CORS headers, or a same-origin proxy |
toDataURL or toBlob throws a security error |
The canvas is tainted | Stop drawing disallowed cross-origin resources; configure CORS or proxy them |
| Output is blank or clipped | Canvas dimension limit or viewport mismatch | Set matching windowWidth/windowHeight, lower scale, or split the capture |
| Shadow or overlay appears in export | The live UI includes decorative or interactive layers | Use ignoreElements or remove the layer in onclone |
| Transparency looks white | Viewer renders transparent pixels on white | Preview over a checkerboard or contrasting background |
9. Performance and reliability practices
- Capture only the element you need. Smaller DOM trees render faster and use less memory.
- Wait until fonts, images, and layout changes have settled before calling html2canvas.
- Use the smallest practical
scale. A scale of two produces four times as many pixels as a scale of one. - Keep export-only style changes in
oncloneso users do not see the page flash or change. - Handle rejected promises and check for a null element before starting a capture.
- For very large pages, split work into sections and add monitoring around memory errors.
- Pin the library version and verify output in the browsers your application supports.
html2canvas recreates the page from DOM and CSS; it is not a browser screenshot of pixels already painted by the browser. Unsupported CSS, fonts, filters, and embedded resources can therefore produce differences between the live page and the canvas.
10. Or skip the browser setup
If you need a server-side website screenshot with a transparent background, ScreenshotNeo provides a single API request. Its capture pipeline accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot. You can also control capture options such as viewport, device preset, retina scale, custom CSS and JavaScript, waits, hidden selectors, headers, cookies, user agent, timezone, geolocation, resource blocking, caching, and image resizing. Transparent output is available through the API’s background controls.

See the ScreenshotNeo API documentation for the complete option list. A minimal request looks like this:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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(`Screenshot failed: ${res.status}`);
const buffer = await res.arrayBuffer();
await Bun.write('shot.webp', buffer);
Failed loads, bot checks or CAPTCHAs, blank pages, timeouts, and cache hits are not billed as clean shots. Each response identifies the result with X-Page-Verdict and X-Billed headers. ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.
11. FAQ
Does backgroundColor: null remove a white CSS background?
No. It controls html2canvas’s fallback canvas background. Remove the CSS background on the affected element or change it in onclone.
Which output format should I use?
Use PNG when alpha must survive export. JPEG has no alpha channel.
Can I make a cross-origin image transparent with JavaScript?
JavaScript cannot override another server’s CORS policy. Configure the image server, use a same-origin proxy, or omit the image.
Why does the downloaded PNG look white?
Inspect it over a checkerboard or colored background. Many image viewers display transparent pixels as white.
Can html2canvas capture a full webpage?
It can capture a large element, but browser canvas limits and resource loading still apply. Match the window dimensions, reduce scale, or split very large captures.


