Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsUse Puppeteer’s ElementHandle.screenshot() to capture one rendered DOM element. Query the element with page.$(), verify that it exists, wait for your application’s content to be ready, then call element.screenshot() with a file path or output options. Puppeteer scrolls the element into view automatically; it throws if the handle is detached from the DOM.
Capture one element with Puppeteer
The following CommonJS script launches Chromium, opens a page, finds an element, saves it as a PNG, and cleans up both the handle and browser. It uses the current Puppeteer API documented for the 25.x line; pin the version used by your project so behavior and types remain reproducible.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
const element = await page.$('#target');
if (!element) {
throw new Error('Target element not found: #target');
}
try {
await element.screenshot({ path: 'element.png' });
console.log('Saved element.png');
} finally {
await element.dispose();
}
} finally {
await browser.close();
}
})();
ElementHandle.screenshot() captures the rendered element and scrolls it into view when necessary. The path option writes the bytes to disk; a relative path is resolved from the process’s current working directory. If the selector matches nothing, page.$() returns null, so checking the result gives a useful error instead of a less specific failure later.
Install Puppeteer and run the script with:
npm install puppeteer
node element-shot.js
The method is documented at pptr.dev/api/puppeteer.elementhandle.screenshot. The related handle lifecycle is described in the ElementHandle class reference.
#1 Best Overall
Make the capture deterministic
Element capture only guarantees the mechanics of finding, scrolling, and rasterizing the element. It does not know when your application has finished fetching data, decoding images, loading web fonts, or ending an animation. Wait for the condition that matters to your page before taking the shot.
Wait for the element and its content
await page.goto('https://example.com/dashboard', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-testid="sales-card"]', {
visible: true,
timeout: 30_000
});
// Prefer an application-specific readiness signal.
await page.waitForFunction(() => {
const card = document.querySelector('[data-testid="sales-card"]');
return card?.getAttribute('data-rendered') === 'true';
});
const card = await page.$('[data-testid="sales-card"]');
if (!card) throw new Error('Sales card disappeared before capture');
await card.screenshot({ path: 'sales-card.png' });
await card.dispose();
A selector wait confirms that a node exists, not that its data is correct. An application-owned attribute, a completed network request, or a deliberate short delay after a known animation is usually more reliable than an arbitrary global timeout. If images affect the result, wait for their complete state and for naturalWidth to be nonzero, or expose a page-level “ready” flag.
Handle dynamic rerenders
React, Vue, and other frameworks can replace a node while your script is holding its handle. A detached handle causes the documented screenshot error; Puppeteer does not promise an automatic retry. Query close to the capture, and retry by reacquiring the element only when your application expects a transient rerender.
async function captureWithReacquire(page, selector, path) {
for (let attempt = 1; attempt <= 2; attempt++) {
const handle = await page.$(selector);
if (!handle) throw new Error(`No element matches ${selector}`);
try {
await handle.screenshot({ path });
return;
} catch (error) {
if (attempt === 2 || !String(error.message).toLowerCase().includes('detached')) {
throw error;
}
} finally {
await handle.dispose();
}
}
}
Choose the output format and destination
The method returns a Uint8Array by default when no path is supplied. Request base64 with encoding: 'base64'. Supplying path saves the image and still lets you select format and quality through screenshot options.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #2
Save PNG, JPEG, or WebP
await element.screenshot({ path: 'card.png', type: 'png' });
await element.screenshot({ path: 'card.jpg', type: 'jpeg', quality: 82 });
await element.screenshot({ path: 'card.webp', type: 'webp', quality: 82 });
Puppeteer infers the image type from the filename extension when possible. PNG is lossless and is the practical choice for text, diagrams, and transparency. JPEG and WebP can reduce file size when lossy compression is acceptable. The quality value ranges from 0 to 100 and does not apply to PNG. These options are defined in the ScreenshotOptions interface.
Keep the image in memory
const bytes = await element.screenshot();
await storageClient.put('card.png', bytes, { contentType: 'image/png' });
const base64 = await element.screenshot({ encoding: 'base64' });
const dataUri = `data:image/png;base64,${base64}`;
Use the byte result for object storage or an HTTP response. Base64 is convenient for JSON or data URIs but increases payload size, so avoid it for large images when binary transfer is available.
Transparent backgrounds
await element.screenshot({
path: 'logo.png',
omitBackground: true
});
omitBackground: true hides Puppeteer’s default white background. Transparency still depends on the element and its ancestors actually having transparent backgrounds; a solid CSS background remains visible.
Element scope versus page scope
Use ElementHandle.screenshot() when the desired region is one DOM element. Use Page.screenshot() for the viewport or the complete document. The page method supports the same core output settings and adds page-level controls.
| Goal | API | Important options |
|---|---|---|
| One card, chart, component, or image | element.screenshot() |
path, type, quality, omitBackground |
| Current viewport | page.screenshot() |
viewport dimensions, format, clipping |
| Entire document | page.screenshot({ fullPage: true }) |
fullPage, format, quality |
| Fixed rectangle | page.screenshot({ clip }) |
clip, captureBeyondViewport |
For page screenshots, fullPage defaults to false. The documented captureBeyondViewport default is false when no clip is provided and true when a clip is provided. A clip is useful when you need coordinates rather than a semantic DOM target, but coordinates are more sensitive to responsive layout changes.
Within a BrowserContext, Puppeteer waits for a screenshot to finish before creating or closing pages. page.bringToFront() does not wait for existing screenshot operations, so coordinate concurrent work deliberately. See the Page.screenshot() documentation.
TypeScript and typed element handles
The handle API accepts a generic element type, which lets TypeScript narrow DOM properties when you evaluate against the node.
import puppeteer, { ElementHandle } from 'puppeteer';
const canvas = await page.$<HTMLCanvasElement>('#chart');
if (!canvas) throw new Error('Chart canvas not found');
const dimensions = await canvas.evaluate(el => ({
width: el.width,
height: el.height
}));
await canvas.screenshot({ path: 'chart.png' });
await canvas.dispose();
Use a type such as HTMLDivElement or HTMLCanvasElement when it improves checks in your codebase; it does not change the pixels Puppeteer captures.
Rank #4
Troubleshooting common failures
“Target element not found”
- Cause: The selector is wrong, the page has not navigated to the expected route, or the element is inside an iframe.
- Fix: Verify the URL and selector, wait with
page.waitForSelector(), and query the correct frame rather than the top-level page.
Detached-element error
- Cause: A framework replaced or removed the node after you obtained the handle.
- Fix: Wait for the application’s stable state, reacquire the handle immediately before capture, and retry only a bounded number of times.
Image is blank or incomplete
- Cause: Data, fonts, lazy images, or transitions were still loading.
- Fix: Wait for a page-specific ready signal, confirm image decoding, disable or finish animations in test CSS, and use a suitable navigation wait condition.
Unexpected format or file location
- Cause: The extension, explicit
type, or current working directory differs from what you assumed. - Fix: Set
typeexplicitly, use an absolute path when needed, and inspect the process working directory.
Transparent output still looks white
- Cause: An ancestor or the target itself has a white CSS background.
- Fix: Remove that CSS background and keep
omitBackground: true.
Performance, reliability, and operational practices
- Reuse a browser instance for a batch of captures, but create isolated pages or contexts for unrelated sessions.
- Close pages and dispose handles that remain in use; navigation and destruction of a parent context automatically dispose associated handles.
- Capture after the smallest reliable readiness condition instead of waiting for an unnecessarily long global timeout.
- Use PNG only where lossless pixels or alpha matter; choose JPEG or WebP with a tested quality setting for bandwidth-sensitive workflows.
- Keep selectors stable with attributes such as
data-testidrather than styling classes that change during redesigns. - Record the URL, selector, viewport, Puppeteer version, output type, and failure message so a bad capture can be reproduced.
- Do not assume a successful API call means the application rendered correctly: validate dimensions, file type, and—when important—pixel or content expectations in your pipeline.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server when you want one request instead of managing Chromium. Its clean-shot pipeline accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.
For a direct element capture, pass the target selector and other options supported by the API:
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
--data-urlencode selector="#target"
-o shot.webp
See the full parameter list and authentication details in the ScreenshotNeo documentation. The same endpoint supports full-page captures, dark mode, device presets, retina scale, custom CSS and JavaScript, clicks, waits, blocked requests, cookies, headers, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs, webhooks, bulk capture of up to 100 URLs per call, usage reporting, and PDF output.
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://stripe.com",
"selector": "#target",
},
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',
selector: '#target'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo HTTP ${res.status}`);
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. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Plans are $15 for 15,000 (Growth), $39 for 60,000 (Pro), $99 for 250,000 (Scale), and $249 for 1,000,000 (Business); yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to start with the 1,000-shot allowance.
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 matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallFAQ
Does an element screenshot include content outside the element?
No. The capture is scoped to the rendered element’s bounds. Use a page screenshot with clip or fullPage when you need a larger region.
Can I capture an element that is off-screen?
Yes. Puppeteer scrolls the element into view before capturing it.
What happens if the element is removed during capture?
The documented behavior is an error for a detached element. Reacquire the handle after the page reaches a stable state.
Which Puppeteer version should production code use?
Pin and record the version installed by your project. The official references reviewed display 25.12.0 for the screenshot method and 25.10.0 for the ElementHandle class, so examples should not imply that every release has identical documentation labels.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Frequently Asked Questions
Does an element screenshot include content outside the element?
No. The capture is scoped to the rendered element’s bounds. Use a page screenshot with clip or fullPage when you need a larger region.
Can I capture an element that is off-screen?
Yes. Puppeteer scrolls the element into view before capturing it.
What happens if the element is removed during capture?
The documented behavior is an error for a detached element. Reacquire the handle after the page reaches a stable state.
Which Puppeteer version should production code use?
Pin and record the version installed by your project. The official references reviewed display 25.12.0 for the screenshot method and 25.10.0 for the ElementHandle class, so examples should not imply that every release has identical documentation labels.
Free tools Windows power users keep installed
One-click scans. No signup required.
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.

