For an in-page download, select the element and pass it to html2canvas. It returns a canvas that you can display or export as a PNG. This is a DOM-and-style reconstruction rather than a capture of the browser’s actual pixels, so CSS support and cross-origin content affect the result. For automated, browser-rendered captures, use Playwright’s element screenshot API instead.
Choose the right capture method
Your choice depends on where the code runs and what “screenshot” means for your feature.
| Requirement | Recommended approach | What it produces | Main limitation |
|---|---|---|---|
| A button in your web page downloads a card, chart or receipt | html2canvas | A canvas that can be shown or exported with toDataURL() |
It redraws supported DOM and CSS; it is not a literal pixel capture |
| Visual regression, end-to-end tests or server-side automation | Playwright | An image file or buffer of a browser-rendered element | Requires a Playwright browser environment |
Neither method bypasses browser security policy. Cross-origin frames, images and canvases remain subject to origin rules.
Capture a div with html2canvas
1. Load the library
Install it with npm:
npm install html2canvas
In a bundler-based application:
import html2canvas from 'html2canvas';
Alternatively, load the browser bundle from the project’s documented distribution and call the global html2canvas function after the script has loaded.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
2. Select the element and await the canvas
const element = document.querySelector('#capture');
if (!element) {
throw new Error('Element #capture was not found');
}
try {
const canvas = await html2canvas(element);
document.body.appendChild(canvas);
} catch (error) {
console.error('Could not capture element:', error);
}
The selector must resolve to an element that exists when the capture starts. Waiting until the component has rendered and its content is ready avoids empty or incomplete output.
3. Add a download button
const button = document.querySelector('#download-capture');
const element = document.querySelector('#capture');
button.addEventListener('click', async () => {
if (!element) {
console.error('Element #capture was not found');
return;
}
try {
const canvas = await html2canvas(element);
const link = document.createElement('a');
link.download = 'capture.png';
link.href = canvas.toDataURL('image/png');
link.click();
} catch (error) {
console.error('Capture failed:', error);
}
});
The download value supplies the filename. toDataURL('image/png') converts the canvas into a PNG data URL, and clicking the temporary anchor starts the browser download.
Complete page example
<button id="download-capture" type="button">Download card</button>
<div id="capture" class="card">
<h2>Order complete</h2>
<p>Receipt #4821</p>
</div>
<script type="module">
import html2canvas from 'html2canvas';
const button = document.querySelector('#download-capture');
const element = document.querySelector('#capture');
button.addEventListener('click', async () => {
if (!element) return;
button.disabled = true;
try {
const canvas = await html2canvas(element);
const link = document.createElement('a');
link.download = 'order-complete.png';
link.href = canvas.toDataURL('image/png');
link.click();
} finally {
button.disabled = false;
}
});
</script>
Control the captured region and resolution
Capture a specific rectangle
html2canvas accepts x, y, width and height options when you need to crop the rendered page to a region rather than use the element’s full bounds.
const canvas = await html2canvas(element, {
x: 0,
y: 0,
width: element.getBoundingClientRect().width,
height: element.getBoundingClientRect().height
});
For most div captures, passing the element without crop coordinates is simpler and automatically uses that element’s layout box.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Increase output density with scale
const canvas = await html2canvas(element, {
scale: 2
});
A larger scale creates more pixels and can improve print or high-density display output. It also increases memory use and processing time. Choose a value based on the intended display size; increasing it does not add CSS features that html2canvas does not support.
Capture after content is ready
Run capture after fonts, images and dynamic data have loaded. If your interface renders asynchronously, wait for the component’s own ready state before calling html2canvas. A target that is hidden, detached or still changing can produce an incomplete image.
What html2canvas can and cannot reproduce
The project documentation explains that html2canvas “does not actually take a screenshot of the page, but builds a representation of it based on the properties it reads from the DOM.” It walks the target’s DOM and recreates supported styles on a canvas.
CSS fidelity
Unsupported CSS properties will not render as expected. Complex effects, browser-native controls and newer or less common CSS features may differ from the live page. Test the exact components you intend to export, and provide a simpler export style when visual consistency matters.
Rank #3
Images and canvases from another origin
Browser origin rules prevent JavaScript from freely reading cross-origin content. An inaccessible cross-origin iframe cannot be traversed. Cross-origin images, or a canvas that is already tainted by such an image, can make the resulting canvas unreadable when you call toDataURL().
The useCORS option can help only when the remote server permits the required CORS request:
const canvas = await html2canvas(element, {
useCORS: true
});
A proxy is another documented option, but neither useCORS nor a proxy bypasses browser security policy. You must control the resource or configure its server to allow the access your page needs.
Cross-origin iframes
If an iframe points to a different origin, html2canvas cannot inspect its document. Capture content that your page can access, or use a browser automation workflow that takes a screenshot of the rendered page without trying to read the iframe’s DOM from your application.
Rank #4
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Capture an element with Playwright
For tests, visual regression, scheduled jobs or other automation, Playwright captures the browser-rendered element directly. The locator API waits for the element and writes an image file:
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.locator('.card').screenshot({ path: 'card.png' });
await browser.close();
page.locator('.card').screenshot({ path: 'card.png' }) is the key operation. It captures the element as rendered by the browser, making it a better fit for automated visual checks than a client-side DOM reconstruction. Your test still needs a stable selector and any required authentication or setup.
Troubleshooting common failures
“Element not found” or a blank image
- Check the selector and confirm it is unique.
- Call capture after the component mounts and becomes visible.
- Wait for application data and images to finish loading.
- Do not remove the target from the DOM before the promise resolves.
The output looks different from the page
- Confirm that the CSS used by the component is supported by html2canvas.
- Try a dedicated export stylesheet with simpler effects.
- Use Playwright when you need a browser-rendered image for automation.
toDataURL() throws a security error
- Inspect images inside the target for cross-origin URLs.
- Serve those images with appropriate CORS headers and try
useCORS: true. - Remove inaccessible iframe or canvas content, or capture it in a browser automation context.
Capture is slow or the tab runs out of memory
- Capture only the required element instead of a full page.
- Lower
scaleand avoid unnecessarily large crop dimensions. - Release references to large canvases after converting or downloading them.
- For repeated jobs, move capture to Playwright or a server workflow rather than blocking an interactive page.
The downloaded file has the wrong size
CSS pixels and output pixels differ when scale is greater than one. Check the canvas dimensions and set scale deliberately for the destination, such as a thumbnail, retina display or print asset.
Or skip the browser setup
For server-side or repeatable captures, ScreenshotNeo returns an image or PDF from one request. It removes cookie banners, newsletter popups and chat widgets before the shot; bot checks, blank pages, failed loads and timeouts are not billed; and each response identifies the page verdict and billing status with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Every plan includes features such as full-page capture with lazy images loaded, CSS-selector element capture, device and viewport settings, retina scale, custom CSS and JavaScript, waits, request blocking, cookies and headers, geolocation, transparent backgrounds, resizing, cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data and an OpenAPI specification. Parameter names used by other screenshot APIs also work.
Best Value
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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await Bun.write('shot.webp', bytes);
See the ScreenshotNeo documentation for request options and response headers. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free to try it.
Performance, reliability and cost decisions
- Interactive download: html2canvas keeps everything in the user’s browser and is appropriate when the user initiates the export.
- Pixel fidelity: Playwright uses the browser’s rendered output and is preferable for visual regression or automated evidence.
- Untrusted or changing pages: A managed API avoids shipping browser automation code to every client and can report failed loads separately from billed clean captures.
- Large batches: Use an asynchronous or bulk workflow rather than opening many high-scale canvases in one tab. ScreenshotNeo supports asynchronous jobs and bulk capture of up to 100 URLs per call.
Keep API keys on the server, not in browser JavaScript. For either client-side library, measure memory use with the largest element and scale your users will actually export.
Frequently Asked Questions
Can html2canvas capture a div that contains an iframe?
Only if the iframe document is same-origin and accessible to the page. A cross-origin iframe cannot be traversed by html2canvas because of browser security rules.
Should I use PNG or JPEG for the downloaded image?
Use PNG when you need lossless text, lines or transparency; choose JPEG when a smaller photographic file is more important. The canvas export format controls the result.
Can I take a screenshot without showing the canvas on the page?
Yes. You can convert the returned canvas directly with toDataURL() or toBlob() and trigger a download or upload; appending it to the document is only useful for previewing it.
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.

