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.

To screenshot one part of a web page, identify it with a CSS selector, wait until it is rendered, then call your automation library’s element-screenshot method. In Playwright, the core pattern is page.locator('css=article.card').screenshot(); Puppeteer uses page.waitForSelector() followed by element.screenshot(). Use a page screenshot API instead when you need the viewport or entire document.

The selector is only half the solution. A reliable capture also needs a stable target, a settled layout, an explicit policy for multiple matches, and handling for lazy content, animations and consent UI.

What a CSS-selector screenshot does

A CSS selector describes an element in the page’s DOM. The browser automation tool resolves that description to an element, scrolls it into view when necessary and encodes its rendered pixels as an image. The result can be a card, invoice, form, hero section or any other element rather than the whole page.

Choose an element capture when the output is a component. Choose a page capture when the requirement is the viewport, a full document, or a page-level visual regression. A selector cannot capture content that is not present in the DOM; open menus, lazy images and data loaded after navigation must be made visible first.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Choose a selector that will survive a redesign

Start with the user-facing contract

When a unique role, label, accessible name, visible text, alt text or title identifies the target, prefer that locator in Playwright. It describes what a person recognizes and is usually less coupled to layout than a generated class. CSS remains useful when the target is a visual component or when the page exposes a deliberate CSS contract.

Useful CSS patterns

Pattern Example Best use
ID #invoice A unique, stable element ID.
Component class article.card A repeated component with an intentional class name.
Attribute form[data-testid="checkout"] An explicit automation contract.
Descendant main article.card Scoping a component to a meaningful region.
Direct child nav > ul > li A short, known parent-child relationship.
Playwright extensions button:visible, article:has-text("Results"), section:has(.error) Visibility, text or contained-state filtering.

Keep the chain short. A selector such as body > div:nth-child(3) > div > section > article:nth-child(7) encodes implementation details and is likely to fail after a harmless DOM change. Generated framework classes are similarly brittle. If several elements match, scope to a container, filter by meaningful text, or use an index only when order is part of the page’s contract.

Playwright: capture one element

Minimal runnable example

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com/products', { waitUntil: 'networkidle' });

const card = page.locator('css=article.card');
await card.screenshot({ path: 'card.png', animations: 'disabled' });

await browser.close();

Playwright locators provide auto-waiting and retry behavior. The locator screenshot waits for the element to be actionable, scrolls it into view and captures the matched element. If the selector matches more than one element, make the choice explicit rather than silently accepting an accidental match.

Make the target deterministic

const checkout = page.locator('[data-testid="checkout"]');
await checkout.waitFor({ state: 'visible' });
await checkout.screenshot({
  path: 'checkout.png',
  animations: 'disabled',
  scale: 'css'
});
  • Use a stable ID or data-testid for an automation contract.
  • Wait for page-specific data, fonts or lazy images when visibility alone is insufficient.
  • Disable animations and mask timestamps, rotating ads or other changing regions in visual tests.
  • Use scale: 'css' when you want one output pixel per CSS pixel; device scale is useful when a retina-sized asset is required.

When the page has repeated cards

const results = page.locator('main article.card');
await results.filter({ hasText: 'Pro plan' }).first().screenshot({ path: 'pro-plan.png' });

Filtering by meaningful content is preferable to an arbitrary index. If the order itself is the contract, document that assumption and assert the expected count before capturing.

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

Capturing a whole page in Playwright

Do not use an element selector for a page-level result. Use the page API instead:

await page.screenshot({
  path: 'page.png',
  fullPage: true,
  animations: 'disabled',
  scale: 'css'
});

fullPage: true captures the document rather than only the viewport. A full-page image can still be wrong if content is lazy-loaded or a sticky header changes during scrolling, so trigger the page’s loading behavior and stabilize dynamic regions before the call.

Puppeteer equivalent

Puppeteer accepts CSS selectors by default. Wait for the target, then capture the returned element handle:

Rank #3
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com/products', { waitUntil: 'networkidle0' });

const element = await page.waitForSelector('article.card', { visible: true });
await element.screenshot({ path: 'card.png' });

await browser.close();

Use page.screenshot() for a viewport or document capture. Puppeteer also has locator and alternative selector engines for accessibility, text, XPath and Shadow DOM use cases; use those when a CSS class is not a stable representation of the target.

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

Selenium context

Selenium’s locator guidance favors a unique, predictable ID and then a well-written CSS selector when an ID is unavailable. XPath can express the same targets, but its syntax is generally harder to read and debug. Selenium does not impose one universal element-screenshot workflow across language bindings, so resolve the element with your binding’s CSS locator and call that binding’s element screenshot method. The same rules apply: wait for visibility and layout stability, and decide what to do when multiple elements match.

