October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
HTML

How to Capture a Specific HTML Element as an Image (Playwright and DOM-to-Image)

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

Use a browser automation locator when you need the pixels the browser rendered: in Playwright, call locator.screenshot() on the element. Use html2canvas when the export must run inside your web page and a reconstructed image is acceptable. These methods solve different problems: Playwright captures rendered output, while html2canvas rebuilds an approximation from DOM and CSS.

Choose the right capture method

Requirement Best fit Result and trade-off
Automated test, server job, or CI workflow Playwright locator screenshot Captures the browser-rendered element and saves a file or returns image bytes.
A button that lets visitors export content from your app html2canvas Runs in the page and creates a canvas/data URL, but reconstructs the image rather than reading browser pixels.
PNG, JPEG, or WebP data from a DOM node modern-screenshot Its documented domToPng(node) pattern returns image data; verify current CORS and embedding behavior before shipping.

Decide using four questions: Do you need pixel fidelity? Must code run in the visitor’s tab? Does the element contain cross-origin images or frames? Do you need a file, data URL, or buffer?

Capture one rendered element with Playwright

Playwright launches a real browser, waits for a locator, and screenshots only its bounding box. This is usually the most faithful option for automation.

Install and create a script

npm init -y
npm install -D playwright
npx playwright install chromium

Create capture-element.mjs:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({
  viewport: { width: 1440, height: 1000 },
  deviceScaleFactor: 1
});

await page.goto('https://example.com', { waitUntil: 'networkidle' });
const card = page.locator('.header').first();
await card.waitFor({ state: 'visible' });
await card.screenshot({ path: 'element.png', type: 'png' });

await browser.close();

Replace .header with a stable selector such as an ID, data attribute, or semantic role. The screenshot is clipped to that element, including its visible padding, borders, backgrounds, and descendants.

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

Return bytes instead of writing a file

const imageBytes = await page.locator('#invoice').screenshot({
  type: 'webp',
  quality: 85
});
// Upload imageBytes to object storage or an HTTP response.

JPEG and WebP quality settings apply to lossy formats. PNG is lossless and has no quality parameter.

Make the capture deterministic

  • Wait for a visible locator rather than relying only on a fixed delay.
  • Use waitUntil: 'networkidle' for pages that finish loading their data quickly; for streaming apps, wait for a specific content selector instead.
  • Set a known viewport and device scale factor so output dimensions do not vary by machine.
  • Disable animations in a test stylesheet or wait until transitions finish.
  • For lazy content, scroll the target into view before capture.
await page.locator('#chart').scrollIntoViewIfNeeded();
await page.locator('#chart').screenshot({ path: 'chart.png' });

Element versus full-page screenshots

A full-page screenshot captures the entire document; a locator screenshot clips to one element. Prefer the locator when the target is known: it avoids manual cropping and preserves the browser’s actual layout at the selected viewport.

Export an element in the browser with html2canvas

html2canvas traverses a DOM node and paints a canvas from the properties it understands. It does not take a literal browser screenshot, so unsupported CSS, unreadable resources, and complex effects can differ from what users see.

Minimal download example

<button id="download">Download card</button>
<div id="capture">Your content</div>
<script type="module">
  import html2canvas from 'html2canvas';

  document.querySelector('#download').addEventListener('click', async () => {
    const element = document.querySelector('#capture');
    const canvas = await html2canvas(element);
    const link = document.createElement('a');
    link.download = 'capture.png';
    link.href = canvas.toDataURL('image/png');
    link.click();
  });
</script>

Install it with npm install html2canvas, or load the project’s browser bundle according to your build system.

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

Control resolution, crop, and excluded nodes

const canvas = await html2canvas(document.querySelector('#capture'), {
  scale: window.devicePixelRatio,
  useCORS: true,
  backgroundColor: '#ffffff',
  ignoreElements: element => element.dataset.html2canvasIgnore === 'true'
});
const png = canvas.toDataURL('image/png');

A larger scale produces sharper output but consumes more memory. Mark controls or transient UI with data-html2canvas-ignore="true" when they should not appear.

Why the result may not match the page

The project documentation describes the limitation directly: “The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page.” CSS features outside the library’s supported set, browser-native controls, filters, pseudo-elements, and canvas content can therefore differ. For visual regression or legal evidence, use a real-browser screenshot instead.

Cross-origin images, canvases, and iframes

Images and CORS

