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.

The standard browser workflow is HTML element → canvas → PNG: select the element, render it with html2canvas, then export the canvas with the browser’s PNG-capable APIs. This is convenient for cards, invoices, charts and previews, but it reconstructs the DOM rather than photographing browser pixels. If you need the exact rendered page, use Playwright or Puppeteer—or an API such as ScreenshotNeo.

Convert an HTML element to PNG in the browser

Install html2canvas with your package manager:

npm install html2canvas

Give the element an identifier and call html2canvas(element). The promise resolves to a canvas, which can be downloaded as a PNG:

import html2canvas from 'html2canvas';

async function downloadPng() {
  const element = document.querySelector('#capture');
  if (!element) throw new Error('Capture element not found');

  const canvas = await html2canvas(element, {
    backgroundColor: null,
    scale: window.devicePixelRatio,
    useCORS: true
  });

  const blob = await new Promise(resolve =>
    canvas.toBlob(resolve, 'image/png')
  );
  if (!blob) throw new Error('PNG export failed');

  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'capture.png';
  link.click();
  URL.revokeObjectURL(url);
}

document.querySelector('#download').addEventListener('click', downloadPng);

Example markup:

<article id="capture">
  <h1>Monthly report</h1>
  <p>Revenue: $12,480</p>
</article>
<button id="download" type="button">Download PNG</button>

backgroundColor: null requests transparency when the captured element has no background. scale controls output density and defaults to the device pixel ratio when omitted. useCORS attempts to load images with CORS, but it cannot override the remote server’s policy.

Wait for fonts, images and dynamic content

Capture only after the element is populated. For images, wait for their load events; for fonts, await document.fonts.ready. Frameworks should capture after the relevant render state exists. Otherwise the canvas may contain fallback fonts or blank image areas.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await document.fonts.ready;
await Promise.all([...document.images].map(img => {
  if (img.complete) return Promise.resolve();
  return new Promise(resolve => {
    img.addEventListener('load', resolve, { once: true });
    img.addEventListener('error', resolve, { once: true });
  });
}));
await downloadPng();

PNG export choices: toBlob() versus toDataURL()

canvas.toBlob() creates a binary Blob and is the better default for downloads and large images because it avoids placing the entire encoded image in a JavaScript string. The object URL should be revoked after the browser has consumed it; if a target browser cancels downloads when cleanup is immediate, defer URL.revokeObjectURL(url) briefly.

canvas.toDataURL('image/png') returns a base64 data URL, useful when an inline URL is specifically required:

const dataUrl = canvas.toDataURL('image/png');
window.open(dataUrl, '_blank');

PNG is the required canvas export format and is used when no type is supplied or an unsupported type is requested. Both methods can throw a SecurityError when the canvas is not origin-clean.

Cross-origin images and the canvas security boundary

An image hosted on another origin can be skipped or taint the canvas. useCORS: true succeeds only when that server returns compatible CORS headers. You cannot make an origin-tainted canvas readable by setting allowTaint; a tainted canvas cannot be exported.

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

Practical fixes

  • Host the asset on the same origin as the page.
  • Configure the asset server to return an appropriate Access-Control-Allow-Origin value, then load the image with CORS enabled.
  • Proxy the asset through a server you control, preserving content type and applying your own access policy.
  • Replace remote images with data URLs or inline SVG when that is appropriate and safe.

Do not use an unrestricted public proxy for private images or credentials. CORS is a browser security rule, not an html2canvas setting that can be bypassed.

What html2canvas can—and cannot—reproduce

html2canvas traverses the DOM and computed styles to construct a canvas. Its documentation states: “The screenshot is based on the DOM and as such may not be 100% accurate to the real representation of the page.” Unsupported or partially supported CSS, pseudo-elements, transforms, filters, complex SVG, web fonts and timing-sensitive effects can differ from what the browser displays.

  • Compare output in every target evergreen browser.
  • Test the actual fonts, SVGs, animations and responsive breakpoints used by your component.
  • Disable animations or capture at a stable state.
  • Use a simple, explicit background when transparency is not required.

Full-page, scrolling and oversized elements

A captured element is limited by the renderer’s viewport and canvas dimensions. If content is cropped, provide dimensions based on the element’s scroll area:

