October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
browser automation

How to Capture an Entire Element with a Puppeteer Screenshot

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

Use an element handle, not page.screenshot({fullPage: true}). Wait for the target node, then call ElementHandle.screenshot():

const element = await page.waitForSelector('#target');
await element.screenshot({ path: 'element.png' });

Puppeteer scrolls the selected element into view when necessary and captures its rendered bounds, including content outside the current viewport. A full-page screenshot is a different operation: it captures the document, not one element.

Element screenshots and full-page screenshots are different

Puppeteer has two scopes:

  • Element scope: an ElementHandle followed by element.screenshot(). Use this for one card, article, chart, component, or other DOM node.
  • Document scope: page.screenshot({ fullPage: true }). Use this for the entire scrollable page.

The fullPage option is page-level and defaults to false. It does not expand a selected element. If the requirement is “the whole element,” select that element and capture its handle.

Minimal runnable Puppeteer example

This script opens a page, waits for a target, captures it, and always closes the browser:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });

  const element = await page.waitForSelector('#target');
  if (!element) throw new Error('Target element was not found');

  await element.screenshot({ path: 'target.png' });
} finally {
  await browser.close();
}

Run it in an environment configured for ECMAScript modules, or adapt the import to your project’s module system. Replace https://example.com and #target with the page and selector you need.

Make the captured pixels final before taking the shot

waitForSelector confirms that a node exists; it does not guarantee that its fonts, images, animations, or client-side data have finished rendering. Add waits that match the application:

Wait for a specific selector

await page.waitForSelector('#report.ready');
const element = await page.$('#report');
if (!element) throw new Error('Report is missing');
await element.screenshot({ path: 'report.png' });

Wait for images to decode

await page.waitForSelector('#report');
await page.evaluate(async () => {
  const images = Array.from(document.querySelectorAll('#report img'));
  await Promise.all(images.map(img => {
    if (img.complete) return img.decode?.().catch(() => {});
    return new Promise(resolve => {
      img.addEventListener('load', resolve, { once: true });
      img.addEventListener('error', resolve, { once: true });
    });
  }));
});
const element = await page.$('#report');
if (!element) throw new Error('Report is missing');
await element.screenshot({ path: 'report.png' });

Wait for fonts

await page.evaluate(async () => {
  if (document.fonts?.ready) await document.fonts.ready;
});

For data loaded after navigation, wait for the application’s “ready” selector or a page-specific promise rather than relying only on a fixed delay. A delay can be useful for an animation, but a state-based wait is usually less brittle.

Dynamic pages: avoid detached element handles

When a framework rerenders a component, the original handle can point to a node that is no longer attached to the DOM. Puppeteer throws when an element handle has been detached. Query the selector again immediately before capture, after the render that matters:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.waitForSelector('#target');
await page.waitForFunction(() => {
  const node = document.querySelector('#target');
  return node && node.isConnected && node.getBoundingClientRect().height > 0;
});

const element = await page.$('#target');
if (!element) throw new Error('Target disappeared');
await element.screenshot({ path: 'target.png' });

If the page can rerender during capture, pause the state change (for example, finish a transition or wait for a stable application state) and reacquire the handle just before calling screenshot().

Screenshot options that matter

ElementHandle.screenshot() accepts the screenshot options used by Puppeteer’s page screenshot machinery. Choose only the options that match your output requirement.

Option What it does Important detail
path Writes the image to a file. Omit it to receive screenshot bytes instead.
encoding: 'base64' Returns a base64 string. Useful when an in-memory transport expects text rather than a file.
type Selects png or jpeg. PNG is lossless; JPEG is smaller for many photographic images.
quality Controls JPEG quality. It applies to JPEG, not PNG.
clip Captures a manual page rectangle. This changes the geometry from automatic element bounds to your supplied rectangle.
captureBeyondViewport Controls whether a clipped region may extend beyond the viewport. The documented default depends on whether clip is present.
omitBackground Hides the default white background. Use it when you need transparency-capable output.

Save a JPEG with quality

const element = await page.waitForSelector('#hero');
if (!element) throw new Error('Hero not found');
await element.screenshot({
  path: 'hero.jpg',
  type: 'jpeg',
  quality: 85
});

Keep bytes in memory

const element = await page.waitForSelector('#chart');
if (!element) throw new Error('Chart not found');
const pngBytes = await element.screenshot({ type: 'png' });
// Send pngBytes to object storage, an HTTP response, or another service.

Request base64

const element = await page.waitForSelector('#thumbnail');
if (!element) throw new Error('Thumbnail not found');
const base64 = await element.screenshot({ encoding: 'base64' });

Geometry, scrolling, and layout edge cases

Content taller than the viewport

The element method scrolls the node into view and captures the element rather than merely cropping the visible viewport. This is the normal solution for a long component. If the element uses an internal scroll container such as overflow: auto, its screenshot reflects the rendered box; content hidden by that container is not automatically turned into a longer document. To capture all rows, first expand the container or remove the limiting overflow in a controlled page-side style.

