If html2canvas omits an SVG, first check whether the image finished loading and whether its URL—or a resource inside the SVG—is cross-origin. Wait for the asset, then either serve it with the right CORS header and use useCORS: true, route it through a same-origin proxy, or encode a self-contained inline SVG as a data URI. useCORS cannot grant permission the image server has not given. If the whole capture is blank or cut off, also check capture dimensions and canvas limits.
Identify what is failing
html2canvas reconstructs a page from DOM and CSS; it is not a browser screenshot and cannot override browser content-security rules. SVG can disappear because its image has not loaded, because the browser will not let the canvas use a cross-origin resource, because the SVG refers to other unavailable assets, or because the capture itself is too large. These causes need different fixes, so start by narrowing down the symptom rather than changing several options at once.
- Open DevTools before taking the capture. Check the Console for image, SVG, CORS, or decoding errors.
- In Network, locate the SVG request. Check its status, response headers, and final URL. A request that starts at your origin but redirects to a CDN is cross-origin after the redirect.
- Confirm the page’s
<img>or CSS background has loaded before invoking html2canvas. - Test a small element containing only the SVG. If that works, the problem may be another resource or the dimensions of the full target.
The html2canvas FAQ states that the library “cannot circumvent content policy restrictions set by your browser.” Its cross-origin remedies are CORS enabled by the image server or fetching through a proxy on the same origin. A console-free capture is not proof that every asset was included; use the output and the Network panel to confirm.
Wait for the SVG before capturing
Calling html2canvas immediately after inserting an image can race its download or decode. For an image element, wait for decode() when available; alternatively, listen for load and error. Do this for the actual element in the target subtree before starting the capture.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
async function waitForImage(img) {
if (img.complete && img.naturalWidth > 0) {
if (img.decode) await img.decode();
return;
}
await new Promise((resolve, reject) => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', () => reject(new Error(`Image failed: ${img.src}`)), { once: true });
});
if (img.decode) await img.decode();
}
const target = document.querySelector('#capture');
const svgImage = target.querySelector('img[src$=".svg"]');
if (svgImage) await waitForImage(svgImage);
const canvas = await html2canvas(target, {
onError: error => console.warn('html2canvas resource failed:', error.message)
});
Adapt the selector to your markup; SVG may have a query string or be served without a .svg suffix, so a selector based on the actual element is often safer. The configuration’s onError callback is intended to report a resource (including an image, SVG, or background image) that fails to load or render. It helps expose the failure; it does not repair it.
For a slow asset, html2canvas also has an imageTimeout option. Raise it only when the request is genuinely slow and eventually succeeds. A longer timeout will not fix a 404, a missing CORS header, or a broken SVG reference; it can simply make the capture wait longer.
Fix a cross-origin SVG with CORS or a proxy
An SVG from another origin can be used in a canvas only when the browser’s cross-origin rules permit it. For the direct-host approach, the server serving the SVG must return an appropriate Access-Control-Allow-Origin response header. Then ask html2canvas to use its CORS loading strategy:
const target = document.querySelector('#capture');
const canvas = await html2canvas(target, {
useCORS: true,
onError: error => console.warn('html2canvas resource failed:', error.message)
});
useCORS is a request strategy, not a way to add permission. If the response lacks the required header, the browser still blocks canvas use. A failed cross-origin asset may be skipped when allowTaint is false, which is the default. Setting options without addressing the response policy is not a reliable fix.
Recommended Free Tools
When you control the image host
Configure the SVG response to include an appropriate Access-Control-Allow-Origin header for the page that captures it, and verify the header on the final response in DevTools. Check redirects too: the header on the initial response is not enough if the browser ultimately receives the file from a different host.
When you cannot change the image host
Use a server-side same-origin proxy that fetches the SVG and returns it through your own origin. html2canvas’s proxy option can point at that endpoint:
const svgUrl = 'https://assets.example.com/icon.svg';
const target = document.querySelector('#capture');
const canvas = await html2canvas(target, {
proxy: '/image-proxy?url=' + encodeURIComponent(svgUrl)
});
This example assumes you have implemented /image-proxy; html2canvas does not create the endpoint for you. The proxy must fetch the asset safely and return it in a form the capture can use. The project getting-started guide describes a proxy approach that returns a base64 data URI. Treat proxy input as untrusted: restrict allowed hosts and validate requests so it cannot become an open proxy to internal services.
Check same-origin redirects
A URL that looks local can redirect to a CDN. Issue #3020 records a case in which html2canvas treated the initial URL as same-origin and did not apply useCORS as expected after a redirect. Inspect the final request in Network and make the policy explicit by using a direct CORS-enabled asset URL, a same-origin proxy, or another URL that does not hide the cross-origin hop.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #3
const response = await fetch(svgUrl, { redirect: 'manual' });
console.log(response.type, response.status, response.headers.get('location'));
Browser behavior around manual redirects and cross-origin fetches can limit what this diagnostic reveals. Use the Network panel as the main source of truth for the redirect chain and final response.
Make inline SVG data URIs safe to parse
If the SVG is generated in code or embedded directly, percent-encode its markup before placing it in a data URI. Raw characters such as spaces, #, quotes, and angle brackets can be interpreted as part of the URI rather than as SVG content.
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="tomato"/>
</svg>`;
const img = document.querySelector('#icon');
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
await img.decode();
const canvas = await html2canvas(document.querySelector('#capture'));
The xmlns declaration makes the markup an SVG document, and encodeURIComponent protects its content in the URI. Encoding prevents the separate SVG network request, but it does not automatically make resources referenced by the SVG available. External raster images, fonts, stylesheets, <use> targets, filters, and similar dependencies still need to load in a way the browser permits for canvas use. For Safari-specific data-URI history, project pull request #2683 discusses escaped SVG data URIs in the context of Safari 10.3–11.2; do not treat that historical discussion as a guarantee for every browser or nested asset.
Choose the remedy that fits the asset
| Approach | Use it when | Trade-off |
|---|---|---|
CORS header plus useCORS: true |
You control the SVG host or its operator can configure the response. | Keeps the original asset URL, but the server must grant the required browser permission. |
| Same-origin proxy | You cannot configure the remote host and can operate a backend endpoint. | Routes the fetch through your origin; you must implement and secure the proxy. |
| Encoded inline data URI | The SVG markup is available to your code and can be embedded. | Avoids a separate request for the SVG itself; nested resources still need handling, and changing markup means updating the embedded data. |
foreignObjectRendering: true |
A targeted test for complex content that the browser supports rendering through this path. | It is optional and false by default; it does not bypass CORS or browser security rules. |
The ordinary renderer is the default. Try foreignObjectRendering only after checking the asset and origin; it is an experiment for a different rendering path, not a universal SVG switch:
const canvas = await html2canvas(document.querySelector('#capture'), {
foreignObjectRendering: true
});
html2canvas implements CSS properties selectively, so an SVG that works in the normal browser view can still render differently in the reconstructed capture. If the issue is a CSS feature rather than a load or origin failure, isolate it in a small reproduction rather than assuming another renderer option will support it.
Fix blank or truncated output separately
If the SVG alone is missing, prioritize loading and cross-origin checks. If the whole output is blank, clipped, or only partly rendered, check whether the capture exceeds browser canvas dimensions. html2canvas’s FAQ gives a rough current evergreen-browser guide of about 32,767 pixels per dimension for Chrome/Chromium, Firefox, and desktop Safari. This is not a guaranteed limit: actual limits vary with browser, GPU, operating system, device memory, and can be lower on iOS.
const el = document.querySelector('#capture');
const canvas = await html2canvas(el, {
windowWidth: el.scrollWidth,
windowHeight: el.scrollHeight
});
Using the target’s scroll dimensions can make the virtual window large enough for full-page content; it cannot exceed the browser or device’s canvas capacity. For an oversized capture, split the page into smaller sections or capture only the required element. If the capture succeeds at smaller dimensions, that points to a size limit rather than an SVG-specific failure.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot by symptom
- The SVG is absent, but the rest of the page renders: verify its request completed, inspect the final URL and CORS header, and test with the CORS or proxy path above.
- The SVG appears in the page but disappears in the capture: page rendering alone does not prove canvas permission. Check the console and response headers; also check whether the SVG references remote fonts, images, styles, or symbols.
useCORS: truechanges nothing: confirm the final asset response grants CORS. Check for a same-origin-to-CDN redirect and remember that this option cannot modify server headers.- A data URI works in one browser but not another: verify that the markup is percent-encoded, the image has decoded before capture, and every referenced resource is available. Reproduce with a minimal SVG and note the browser version.
onErrorreports a failed resource: use the error alongside Network details to identify the specific URL and response; then fix its load, origin policy, or reference.- The image loads eventually but is missed intermittently: wait for its load/decode before capturing. Increase
imageTimeoutonly if the asset is slow but valid. - The whole image is blank or cut short: compare target dimensions with rough browser canvas limits and try a smaller region or separate captures.
- The SVG remains wrong after those checks: reduce it to a minimal reproducible case with the SVG, browser and html2canvas versions, and network response headers. The project notes that browser-side rendering is not universal and CSS support is partial.
Performance and reliability considerations
There is no single option that makes every capture reliable. Waiting for image decode avoids racing a known asset but may delay the capture; proxying introduces a server request and maintenance; embedding markup removes one network fetch but can make updates less convenient. Choose the smallest intervention that fits how the SVG is hosted.
- Wait for the target’s actual image elements rather than adding an arbitrary delay to every capture.
- Use direct CORS when the asset host can provide the header; reserve a proxy for assets you cannot configure.
- Keep an inline data URI self-contained where possible, or explicitly test its dependencies.
- Measure target dimensions before attempting very tall full-page output, especially on mobile or memory-constrained devices.
- Use
onErrorand browser Network diagnostics during development so an omitted resource is visible instead of silently mistaken for a successful render.
These steps improve diagnosis; they do not turn html2canvas into a standards-complete browser renderer. The project FAQ names Puppeteer and Playwright as alternatives for server-side screenshots. Check their current versions and commercial terms separately if the actual requirement is a browser-produced screenshot rather than a client-side canvas reconstruction.
Or skip the browser setup
If you need a website screenshot rather than a client-side html2canvas canvas, ScreenshotNeo is a screenshot API and MCP server. One GET request returns an image or PDF. It accepts consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; these steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses report the page verdict and billing status in headers. Its MCP server offers screenshot tools for AI agents.
Here is the one-call cURL pattern, targeting an example page; replace the URL and API key with your own. 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
The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. If that fits your use case, sign up for the free plan.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.