const element = document.querySelector('#capture');
const canvas = await html2canvas(element, {
  windowWidth: Math.max(document.documentElement.clientWidth, element.scrollWidth),
  windowHeight: Math.max(document.documentElement.clientHeight, element.scrollHeight),
  scale: 1
});

Very large canvases may be blank or partial. Maximum dimensions vary by browser, GPU, operating system and device, so do not rely on one universal limit. Reduce scale, split a long document into sections, or capture at a smaller output size. Higher scale increases pixels, memory use and encoding time.

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

When to use a real browser screenshot instead

html2canvas runs in a browser because it depends on window, document and computed styles; it is not a Node.js conversion library. For server-side jobs or pixel-level browser output, use Playwright or Puppeteer to load the page and call the native screenshot API. That route executes the page in a real browser, so browser layout, fonts and CSS are the things being captured.

Requirement Best fit Reason
Download one rendered component in a web app html2canvas No server browser required; direct DOM-to-canvas flow.
Exact browser pixels, full page or extension tab Playwright/Puppeteer or native extension API Captures the actual browser rendering.
Already have a canvas toBlob() Skips DOM reconstruction entirely.
Automated URL screenshots without browser setup ScreenshotNeo Hosted capture, clean-page processing and usage reporting.

There is no universal accuracy or speed winner among libraries. Capture a representative page in your target browsers and measure memory, latency and output quality.

Export an existing canvas directly

If your chart or drawing is already in a <canvas>, do not render its parent element:

const source = document.querySelector('#chart');
const blob = await new Promise(resolve => source.toBlob(resolve, 'image/png'));
if (!blob) throw new Error('Could not encode canvas');
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'chart.png';
a.click();
setTimeout(() => URL.revokeObjectURL(url), 0);

Or skip the browser setup

For a URL screenshot, ScreenshotNeo provides a hosted GET endpoint. It accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and whether it was billed. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients. Every plan includes the features; 1,000 shots per month are free without a card, Starter is $5 for 3,000, and paid plans start at $5.

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

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 API documentation for PNG, JPEG, WebP, PDF, selectors, device presets, custom CSS and JavaScript, waits, blocking rules, headers, cookies, geolocation, signed links, asynchronous jobs, bulk capture and usage endpoints. Create a free ScreenshotNeo account to get 1,000 screenshots each month with no card.

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

Troubleshooting checklist

“Capture element not found”

The selector ran before the component mounted or does not match the markup. Run the function after rendering, verify the ID, and check for shadow-DOM boundaries.

Blank or incomplete output

Wait for images and fonts, remove animation, inspect browser console errors, reduce the capture dimensions and lower scale. Oversized canvases can exceed platform limits.

Images missing

Check the image response’s CORS headers. Same-origin hosting or a controlled proxy is required when the canvas must be exported.

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

Text or CSS differs

Confirm the font actually loaded, test unsupported CSS and pseudo-elements, and remember that DOM reconstruction is not a native screenshot.

“SecurityError” on export

The canvas is origin-tainted, usually by a cross-origin image or SVG. Fix the asset’s CORS policy or remove the asset; do not attempt to bypass the browser security model.

Download does not start

Use toBlob() and an object URL, trigger the link from a user gesture, and delay URL revocation if necessary.

Performance and reliability practices

  • Capture only the required element instead of the whole document.
  • Use the lowest scale that meets your pixel requirements.
  • Reuse a stable component state and avoid capturing during layout changes.
  • Release object URLs and avoid retaining large data URLs.
  • For server jobs, set navigation and resource timeouts, retry transient failures, and record the browser and page URL with each result.
  • Validate output dimensions and file size before storing or publishing the PNG.

Frequently Asked Questions

Can html2canvas convert an entire webpage to PNG?

It can attempt a large element or document, but scrolling content and platform canvas limits may require dimension settings or section-by-section capture.

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

Does html2canvas work in Node.js?

No. It depends on browser globals and computed styles; use Playwright, Puppeteer or a hosted screenshot API for Node.js jobs.

Why is my PNG transparent?

The example requests transparency with backgroundColor: null. Set a CSS background or a concrete html2canvas background color when you need an opaque image.

Is PNG better than JPEG for HTML captures?

PNG preserves text, line art and transparency. Choose another format only when your delivery requirements favor smaller lossy files.

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.