How to Take a Screenshot of a Specific HTML Element in Chromium
Capture one DOM element as a saved image with Playwright, or use Chrome’s Element Capture API to restrict a live video stream to that element.
To save a screenshot of one HTML element in Chromium, use browser automation such as Playwright and call the element’s screenshot() method. This captures that element as an image file. Chrome’s Element Capture API is a different tool: it restricts a live tab-capture video track to an element and its descendants; it is not the usual way to save a PNG.
This guide covers both workflows, their limits, output options, and common failures. Use Playwright for a still image. Use Element Capture when you need a live video stream of a region.
1. Save an element screenshot with Playwright
Playwright can target an element through a locator. The following complete Node.js example opens Chromium, waits for the target to become visible, and saves it as a PNG.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const card = page.locator('#pricing-card');
await card.waitFor({ state: 'visible' });
await card.screenshot({ path: 'pricing-card.png' });
} finally {
await browser.close();
}
Install Playwright and its Chromium browser if they are not already available in your project:
npm install playwright
npx playwright install chromium
Replace #pricing-card with a selector for the element you want. Prefer a stable ID, test ID, or other selector that is unlikely to change with page styling. If the selector matches more than one element, narrow it or choose the intended match explicitly.
Choose an image format and scale
Playwright supports PNG, JPEG, and WebP screenshots. The file extension can be used to select a format, or you can set type explicitly. For example:
await page.locator('#pricing-card').screenshot({
path: 'pricing-card.webp',
type: 'webp',
quality: 85
});
Quality applies to lossy formats such as JPEG and WebP. PNG is lossless. Element screenshot dimensions normally follow the element’s CSS-pixel size. To capture at device-pixel-ratio scale, create the browser context with deviceScaleFactor:
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
deviceScaleFactor: 2
});
const page = await context.newPage();
A scale factor of 2 produces a denser image, useful for high-resolution output, at the cost of a larger file and more image data. fullPage is for a whole page screenshot and cannot be combined with an element target.
Wait for the content you need
Navigation completion does not guarantee that asynchronous content, images, charts, or fonts are ready. Wait for a meaningful condition before capture. For example:
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('#pricing-card').waitFor({ state: 'visible' });
await page.locator('#pricing-card img').first().waitFor({ state: 'visible' });
await page.locator('#pricing-card').screenshot({ path: 'pricing-card.png' });
For applications that render after an API response, wait for the relevant text or state rather than adding an arbitrary delay. If the page uses lazy loading, scroll the target into view; Playwright’s locator actions generally bring elements into view, but content may still need time to load.
2. Capture an element from a live Chrome tab with Element Capture
Chrome’s Element Capture API restricts a video track created from the current tab so that frames contain a chosen element and its descendants. It is intended for capturing or recording a live region. Chrome documents availability from Chrome 132 on desktop and says it is currently enabled only for self-capture.
The API requires a user-mediated tab capture. This minimal example shows the core flow; run it in a secure context and provide a page button or other user action to start capture.
async function captureElement() {
const target = document.querySelector('#share-region');
if (!target) throw new Error('Capture target not found');
if (!('RestrictionTarget' in window) ||
typeof RestrictionTarget.fromElement !== 'function') {
throw new Error('Element Capture is not available in this browser');
}
const stream = await navigator.mediaDevices.getDisplayMedia({
preferCurrentTab: true,
video: true
});
const track = stream.getVideoTracks()[0];
if (!track) {
stream.getTracks().forEach((item) => item.stop());
throw new Error('No video track was returned');
}
try {
const restrictionTarget = await RestrictionTarget.fromElement(target);
await track.restrictTo(restrictionTarget);
return stream;
} catch (error) {
stream.getTracks().forEach((item) => item.stop());
throw error;
}
}
// Call from a user gesture, such as a button click.
document.querySelector('#start-capture').addEventListener('click', async () => {
try {
const stream = await captureElement();
document.querySelector('video').srcObject = stream;
} catch (error) {
console.error('Could not capture element:', error);
}
});
The restriction includes the target and its descendants. Siblings and content that occludes or is occluded by the target are excluded from resulting frames. This is a video stream workflow; to produce a still image from the stream, render a video frame to a canvas and export it, subject to the usual video and canvas constraints.
Element Capture eligibility and limitations
- The target must belong to the tab whose self-capture track is being restricted. A target created in another tab is invalid.
- The target must remain in the document. Removing it prevents capture.
- The track must be a self-capture video track. A track with clones can also cause the restriction operation to fail.
- The target needs suitable geometry: Chrome describes it as a cohesive two-dimensional rectangle whose pixels can be determined independently of its parents and siblings, and it should form its own stacking context. Consider
isolation: isolate. - An element or ancestor with
display: noneis an example of an ineligible target. If style changes make the target ineligible, new frames stop until eligibility returns. - The captured video has no alpha channel. Transparent pixels can appear differently, including as black areas. Inspect the actual stream before relying on its appearance.
3. Choose the right capture route
| Need | Recommended route | Why |
|---|---|---|
| Save a PNG, JPEG, or WebP of one DOM element | Playwright element screenshot | Directly targets a locator or element and writes a still image. |
| Share or record a live region from the current tab | Chrome Element Capture | Restricts a self-capture video track to the target and its descendants. |
| Build an extension with lower-level browser debugging control | Chrome debugger API and CDP | Offers a debugging transport, but requires additional CDP implementation detail. |
Chrome’s chrome.debugger extension API requires the debugger permission. Managed-device policy can prevent attachment: Chrome documents that enterprise DisableScreenshots policy or data loss prevention restrictions may trigger a screenshot-restriction error. This route is more involved than Playwright for a saved element image.
4. Troubleshoot common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Playwright says the locator resolved to no element | The selector is wrong, the element has not rendered yet, or it is inside a frame. | Check the selector in the page, wait for the target, and use the appropriate frame locator when needed. |
| Screenshot is blank or missing expected content | The target is hidden, content has not loaded, or an image/chart is still rendering. | Wait for visibility and a content-specific readiness condition; confirm the target is not hidden by CSS. |
| Screenshot clips or captures an unexpected size | The element’s rendered bounds differ from the expected CSS dimensions. | Inspect its bounding box and layout at the chosen viewport; use a suitable viewport and device scale factor. |
RestrictionTarget is undefined |
The browser does not support the API, or the feature is unavailable in that environment. | Feature-detect RestrictionTarget and fromElement; use Playwright if a saved still image is the requirement. |
restrictTo() rejects or frames stop |
The target is from another tab, was removed, is ineligible, or the track is not valid self-capture. | Use a current-tab target, keep it connected, restore eligible layout and stacking context, and use the original un-cloned capture track. |
| Debugger attachment is rejected by a screenshot restriction | An enterprise screenshot policy or DLP rule blocks debugging access. | Check managed-device policy with the administrator; do not assume page JavaScript can override it. |
5. Performance, reliability, and cost
An element screenshot avoids saving the rest of the page, but browser startup, navigation, JavaScript execution, and asset loading often dominate the work. Reuse a browser process for batches of captures when appropriate, keep the viewport stable, wait on specific conditions, and avoid unnecessary high device scale factors when file size matters.
For reliability, use stable selectors, explicit timeouts appropriate to the site, and cleanup in a finally block so the browser closes after errors. Pages that depend on authentication, geolocation, locale, or third-party assets may render differently unless the automation context reproduces those conditions. A saved screenshot is a snapshot of the rendered state, so dynamic content can vary between runs.
Playwright is open-source software; your operational costs are the machine, browser execution, and any infrastructure you use to run captures. Chrome Element Capture is a browser API for a live stream and does not itself provide a still-image service or hosted capture endpoint.
6. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. For a full-page screenshot of a URL, send one request; see the ScreenshotNeo API documentation. An API call captures a page URL; it does not select a CSS element from an already-open browser DOM like Playwright does.
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,
)
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 request failed: ${res.status}`);
await Bun.write('shot.webp', res);
- Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed. Response headers say the page verdict and whether the request was billed.
- An MCP server lets AI agents, including Claude, Cursor, and other MCP clients, take screenshots.
- 1,000 screenshots a month are free with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
7. Frequently asked questions
Can I use Playwright’s full-page option and target an element together?
No. Full-page capture and an element target are separate modes; use the element screenshot for one node, or a page screenshot for the whole document.
Does Chrome Element Capture save a PNG directly?
No. It restricts a live video track. If you need a saved still image directly, use an automation screenshot operation such as Playwright’s element screenshot.
Can Element Capture include transparent pixels?
The captured video has no alpha channel, so transparent content may display with changed colors or as black. Check the rendered stream rather than expecting a transparent still.
Can an extension always take screenshots through chrome.debugger?
No. The extension needs the debugger permission, and enterprise screenshot or DLP policy can block debugger attachment.