Sticky and fixed descendants

Sticky headers, fixed toolbars, and overlays can appear according to their position at capture time. Hide or restyle them before the shot if they obscure the target:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.addStyleTag({
  content: '.cookie-banner, .chat-widget { display: none !important; }'
});

Transforms and fractional pixels

CSS transforms can make an element’s visual bounds differ from its untransformed layout box. If exact geometry matters, inspect the rendered rectangle and consider a manual clip only when you deliberately want page coordinates. A selector-based element capture is preferable for ordinary components because Puppeteer calculates the target’s bounds for you.

Responsive output

Set the viewport before navigation so responsive breakpoints, wrapping, and lazy content are deterministic:

await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });

For high-density output, increase deviceScaleFactor; the resulting bitmap dimensions and file size will increase.

Common errors and fixes

Symptom Likely cause Fix
Cannot read properties of null or a missing handle The selector did not match yet, or the node was removed. Use waitForSelector, check the returned handle, and verify the selector and frame.
Detached element exception A client-side rerender replaced the node. Wait for the render to settle and query the selector again immediately before capture.
Image, font, or data is missing The node exists before its visual content is ready. Wait for the relevant ready state, image decode, font readiness, or application request.
Only the visible portion appears You used a page crop, an internal scroll container, or a manual clip. Use element.screenshot(); expand internal overflow content if “all rows” are required.
The whole page was captured page.screenshot({ fullPage: true }) was used. Replace it with a handle to the desired node and call the handle’s screenshot method.
Unexpected cookie or chat overlay A consent banner or widget covers the page. Handle the banner in the page workflow or hide the overlay before selecting the target.
Blank or navigation timeout The URL, network, authentication, or page scripts did not complete. Check navigation errors, credentials, resource blocking, and use a wait condition appropriate to the site.

Reusable helper for production scripts

Wrapping the repeated checks in a helper makes failures explicit and keeps cleanup in the caller:

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.
async function captureElement(page, selector, options = {}) {
  await page.waitForSelector(selector);
  const handle = await page.$(selector);
  if (!handle) throw new Error(`Element not found: ${selector}`);
  return handle.screenshot(options);
}

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 800 });
  await page.goto('https://example.com/dashboard', { waitUntil: 'networkidle2' });
  await page.waitForFunction(() => document.fonts?.status === 'loaded');
  await captureElement(page, '#dashboard-card', {
    path: 'dashboard-card.png',
    type: 'png'
  });
} finally {
  await browser.close();
}

Performance, reliability, and cost considerations

Reduce unnecessary work

  • Reuse a browser process for multiple pages instead of launching Chromium for every element.
  • Set the viewport and navigation wait condition deliberately; waiting for every network request can delay pages that keep analytics connections open.
  • Use PNG for text and sharp UI; use JPEG with a suitable quality when a smaller photographic image is acceptable.
  • Capture only the required node rather than the full document when downstream systems need a component.

Make jobs reproducible

  • Pin the Puppeteer version used by your project and run captures with a consistent browser executable.
  • Set locale, timezone, viewport, and authentication explicitly when they affect layout.
  • Record the URL, selector, viewport, and wait condition with each artifact so a mismatch can be diagnosed.
  • Close pages and browsers in finally blocks, including when navigation or capture throws.

Security boundaries

Only visit URLs and execute page-side code that your workflow trusts. Treat screenshots and returned bytes as potentially sensitive, especially when the page contains account data. Keep credentials out of selectors, filenames, logs, and generated HTML.

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 provides a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF, and its element capture accepts a CSS selector. It can load lazy images, wait for a selector, delay, or network idle, and apply custom CSS or JavaScript when a page needs preparation.

Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the parameter reference and examples in the ScreenshotNeo documentation. A direct request looks like this (replace the URL and key):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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(`Screenshot failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

ScreenshotNeo also supports dark mode, device presets and custom viewports, retina scale, PDF paper and page-range controls, click-before-capture actions, hidden selectors, blocked ads or resource types, custom headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.

Every feature is available on every plan: Free includes 1,000 shots per month with no card; Starter is $5 for 3,000; 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. Sign up for the free plan to get 1,000 screenshots a month without a card.

Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

FAQ

Does an element screenshot include content below the viewport?

Yes, when that content belongs to the element’s rendered box. Puppeteer scrolls the element into view and captures it; content clipped by an internal scroll container still requires you to expand that container.

Can I return the screenshot without writing a file?

Yes. Omit path to receive bytes, or request encoding: 'base64' when a text transport is required.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Why does my selector work in DevTools but not in Puppeteer?

The element may be inside an iframe, appear after client-side rendering, or use a different URL state. Wait for it, select the correct frame, and confirm the page has reached the expected route before querying.

When should I use a manual clip?

Use clip when you intentionally need a page-coordinate rectangle. For a normal DOM component, an element handle avoids maintaining those coordinates yourself.

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 *

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

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

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.