Selector choice by requirement

Requirement Recommended approach Why
User-visible control Playwright role, label or text locator Matches how a user identifies the control.
Stable automation contract data-testid or stable ID Explicitly separates tests from layout.
Visual component Scoped CSS such as article.card Readable component boundary without a long DOM path.
Page or viewport Page screenshot API No element selector is needed.
Dynamic or animated content Locator screenshot plus waits, disabled animations or masks Reduces nondeterministic pixels.

Waiting, lazy loading and overlays

Wait for the state you actually need

“Visible” means the element has a renderable box; it does not guarantee that its text, image, web font or asynchronous data has finished changing. Wait for a page-specific selector, a known response, a deliberate delay, or network idle according to the application. Avoid an arbitrary long sleep when a precise condition is available.

Make hidden content visible

Click tabs, accordions or menus before the screenshot when the target is intentionally hidden. Scroll through a long page if that is how its lazy images load. If a cookie banner, newsletter popup or chat widget covers the target, dismiss it or hide the covering selector before capture.

Shadow DOM and iframes

Playwright CSS locators pierce open Shadow DOM, but closed shadow roots are not directly addressable from page selectors. For an iframe, first obtain the frame and then resolve the selector inside that frame. A selector in the top document cannot match an element owned by a different browsing context.

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

Common failures and fixes

Symptom Likely cause Fix
“Selector resolved to multiple elements” A repeated component was not scoped. Use a parent container, content filter or an intentional index; assert the count.
Timeout waiting for selector Wrong route, delayed rendering, hidden tab or changed markup. Check the URL and DOM, wait for the real readiness condition, then update the selector to a stable contract.
Blank or clipped image Element has no layout box, is covered, or is still transitioning. Wait for visibility, dismiss overlays, stop animations and verify computed dimensions.
Missing images or text Lazy loading, web fonts or client data had not settled. Trigger lazy loading and wait for the relevant image/data condition before capture.
Flaky visual diffs Animations, timestamps, ads or rotating content. Disable animations, mask dynamic regions, block unnecessary resources and use a fixed viewport.
Works locally, fails in CI Different browser, viewport, permissions, fonts or authentication. Pin the browser/runtime, set the viewport and state explicitly, and log the final URL and matched count.
Selector breaks after a redesign Generated classes or positional DOM traversal changed. Replace it with a role, label, stable ID, test ID or short component selector.

Performance, reliability and output details

  • Reuse one browser process for a batch of URLs, but isolate pages when cookies or authentication must not leak.
  • Set a fixed viewport, color scheme, locale, timezone and device scale when pixel consistency matters.
  • Block ads, trackers and irrelevant resource types only when doing so does not change the component you intend to capture.
  • Use a deliberate filename and record the URL, selector, viewport and timestamp alongside the image for reproducibility.
  • For very large elements, consider a page-level PDF or a purpose-built export instead of creating an unwieldy bitmap.
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 is a website screenshot API and MCP server. It can capture one element by CSS selector without maintaining Playwright, Puppeteer or Selenium infrastructure. The API accepts a URL and options for full-page capture, selector targeting, viewport or device presets, retina scale, waits, custom CSS or JavaScript, clicks, hidden selectors, dark mode, cookies, headers, user agents, authentication, timezone, geolocation and output format. It also supports PDFs, HTML/CSS-to-image, request blocking, caching with a chosen TTL, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification.

See the ScreenshotNeo API documentation for the current parameter names. A selector capture can be requested with one GET call:

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 particular element, add the selector parameter documented for the endpoint (for example, your article.card target) and keep the URL encoded. The same service is available from 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)

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

Before capture, ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed as clean shots, and the response identifies the page verdict and billing status in 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.

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

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; Growth is $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 included on every plan. Create a free ScreenshotNeo account to try selector captures without installing a browser.

FAQ

Can a CSS selector capture several elements into one image?

An element screenshot normally targets one resolved element. Capture each match separately, or wrap the desired elements in a stable container and capture that container.

Should I use CSS or XPath?

Use a short, stable CSS selector when it expresses the target clearly. Use a role, label or test ID when that better represents the user-facing or automation contract; reserve complex XPath for cases CSS cannot express cleanly.

Why does a selector work in the inspector but not in automation?

The automation page may be on a different route, inside an iframe, authenticated differently, or rendering a different responsive DOM. Log the final URL, viewport and browsing context, then inspect the same state in the automated session.

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

How do I capture a responsive mobile version?

Create a context or page with the intended mobile device or viewport before navigation. Keep the selector stable across breakpoints, since responsive layouts may render different component structures.

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.