Choose the capture method by what you need to capture: use canvas.toBlob() to export pixels from a canvas your app owns, html2canvas to reconstruct a DOM element, or navigator.mediaDevices.getDisplayMedia() to let a user select a screen, window, or browser tab. These approaches have different fidelity, cross-origin, and permission constraints; ordinary page JavaScript cannot silently screenshot an arbitrary page or display.
Which browser screenshot method should you use?
“Screenshot” can mean three distinct jobs in a web app. A canvas export serializes a bitmap your application has already drawn. A DOM capture library recreates part of the page from DOM and style information. Display capture asks the user to choose a source and grant access. Decide which job you need before choosing an API.
| Method | What it captures | Fidelity and limits | User involvement |
|---|---|---|---|
HTMLCanvasElement.toBlob() or toDataURL() |
The bitmap in a canvas your app owns | Exports the canvas bitmap; a tainted canvas cannot be read or exported | No display-capture prompt |
html2canvas |
A DOM element or page region reconstructed from DOM information | Not a native screenshot; unsupported CSS and cross-origin restrictions can cause differences or omissions | Runs in the page |
getDisplayMedia() |
A screen, window, or tab selected by the user | Captures a user-approved display source rather than an arbitrary page region | Requires user interaction, source selection, and permission for each capture |
The key distinction is that only the first method exports an already-rendered canvas bitmap. html2canvas reconstructs content, while display capture is a permission-mediated browser feature.
Export a canvas your application owns
When your application already drew a chart, editor, game frame, or other image to a <canvas>, the Canvas API is the direct route. Prefer toBlob() for a Blob you can preview, upload, or download. Use toDataURL() when a data URL is specifically useful and the image is modest in size: it encodes the whole image into an in-memory string.
#1 Best Overall
Export as a Blob
function canvasToBlob(canvas, type = "image/png", quality) {
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) resolve(blob);
else reject(new Error("Canvas export did not produce a Blob"));
}, type, quality);
});
}
const canvas = document.querySelector("canvas");
if (!canvas) throw new Error("Canvas not found");
const blob = await canvasToBlob(canvas);
const imageUrl = URL.createObjectURL(blob);
// For a preview:
const preview = document.querySelector("#preview");
preview.src = imageUrl;
// For a download:
const link = document.createElement("a");
link.href = imageUrl;
link.download = "canvas.png";
link.click();
// Revoke the URL when the preview or download is no longer needed.
URL.revokeObjectURL(imageUrl);
toBlob() uses a callback, so the helper wraps it in a Promise for use with await. For a long-lived preview, do not revoke the object URL immediately after assigning it; revoke it when the preview is replaced or removed.
Choose an image format
PNG is the default and required supported format. JPEG and WebP may also be supported. If the browser does not support the requested format, it falls back to PNG. The optional quality value applies to lossy formats such as JPEG or WebP; it is ignored for PNG.
toDataURL() is useful when an API or markup specifically needs a data URL:
Rank #2
const canvas = document.querySelector("canvas");
if (!canvas) throw new Error("Canvas not found");
const dataUrl = canvas.toDataURL("image/png");
For large images, avoid turning the entire bitmap into a base64-encoded string if a Blob will do. A canvas with zero dimensions, or dimensions beyond the browser’s maximum canvas size, returns the sentinel string data:, from toDataURL(). See MDN’s HTMLCanvasElement: toDataURL() method documentation for format and exception details.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Capture a DOM element with html2canvas
If the target is a DOM element rather than an app-owned canvas, html2canvas builds a representation by traversing DOM information. It does not take a native screenshot of the browser’s rendered pixels. The output can differ from what the user sees, particularly where the page uses CSS or browser features the library does not support.
Install and capture an element
Install the package in a JavaScript project:
npm install html2canvas
Then pass the element you want to capture. This module example is suitable for a bundler or other environment that supports ES modules:
Rank #3
import html2canvas from "html2canvas";
const element = document.querySelector("#receipt");
if (!element) throw new Error("Capture target #receipt not found");
const canvas = await html2canvas(element);
const blob = await new Promise((resolve, reject) => {
canvas.toBlob((result) => {
if (result) resolve(result);
else reject(new Error("Capture did not produce an image"));
}, "image/png");
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "receipt.png";
link.click();
For the full document, the project’s getting-started example is const canvas = await html2canvas(document.body);. Capturing a smaller element is usually a better fit when the page contains unrelated content. Check the project’s Getting Started guide for setup and its stated browser support: modern evergreen browsers, including Chrome/Chromium-based browsers, Firefox, and Safari. That is the project’s compatibility statement, not a promise that every CSS feature works in every version.
Understand reconstruction limits
- It is not pixel-for-pixel browser capture. html2canvas supports properties it understands and may render a page differently from the browser.
- Cross-origin iframes are inaccessible. Browser security restrictions prevent the library from reading their contents.
- Foreign images and resources are subject to CORS. A resource that cannot be used under the page’s origin rules may be absent from the result.
- Existing tainted canvases remain restricted. A DOM reconstruction library cannot bypass the browser’s content security model.
The project documents these limitations in its documentation. If exact rendered pixels, cross-origin content, or a full-page capture are essential, validate the result for your page rather than assuming reconstruction equals a screenshot.
Let the user select a screen, window, or tab
Use navigator.mediaDevices.getDisplayMedia() when the user should choose a display source. The browser presents a source picker and permission flow; it is not a way for ordinary page JavaScript to silently capture a display.
Start a user-mediated capture
Call it in response to a user action, such as a button click. The stream below is attached to a video element so the user can preview the selected source:
const button = document.querySelector("#start-capture");
const video = document.querySelector("#capture-preview");
button.addEventListener("click", async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false
});
video.srcObject = stream;
await video.play();
// Stop the capture when the user ends it in the browser UI,
// or when your app no longer needs the stream.
for (const track of stream.getTracks()) {
track.addEventListener("ended", () => {
video.srcObject = null;
});
}
} catch (error) {
console.error("Display capture was not started:", error);
}
});
Example markup:
<button id="start-capture">Choose what to share</button>
<video id="capture-preview" autoplay playsinline></video>
The user must interact to initiate capture, choose a source, and grant permission again for each capture; permission cannot be persisted for reuse. Constraints cannot be used to silently pre-limit the user’s source choices. Consult MDN’s getDisplayMedia() documentation for API behavior and current browser requirements.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Cross-origin images: why canvas export fails
When a foreign image is drawn into a canvas without suitable CORS approval, the browser marks the canvas as tainted. Attempts to inspect its pixels or export it—including getImageData(), toBlob(), toDataURL(), and captureStream()—are blocked with a security error.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC 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 & 11Best Value
Setting an image element’s crossorigin attribute is not sufficient on its own. The image server must also return an appropriate CORS response. Client-side JavaScript cannot grant itself access to another origin’s image pixels. For the practical rules, see MDN’s guide to using cross-origin images in a canvas.
Common failures and how to fix them
| Symptom | Likely cause | What to do |
|---|---|---|
SecurityError when exporting |
The canvas includes a cross-origin image without valid CORS approval | Serve the image with suitable CORS headers and load it with the appropriate crossorigin setting, or avoid drawing that resource into an exportable canvas. |
toDataURL() returns data:, |
The canvas has zero dimensions or exceeds the browser’s maximum canvas size | Check the canvas width and height; use a smaller output or split the content into smaller captures. |
| html2canvas omits an image or iframe | Cross-origin policy blocks access to the resource or iframe | Use resources served with appropriate CORS permission where possible; cross-origin iframe contents cannot be read by the library. |
| html2canvas looks different from the page | The library reconstructs supported DOM features rather than photographing rendered pixels | Check the project’s supported properties and simplify or adapt the target markup; choose another capture route if exact rendered output is necessary. |
| The display picker does not appear or capture fails | The call was not initiated through the expected user interaction, or the user declined or canceled permission | Call from a user action and handle cancellation as a normal outcome; explain that the user must choose a source. |
| A generated preview disappears or leaks memory | An object URL was revoked too early, or not revoked after use | Keep it alive while needed, then call URL.revokeObjectURL() when replacing or removing the preview. |
Or skip the browser setup
If you need a screenshot of a public website rather than content in your app’s own browser session, ScreenshotNeo offers a one-request screenshot API and an MCP server for AI agents. Example cURL request, using the documented endpoint and parameter style:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for the request options and output formats. It removes cookie and consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use screenshot tools. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. This is a website capture service, not a way to capture a user’s private display or bypass browser permissions. Sign up for 1,000 free screenshots a month with no card.
FAQ
Can I use html2canvas in a browser extension?
It depends on the extension’s execution context and its access to the page. html2canvas cannot bypass cross-origin iframe or resource restrictions, so extension permissions do not make every page element readable.
Free tools Windows power users keep installed
One-click scans. No signup required.
Can I copy an html2canvas result to the clipboard?
The rendered result is a canvas, so clipboard handling is a separate step from capture. Browser clipboard permissions and support determine whether a web app can write an image; html2canvas itself does not grant clipboard access.
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.

