Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
To capture one rendered <div> in Node.js, load the page in a real browser, identify the element with a stable selector, wait until it exists and is ready, then call the element screenshot method. Playwright uses page.locator('#target').screenshot({ path: 'div.png' }); Puppeteer waits for a selector and calls ElementHandle.screenshot(). Both produce an image clipped to the matched element rather than the whole page.
What an element screenshot actually captures
An element screenshot is a crop of the browser’s rendered pixels at the element’s position and size. It is not an HTML export and it does not capture a hidden or unrendered state. CSS, fonts, images, animations, overlays and the current scroll position all affect the result.
- Covered pixels stay covered. If a cookie dialog, modal, sticky header or another layer sits above the div, the screenshot contains that visible layer instead of the obscured content.
- Scrollable elements are not automatically expanded. A scrollable div shows the content currently inside its scroll position. Capturing its entire scrollable history requires a separate scrolling or stitching design.
- The page must be rendered first. A Node.js HTTP request alone cannot execute the page’s JavaScript or calculate a DOM element’s layout; use Playwright, Puppeteer or a screenshot service that runs a browser.
Use a unique selector such as #invoice-card or [data-testid="hero-card"], not a generic div selector that may match many nodes.
Recommended Free Tools
Playwright: the simplest current API
Playwright’s Locator API describes how to find an element and captures a screenshot clipped to that element’s bounds. Create a project, install Playwright, and install a browser:
#1 Best Overall
mkdir element-shot && cd element-shot
npm init -y
npm install playwright
npx playwright install chromium
Save this as capture-playwright.js:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
});
try {
await page.goto('https://example.com', {
waitUntil: 'networkidle',
timeout: 60_000,
});
const target = page.locator('#target');
await target.waitFor({ state: 'visible', timeout: 15_000 });
await target.screenshot({
path: 'div.png',
type: 'png',
});
console.log('Saved div.png');
} finally {
await browser.close();
}
})();
Replace the URL and #target with your page and selector. The locator method is preferable to an old-style handle for a short capture script because the selector remains the source of truth until the action runs. A locator that resolves to multiple elements should be narrowed with an ID, a data attribute, or another selector that identifies the intended node.
Make the pixels deterministic
Waiting for visibility only proves that the element is displayed. If its contents arrive later, wait for a child, a state class or a known application condition:
await page.locator('#target .chart').waitFor({ state: 'visible' });
await page.waitForFunction(() => document.fonts.status === 'loaded');
await page.waitForTimeout(300); // only when a short animation settling delay is justified
await page.locator('#target').screenshot({ path: 'div.png' });
For repeatable output, set the viewport and device scale factor explicitly, freeze or disable animations with a stylesheet, and authenticate before navigation when the div is behind a login. The screenshot format can be PNG, JPEG or WebP in Playwright’s screenshot tooling; choose the format and quality options supported by the version you install.
Puppeteer: wait for a selector, then capture its handle
Puppeteer’s documented element flow waits for a selector and calls ElementHandle.screenshot(). Install it and a compatible browser package:
Rank #2
mkdir puppeteer-element-shot && cd puppeteer-element-shot
npm init -y
npm install puppeteer
Example:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
try {
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 60_000,
});
const element = await page.waitForSelector('#target', {
visible: true,
timeout: 15_000,
});
if (!element) throw new Error('The #target element was not found');
await element.screenshot({ path: 'div.png', type: 'png' });
console.log('Saved div.png');
} finally {
await browser.close();
}
})();
Puppeteer’s element screenshot attempts to scroll a hidden element into view before capturing it. That behavior helps when the target is below the fold, but it does not remove overlays or expand a scrollable container. Keep the handle close to the capture operation; if the page rerenders the node, reacquire it with waitForSelector.
Playwright versus Puppeteer for a single div
| Concern | Playwright | Puppeteer |
|---|---|---|
| Element API | page.locator(selector).screenshot() |
page.waitForSelector(selector), then handle.screenshot() |
| Waiting style | Locator assertions or locator.waitFor() |
Explicit waitForSelector() and page waits |
| Target model | A locator describes how to retrieve the element | An ElementHandle points to a particular DOM node |
| Visibility caveat | Covered pixels remain covered; current scroll content is captured | Attempts to scroll a hidden element into view; covered and scrollable content still need handling |
| Output formats | PNG, JPEG and WebP are documented for screenshot tooling | Use the formats and options supported by your installed Puppeteer version |
Neither library is a universal performance winner. Select the one already used by your test or automation stack, then pin and periodically update its package and browser versions.
Selectors, layout and page-state edge cases
Selector matches nothing
Check the spelling, whether the element is inside an iframe or shadow root, and whether navigation has finished. For an iframe, obtain the frame first and query inside it. For a shadow root, use the framework’s supported shadow-DOM locator strategy rather than assuming a document-level query can cross the boundary.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesThe image is blank or smaller than expected
Confirm the element has non-zero dimensions, wait for its images and fonts, and inspect computed styles. A transparent background can look blank even when pixels exist. Lazy-loaded content may need the element scrolled into view before waiting for its final child.
Rank #3
A modal or consent banner appears
Dismiss it through the page’s own controls before the screenshot, or hide it with a narrowly scoped stylesheet only when doing so reflects your intended output. Do not blindly remove every fixed-position element: some are part of the div you need.
Animations change every capture
Inject CSS that sets transition and animation durations to zero, wait for images to complete, and capture at a fixed viewport and device scale. If the page uses a canvas or chart, wait for the application’s “ready” signal instead of relying only on network idle.
The target is clipped
Element capture follows the element’s rendered box. For a fixed-height container with overflow: auto, capture the visible region or temporarily change the style and restore it afterward. For a very tall element, verify memory and output-size limits in your deployment environment.
Free tools Windows power users keep installed
One-click scans. No signup required.
Reliability and production practices
- Timeouts: use separate navigation and selector timeouts so a slow page does not hide a missing selector.
- Retries: retry transient navigation failures with a fresh page or browser context; do not endlessly retry deterministic selector errors.
- Cleanup: close pages and browsers in a
finallyblock so failed jobs do not leak Chromium processes. - Security: treat target URLs and page data as untrusted. Restrict outbound network access if users can submit arbitrary URLs, and avoid logging cookies, authorization headers or private query strings.
- Storage: write to a unique path or stream the bytes to object storage. Check that the response finished before reporting success.
- Concurrency: reuse a controlled browser process and limit parallel pages according to available memory. More simultaneous captures can increase contention and timeouts.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It can capture one element by CSS selector, wait for a selector, load lazy images, run custom JavaScript or CSS, click an element, choose a viewport or device preset, and return PNG, JPEG, WebP or PDF. Cookie/consent banners, newsletter popups and chat widgets are removed before the shot; bot checks, blank pages, failed loads and cache hits are not billed, and the response reports the page verdict and billing status.
Send the target selector as the API’s element option (see the parameter names and current syntax in the ScreenshotNeo documentation). The one-call pattern is:
Rank #4
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For a div-specific request, add the selector parameter documented for element capture to that same GET request. The service also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools, so Claude, Cursor and other MCP clients can request captures without you wiring browser automation.
The Free plan includes 1,000 shots per month with no card. Paid plans are Starter $5 for 3,000 shots, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000 and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is on every plan.
Try the free plan: create a ScreenshotNeo account and start with 1,000 screenshots a month without a card.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting checklist
- Open the URL in the same browser engine and confirm the selector in DevTools.
- Log the selector count or bounding box before capture; a zero width or height explains empty output.
- Wait for the specific child, font status or application-ready flag that controls the div’s final content.
- Check overlays, iframe boundaries, shadow roots and scroll containers.
- Capture a full-page diagnostic image once to verify that navigation and authentication succeeded.
- Record navigation time, selector wait time and screenshot time so slow stages are distinguishable.
- When a local script works but production fails, compare browser installation, sandbox permissions, outbound access, viewport, timezone and credentials.
FAQ
Can I capture a div without launching Chromium?
Not with Playwright or Puppeteer: both operate on a rendered browser page. Use a browser-based screenshot API if you do not want to manage that runtime.
Does an element screenshot include content below the fold?
It includes the element’s rendered box. A scrollable box shows its current scroll position rather than every hidden child.
Which selector should I use?
Prefer a stable, unique ID or data attribute owned by your application. Avoid positional selectors and generic div queries that can change as the layout evolves.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Why does my capture show a cookie dialog?
The dialog is part of the rendered page and may cover the target. Dismiss it in automation or use a service that handles consent overlays before capture.
Frequently Asked Questions
Can I capture a div without launching Chromium?
Not with Playwright or Puppeteer; they require a rendered browser page. A browser-based screenshot API is the alternative.
Does an element screenshot include content below the fold?
Only the element’s rendered box and current scroll position are captured.
Which selector should I use?
Use a stable unique ID or data attribute rather than a generic or positional selector.
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.

