Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteUse a locator for the scrollable element and call locator.screenshot(). Playwright captures the element’s visible bounds at its current internal scroll position; it does not automatically stitch every pixel in a long, scrollable container. Set scrollTop, scroll with the mouse, wait for lazy content, and then capture each position you need.
This distinction matters because page.screenshot({ fullPage: true }) captures the full scrollable page, not the complete internal scroll range of a nested panel. The official guidance is documented in Playwright’s screenshots guide and the Locator API reference.
Capture the visible portion of a scrollable element
Start with a locator, position the container, and call its screenshot method:
import { test } from '@playwright/test';
test('capture a scrolling panel', async ({ page }) => {
await page.goto('https://example.com/dashboard');
const panel = page.getByTestId('scrolling-container');
await panel.waitFor();
await panel.screenshot({ path: 'panel.png' });
});
The resulting image is clipped to the locator’s rendered bounds. If the element is a scrollable container, only the content currently visible through that container appears. A locator screenshot is therefore the correct API for “what the user can see in this panel right now,” not for a one-call, stitched image of the panel’s entire internal scroll range.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11#1 Best Overall
Prefer a stable role, test ID, or accessible label over a brittle CSS chain. For example:
const panel = page.getByRole('region', { name: 'Activity feed' });
// or: page.getByTestId('activity-feed');
await panel.screenshot({ path: 'activity-visible.png' });
Choose the capture scope first
| Goal | API | What it captures |
|---|---|---|
| Visible part of one element | locator.screenshot() |
The element’s box at its current scroll position |
| Entire page, including page-level scrolling | page.screenshot({ fullPage: true }) |
A full scrollable page rendered as one tall screenshot |
| Specific internal section | locator.evaluate() plus locator.screenshot() |
The section after you set its internal offset |
Playwright describes a full-page screenshot as a full scrollable page “as if you had a very tall screen and the page could fit it entirely.” That option changes page capture scope; it does not make a locator screenshot traverse a nested element’s hidden content.
Set an exact scroll position with scrollTop
For deterministic captures, set the element’s scroll offset in the browser context:
const panel = page.getByTestId('scrolling-container');
await panel.evaluate((element) => {
element.scrollTop = 500;
});
await panel.screenshot({ path: 'panel-at-500px.png' });
500 is only an example. Select an offset based on the content you need. You can read the dimensions first and clamp the requested position so it cannot exceed the available range:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const panel = page.getByTestId('scrolling-container');
const metrics = await panel.evaluate((element) => ({
scrollTop: element.scrollTop,
scrollHeight: element.scrollHeight,
clientHeight: element.clientHeight,
}));
const requestedOffset = 500;
const maxOffset = Math.max(0, metrics.scrollHeight - metrics.clientHeight);
await panel.evaluate((element, offset) => {
element.scrollTop = offset;
}, Math.min(requestedOffset, maxOffset));
await panel.screenshot({ path: 'panel-positioned.png' });
Setting scrollTop works when the locator resolves to the actual scrolling node. If a wrapper contains the scrollbar, target that wrapper instead.
Scroll like a user with the mouse
When application behavior depends on wheel input, hover the panel and send a wheel event:
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
const panel = page.getByTestId('scrolling-container');
await panel.hover();
await page.mouse.wheel(0, 600);
await page.waitForTimeout(200);
await panel.screenshot({ path: 'panel-after-wheel.png' });
Mouse scrolling is useful for virtualized or infinite lists that load more rows in response to user-like movement. The Playwright input guide covers programmatic and mouse scrolling at playwright.dev/docs/input. Avoid arbitrary sleeps when your app exposes a reliable readiness signal; wait for a row, spinner disappearance, or network state instead.
Capture several positions when the element is taller than its viewport
Because a locator screenshot does not stitch internal scroll positions, capture a sequence of viewports if you need complete coverage:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →import { test } from '@playwright/test';
test('capture every panel segment', async ({ page }) => {
await page.goto('https://example.com/dashboard');
const panel = page.getByTestId('scrolling-container');
const { maxOffset, viewport } = await panel.evaluate((element) => ({
maxOffset: Math.max(0, element.scrollHeight - element.clientHeight),
viewport: element.clientHeight,
}));
const step = Math.max(1, viewport);
let index = 0;
for (let offset = 0; offset <= maxOffset; offset += step) {
await panel.evaluate((element, value) => {
element.scrollTop = value;
}, Math.min(offset, maxOffset));
// Replace this with a row/asset readiness assertion in your app.
await panel.screenshot({ path: `panel-${index}.png` });
index += 1;
}
});
Adjacent images can overlap or miss content if the scroll step and layout change between captures. For a single composite artifact, record the offsets and compose the images with an image-processing library after capture. The official Locator, screenshots, and input documentation does not specify a built-in locator option that stitches all internal positions.
Wait for lazy, virtualized, and animated content
Lazy-loaded images
Scrolling may be what triggers an image or row to load. After moving the panel, wait for the specific asset or row:
await panel.evaluate((element) => {
element.scrollTop = element.scrollHeight;
});
await panel.locator('img[data-loaded="true"]').first().waitFor();
await panel.screenshot({ path: 'panel-bottom.png' });
Use an application-specific selector rather than assuming one universal wait condition. For network-driven interfaces, combine a locator assertion with a bounded timeout.
Disable animation for repeatable images
The Locator API supports animations: 'disabled':
await panel.screenshot({
path: 'panel-stable.png',
animations: 'disabled',
});
Playwright says this disables CSS animations, CSS transitions, and Web Animations. Finite animations are fast-forwarded to completion; infinite animations are canceled to their initial state during capture.
Rank #3
Element screenshot options worth using
path: writes PNG, JPEG, or another format inferred from the filename.animations: 'disabled': removes timing differences from supported animations.maskandmaskColor: useful when your test policy allows masking dynamic regions; verify the option against the Playwright version installed in your project.quality: applies to JPEG screenshots when you need smaller files.scale: controls whether output follows device pixels or CSS pixels; choose consistently for visual comparisons.
Consult the versioned Locator API reference for the exact option set supported by your installed Playwright release.
Common failures and precise fixes
The screenshot shows only the top rows
Cause: the panel was never scrolled, or the locator points to a non-scrolling wrapper.
Fix: inspect scrollHeight, clientHeight, and scrollTop; then set scrollTop on the node whose scrollbar moves.
The target is covered by another element
Cause: a sticky header, modal, cookie layer, or other overlay obscures part of the element. The screenshot records what is actually visible.
Free tools Windows power users keep installed
One-click scans. No signup required.
Fix: close the overlay, hide it in a test-only style, or capture after the UI reaches the intended state. Do not assume Playwright will paint covered pixels.
The locator detaches during capture
Cause: a React/Vue rerender replaced the node after the locator resolved.
Fix: wait for the stable state, use a locator rather than a stale ElementHandle, and retry only around a known transient update. Playwright’s ElementHandle documentation recommends locator-based APIs for this reason; see ElementHandle.
Rank #4
- 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
Scrolling does not load more items
Cause: the list may require pointer focus, a wheel event, an intersection observer, or time for a request to finish.
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 →Fix: hover and use page.mouse.wheel(), wait for a new row or request completion, and verify that the scroll container—not the page—is moving.
Images differ between runs
Cause: animations, fonts, late network responses, device scale, or changing data.
Fix: disable animations, wait for fonts and critical assets, fix viewport and scale, and freeze test data where possible.
Reliability and performance practices
- Resolve the locator by an accessible name or test ID so layout changes do not silently target the wrong node.
- Capture only the required panel instead of the entire page to reduce image size and rendering work.
- For multiple segments, use measured offsets and avoid repeated captures of the same final position.
- Wait on observable UI conditions rather than long fixed delays; keep a timeout for genuinely slow environments.
- Record the URL, viewport, device scale, scroll offset, and application revision alongside each artifact so failures are diagnosable.
- Use a consistent browser, fonts, timezone, and locale for visual regression suites.
Or skip the browser setup: ScreenshotNeo
ScreenshotNeo is a hosted website screenshot API and MCP server. It can capture a URL without you managing Playwright, browsers, or deployment. Its clean-shot pipeline accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers.
For a normal page capture, use the API documented at screenshotneo.com/docs/:
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)
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}`);
ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, custom JavaScript and CSS, click and wait actions, request blocking, cookies and headers, device presets, retina scale, PDF output, caching with your chosen TTL, bulk capture of up to 100 URLs per call, asynchronous jobs with signed webhooks, signed links, usage reporting, and an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
Best Value
The Free plan includes 1,000 shots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.
When Playwright is still the better choice
Use Playwright when you need browser-level assertions, authentication flows, application-specific scrolling logic, or a stitched artifact assembled from several internal positions. Use ScreenshotNeo when a URL-to-image request, clean output, failure-aware billing, or an AI-agent workflow is more important than maintaining browser infrastructure.
Frequently Asked Questions
Does fullPage: true capture a scrollable div’s entire contents?
No. It applies to page.screenshot() and captures the full page. A nested scrollable element still requires positioning and separate captures if you need all internal content.
Can Playwright automatically stitch a locator’s hidden scroll range?
The documented locator screenshot API captures the current view; the cited official pages do not document an option that stitches every internal scroll position. Capture segments and compose them when a single image is required.
Should I use an ElementHandle instead of a locator?
Prefer locators. They re-resolve the element and include actionability behavior, while stale handles are more likely to fail after framework rerenders.
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.




