Free tools Windows power users keep installed
One-click scans. No signup required.
html2canvas saves a rendered SVG region as a raster PNG, not as an editable SVG file. Call html2canvas(element), wait for its Promise, convert the returned canvas with toDataURL('image/png'), and download that data URL. If you need vector editability, download the original SVG markup or resource separately; do not rename the PNG to .svg.
Decide which file you actually need
“Save an SVG image” can mean two different jobs. A visual snapshot includes the surrounding DOM, CSS layout, fonts and the SVG as it appears in the browser. An editable asset is the SVG source itself, with paths, text and attributes preserved. html2canvas is designed for the first job: it reconstructs a view from the DOM and properties it understands, then paints that view onto a canvas. The documented download workflow produces PNG data.
| Goal | Correct method | Result |
|---|---|---|
| Download what a page region looks like | Pass the region to html2canvas and download canvas.toDataURL('image/png') |
Raster PNG; convenient for previews and reports |
| Keep paths and text editable | Download the inline SVG markup or fetch the original SVG resource | SVG source; remains vector and editable |
| Capture a page without installing browser code | Use a screenshot service such as ScreenshotNeo | PNG, JPEG, WebP or PDF from an API request |
Save a rendered region as a PNG with html2canvas
Minimal browser example
Load html2canvas in your page, give the target a real selector, and trigger the capture from a user action. The anchor’s download value controls the suggested filename.
<button id='save-png' type='button'>Save PNG</button>
<div id='capture'>
<svg width='320' height='180' viewBox='0 0 320 180' role='img' aria-label='Sample chart'>
<rect width='320' height='180' fill='#102a43' />
<circle cx='90' cy='90' r='48' fill='#2f80ed' />
<text x='160' y='98' fill='white' font-size='22'>SVG chart</text>
</svg>
</div>
<script src='https://cdn.jsdelivr.net/npm/html2canvas@latest/dist/html2canvas.min.js'></script>
<script>
document.querySelector('#save-png').addEventListener('click', async () => {
const element = document.querySelector('#capture');
if (!element) throw new Error('Capture element was not found');
const canvas = await html2canvas(element);
const link = document.createElement('a');
link.download = 'screenshot.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
</script>
The Promise resolves to a canvas. Calling toDataURL('image/png') produces a PNG data URL, so the downloaded file is rasterized even when the source inside the region is SVG.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Useful capture options
Set options only for a reason, because each one affects fidelity, security or rendering time.
useCORS: trueasks the browser to load cross-origin images with CORS. It works only when the asset server sends an appropriateAccess-Control-Allow-Originresponse.proxycan route supported remote resources through a server you control when direct browser access is not permitted.scalecontrols output density. A larger value gives more pixels but consumes more memory.backgroundColorsets a solid background; usenullwhen transparency is required and the rendered content supports it.windowWidthandwindowHeightdefine the virtual viewport used during reconstruction. For a full element, matching them to the element’s scroll dimensions can prevent clipping.width,height,xandylimit the capture to a known rectangle when you do not want the entire element.
const element = document.querySelector('#capture');
const canvas = await html2canvas(element, {
useCORS: true,
scale: window.devicePixelRatio,
backgroundColor: null,
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight
});
const link = document.createElement('a');
link.download = '[email protected]';
link.href = canvas.toDataURL('image/png');
link.click();
Download the original SVG when editability matters
Inline SVG
An inline <svg> element already contains the source in the DOM. Serialize it and create a Blob instead of passing it through html2canvas.
function downloadInlineSvg(selector, filename = 'graphic.svg') {
const svg = document.querySelector(selector);
if (!(svg instanceof SVGElement)) {
throw new Error('An inline SVG element is required');
}
const source = new XMLSerializer().serializeToString(svg);
const blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
downloadInlineSvg('#capture svg');
This preserves the SVG markup, but external stylesheets, web fonts and referenced files may not be self-contained. If another editor must open the file offline, inline the required styles and embed or package referenced assets.
SVG loaded as an external resource
For an <img src='diagram.svg'>, request the URL and save the response as a Blob only when the server permits that cross-origin request. Otherwise, download it from the same origin or configure the server; browser security cannot be bypassed by JavaScript.
async function downloadSvgUrl(url, filename = 'diagram.svg') {
const response = await fetch(url, { mode: 'cors' });
if (!response.ok) throw new Error(`SVG request failed: ${response.status}`);
const blob = await response.blob();
if (blob.type && !blob.type.includes('svg')) {
throw new Error(`Expected SVG data, received ${blob.type}`);
}
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = objectUrl;
link.download = filename;
link.click();
URL.revokeObjectURL(objectUrl);
}
downloadSvgUrl('/assets/diagram.svg');
Do not present a canvas PNG as an SVG by changing its extension. It will still contain pixels and will fail wherever vector editing or infinite scaling is expected.
Why the captured SVG can differ from the browser
html2canvas is not a literal screenshot of browser pixels. It reads the DOM and supported CSS properties, then reconstructs the appearance. Unsupported SVG features, filters, masks, blend modes, unusual text rendering, missing fonts and dynamically changed attributes can therefore produce differences. One reported issue describes an SVG line missing from a saved image; treat such reports as asset- and browser-specific, not as proof that every SVG line will disappear.
Capture after the page has finished changing the SVG. If JavaScript adds paths, loads data or swaps classes, wait for that work before calling html2canvas. Test the exact SVG markup and target browsers; current getting-started documentation lists evergreen Chrome/Chromium, Firefox and Safari support, but your deployed versions and fonts are the deciding factor.
Handle cross-origin images and tainted canvases
A remote SVG, raster image or resource referenced by an SVG can taint the canvas. A tainted canvas cannot be read back with toDataURL() or similar APIs. useCORS: true helps only if the remote server explicitly permits your origin. It does not grant permission by itself.
Rank #3
Check these conditions
- Open the asset URL in the network panel and verify the response includes a suitable
Access-Control-Allow-Originvalue. - Use the exact final URL after redirects. A same-origin URL that redirects to a CDN can become cross-origin; a January 17, 2023 repository issue reports this as an edge case where
useCORSdid not solve the redirect. - Use a documented proxy option when you control a server that can fetch and relay the asset with correct headers.
- Do not rely on
allowTaint: trueto make exportable pixels. It permits drawing in some cases but does not make a tainted canvas readable.
Prevent blank, clipped or oversized output
Blank or partially captured image
Confirm that the selector resolves, the element is visible, and the SVG has dimensions. For a long page region, compare the element’s scrollWidth and scrollHeight with the windowWidth and windowHeight options. Lazy content must be loaded before capture; html2canvas cannot paint an image that has not arrived.
Canvas-size limits
Browsers impose maximum canvas dimensions and total pixel budgets. A large full-page element combined with a high scale can exceed those limits, yielding a clipped or empty canvas. Reduce the scale, capture sections separately, or lower the virtual window dimensions, then test in every target browser.
Fonts and layout shifts
Wait for web fonts and data-driven layout to settle. Capture after document.fonts.ready when your application uses web fonts, and avoid changing the DOM while html2canvas is traversing it. A stable layout makes repeated downloads more predictable.
Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
SecurityError from toDataURL() |
Cross-origin resource tainted the canvas | Enable server CORS, use useCORS, serve the asset from your origin, or configure a proxy. |
| SVG is missing a line, filter or text effect | Renderer does not implement that property or the asset differs by browser | Test the actual markup, simplify or inline the effect, and compare supported browsers. |
| Image is blank | Selector, dimensions, load timing or canvas limit | Log the element, wait for assets, set matching window dimensions and reduce scale. |
| Capture is cut off | Viewport dimensions are smaller than the element’s scroll area | Set windowWidth/windowHeight from scrollWidth/scrollHeight, or capture in sections. |
| Downloaded file opens but is not editable | It is a PNG raster capture | Download the original SVG source using serialization or a permitted fetch. |
Performance, reliability and security notes
- Capturing a large DOM subtree costs CPU and memory because styles and nodes are reconstructed. Capture the smallest useful element.
- Higher pixel density improves sharpness but multiplies memory use. Choose a scale that matches the display or document where the PNG will be used.
- Run the capture in response to a user action when possible, and handle Promise rejection so a failed export does not appear successful.
- Never put private credentials in page JavaScript merely to fetch a protected SVG. Use a server endpoint that authenticates and streams an authorized file.
- Keep the original SVG available when users may need accessibility, text selection or later editing; a PNG cannot restore that structure.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It captures a URL as PNG, JPEG, WebP or PDF, rather than requiring html2canvas and a browser page. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients.
Use the API documentation at https://screenshotneo.com/docs/ for authentication and options. A one-request capture 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 fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page options, custom CSS and JavaScript, click and wait conditions, request blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
| Plan | Included shots | Price |
|---|---|---|
| Free | 1,000 per month | $0, no card |
| Starter | 3,000 | $5 |
| Growth | 15,000 | $15 |
| Pro | 60,000 | $39 |
| Scale | 250,000 | $99 |
| Business | 1,000,000 | $249 |
Every feature is available on every plan, and yearly billing gives two months free. Start with 1,000 free screenshots a month with no card; paid plans start at $5 for 3,000 shots.
Frequently Asked Questions
Can a PNG exported by html2canvas be converted back into editable SVG?
No. The PNG contains pixels only. You need the original SVG markup or resource to retain paths, text and vector editability.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWhy does the downloaded image look different from a browser screenshot?
html2canvas reconstructs the DOM and supported properties rather than reading browser pixels directly, so unsupported SVG or CSS features can render differently.
What is the safest way to save a protected SVG?
Fetch it through an authenticated server endpoint and stream the response, rather than exposing private credentials in client-side JavaScript.
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.