html2canvas can read an image only when it is same-origin or the image server grants access with CORS (or you provide a proxy). Set useCORS: true, but remember that the remote server must send an appropriate Access-Control-Allow-Origin header. Otherwise the canvas can become tainted and toDataURL() will fail.

Existing tainted canvases

If the element contains a canvas that previously drew unreadable cross-origin pixels, exporting the parent can still fail. Redraw that canvas from same-origin or CORS-enabled assets before capture.

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

Cross-origin frames

Browser security prevents html2canvas from reading a cross-origin iframe document. Sandboxed frames without allow-same-origin have the same restriction. Capture the framed application from its own origin, or use Playwright and target the frame’s page context where your authorization permits it.

Using modern-screenshot

The modern-screenshot package exposes a compact DOM-to-image API. A typical PNG flow is:

import { domToPng } from 'modern-screenshot';

const node = document.querySelector('#capture');
const dataUrl = await domToPng(node);
const link = document.createElement('a');
link.download = 'capture.png';
link.href = dataUrl;
link.click();

Check the current package release for supported CSS, font embedding, and CORS behavior. Its package documentation warns that partial embedding can fail when resources are blocked by CORS.

Production checklist

  • Selector: use a stable, unique locator and fail clearly when it is missing.
  • Fonts: wait for web fonts before capture when typography matters.
  • Images: wait for each image’s complete state and verify natural dimensions.
  • Animations: pause or disable motion to prevent inconsistent frames.
  • Privacy: remove tokens, personal data, and hidden fields before writing or uploading an image.
  • Memory: large elements at high scale create large canvases; lower scale or capture smaller regions when exports approach browser limits.
  • Retries: retry navigation and transient network failures, but do not blindly retry a deterministic selector or CORS error.
  • Validation: check file type, dimensions, and non-zero byte length before publishing the result.

Troubleshooting

“Locator resolved to multiple elements”

Make the selector specific, use .first() only when the first match is intentional, or iterate over all matching nodes and give each output a distinct filename.

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

The element is empty or clipped

Wait for the element’s content selector, scroll it into view, and confirm that a parent does not have overflow: hidden or a zero height. In Playwright, inspect the locator’s bounding box before taking the screenshot.

Fonts or images are missing

Wait for the relevant network requests or DOM state. For html2canvas, ensure image URLs are same-origin or CORS-enabled; useCORS cannot override a server policy.

SecurityError: Tainted canvases may not be exported

Remove unreadable cross-origin images or serve them with CORS. An already tainted canvas must be redrawn from accessible sources.

Animations produce different captures

Inject a stylesheet that sets transition and animation duration to zero, or wait for a stable state before calling the screenshot method.

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

Playwright cannot launch in CI

Install the browser binaries in the build image with npx playwright install chromium. If the environment is containerized, use the runtime’s documented sandbox configuration rather than disabling security blindly.

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

Or skip the browser setup

ScreenshotNeo captures a specific CSS-selected element through an API, so you do not need to manage Playwright binaries or a rendering server. Its cleanup step accepts cookie banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

Use the ScreenshotNeo API documentation for the complete option list. The API supports element selectors, full-page and lazy-image capture, dark mode, device presets or custom viewports, retina scale, PDF output, custom CSS and JavaScript, pre-capture clicks, wait conditions, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Adapt the URL and add the element-capture parameter described in the documentation.

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

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(`${res.status} ${await res.text()}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every feature is on every plan: Free provides 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. See the free ScreenshotNeo sign-up to begin.

ScreenshotNeo plans

Plan Price Included shots
Free $0 1,000/month, no card
Starter $5 3,000
Growth $15 15,000
Pro $39 60,000
Scale $99 250,000
Business $249 1,000,000

Yearly billing gives two months free. The lowest paid plan is $5 for 3,000 shots.

Frequently Asked Questions

Can I screenshot a hidden element?

A browser screenshot captures what is laid out and rendered. Make the element visible and give it dimensions before capture; otherwise the result may be empty or have a zero-size bounding box.

Which format should I choose?

Use PNG for lossless text and UI, JPEG for smaller photographic files, and WebP when you want a modern format with configurable quality and broad current browser support.

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

Is html2canvas suitable for visual regression tests?

Usually not when pixel accuracy is required. It reconstructs DOM content and can differ from browser pixels; use Playwright’s real-browser screenshot for regression comparisons.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Read next

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.