Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Playwright’s page.screenshot() with a clip rectangle when you need only part of a page:
await page.screenshot({
path: 'clipped.png',
clip: { x: 100, y: 200, width: 600, height: 400 }
});
x and y are the rectangle’s top-left coordinates in CSS pixels; width and height define its size. For a single DOM node, locator.screenshot() is usually safer because Playwright calculates the element’s bounds for you.
Choose the right screenshot scope
Playwright offers four useful scopes. Pick the narrowest one that matches the artifact you need.
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 minuteWindows 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 reinstall| Need | API | Coordinate stability | Typical use |
|---|---|---|---|
| Current viewport | page.screenshot() with neither clip nor fullPage |
Depends on viewport and scroll position | What a user currently sees |
| Fixed rectangle | page.screenshot({ clip: { x, y, width, height } }) |
Explicit geometry; sensitive to layout changes | A region spanning several elements |
| One element | locator.screenshot() |
Tracks the element’s rendered bounds | Cards, headers, charts, buttons or components |
| Entire scrollable page | page.screenshot({ fullPage: true }) |
Page height and lazy content can change | Long-page documentation or audit artifacts |
fullPage defaults to false. Do not combine it with a clip when your intention is a simple, stable region: use one scope deliberately and verify the output.
#1 Best Overall
Clip a rectangle in JavaScript
This complete example launches Chromium, navigates to a page, waits for a visible target, and writes a PNG containing a 600-by-400 CSS-pixel rectangle.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({
path: 'clipped.png',
clip: { x: 100, y: 200, width: 600, height: 400 },
scale: 'css'
});
await browser.close();
The rectangle is measured against the page’s rendered coordinate system. A fixed clip therefore includes whatever happens to occupy those coordinates at capture time. If a cookie banner, responsive breakpoint, font swap or late-loading image changes the layout, the same numbers may capture a different area.
Validate geometry before capturing
Make the rectangle explicit and reject invalid dimensions before calling the API. This avoids confusing protocol errors and makes configuration mistakes obvious.
const clip = { x: 100, y: 200, width: 600, height: 400 };
for (const [name, value] of Object.entries(clip)) {
if (!Number.isFinite(value) || value < 0) {
throw new Error(`Invalid clip.${name}: ${value}`);
}
}
await page.screenshot({ path: 'clipped.png', clip });
Use non-negative values for all four fields. Keep the rectangle inside the intended viewport when you want predictable output; if it extends beyond the visible area, test the result on the browser version and page layout used in CI.
Screenshot one element without manual coordinates
For a single component, prefer a locator. Playwright scrolls the element into view when necessary and captures its rendered box, so a responsive layout can move the component without invalidating hard-coded coordinates.
const card = page.locator('.pricing-card').first();
await card.waitFor({ state: 'visible' });
await card.screenshot({ path: 'pricing-card.png', scale: 'css' });
You can target by role, label or test ID instead of a fragile class:
Rank #2
await page.getByRole('article', { name: 'Pro plan' })
.screenshot({ path: 'pro-plan.png' });
Element screenshots are still affected by animations, changing text, web fonts and content that has not finished loading. Wait for the state your test actually requires rather than relying only on a fixed sleep.
Capture a region that is below the fold
A clip uses page coordinates, while a viewport screenshot shows the current scroll position. If the rectangle is below the fold, scroll the relevant element into view first, or use an element screenshot.
const chart = page.locator('#revenue-chart');
await chart.scrollIntoViewIfNeeded();
await chart.screenshot({ path: 'chart.png' });
If you need the whole document rather than one region, use:
await page.screenshot({ path: 'full-page.png', fullPage: true });
Full-page capture can trigger additional layout and lazy-loading behavior. It is not a crop operation: it produces the full scrollable page.
Control pixel density and transparency
scale: 'css' versus scale: 'device'
scale: 'css' produces one output pixel per CSS pixel, making files smaller and dimensions easier to reason about. scale: 'device' uses device pixels, which can produce sharper but larger images on high-DPI contexts. Choose one consistently for visual regression baselines.
Free tools Windows power users keep installed
One-click scans. No signup required.
await page.screenshot({
path: 'css-scale.png',
clip: { x: 0, y: 0, width: 800, height: 500 },
scale: 'css'
});
await page.screenshot({
path: 'device-scale.png',
clip: { x: 0, y: 0, width: 800, height: 500 },
scale: 'device'
});
Transparent PNG output
omitBackground: true hides the default white background and allows transparency. Use PNG for this; JPEG cannot represent transparency.
await page.screenshot({
path: 'transparent.png',
clip: { x: 100, y: 100, width: 500, height: 300 },
omitBackground: true,
type: 'png'
});
Make clipping deterministic
Most incorrect crops are timing or layout problems, not screenshot API problems. Establish the same browser state before every capture.
- Set a known viewport. A responsive breakpoint can move the target or change its size.
- Navigate and wait for the required state. Use a meaningful locator, a navigation condition, or a controlled network-idle wait.
- Dismiss overlays when appropriate. Consent banners, chat launchers and newsletter dialogs can cover the rectangle.
- Wait for fonts and images. For critical visual work, wait for
document.fonts.readyand for specific images to complete. - Disable motion. Inject a test stylesheet that sets transitions and animations to zero when movement would change pixels.
- Use stable selectors for elements. Prefer roles or test IDs over generated class names.
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('#dashboard').waitFor({ state: 'visible' });
await page.evaluate(async () => {
await document.fonts.ready;
for (const image of document.images) {
if (!image.complete) await new Promise(resolve => {
image.addEventListener('load', resolve, { once: true });
image.addEventListener('error', resolve, { once: true });
});
}
});
await page.addStyleTag({ content: `
*, *::before, *::after {
animation: none !important;
transition: none !important;
caret-color: transparent !important;
}
` });
Use a fixed timezone, locale, color scheme and authentication state when those values affect the rendered page. Keep test data stable so text wrapping does not alter the clip.
Use clipping in visual regression tests
Playwright Test’s expect(page).toHaveScreenshot() accepts the same clipping and full-page concepts. It waits until two consecutive screenshots are identical before comparing the result, which helps settle minor rendering changes. This assertion is available in the Playwright test runner, not in arbitrary scripts.
import { test, expect } from '@playwright/test';
test('dashboard summary is stable', async ({ page }) => {
await page.goto('/dashboard');
await page.getByRole('heading', { name: 'Summary' }).waitFor();
await expect(page).toHaveScreenshot('summary.png', {
clip: { x: 80, y: 120, width: 900, height: 500 },
animations: 'disabled',
scale: 'css'
});
});
Keep clip geometry, browser version, viewport and test data stable. A rectangle is useful when you want to exclude timestamps, rotating banners or unrelated navigation, but it can hide a regression outside the selected area.
Python equivalent
The Python API uses the same fields. This synchronous example saves a clipped PNG.
Rank #4
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1280, "height": 900})
page.goto("https://example.com", wait_until="networkidle")
page.screenshot(
path="clipped.png",
clip={"x": 100, "y": 200, "width": 600, "height": 400},
scale="css",
)
browser.close()
For an element:
card = page.locator(".pricing-card").first
card.wait_for(state="visible")
card.screenshot(path="card.png")
Common failures and fixes
“Element is not visible” or a zero-size screenshot
The locator may match a hidden copy, the page may not have finished rendering, or a parent may have zero dimensions. Inspect the matched count, wait for visibility, and choose a visible locator. Scroll it into view before capture.
The crop contains the wrong content
Hard-coded coordinates describe a location, not a semantic element. Set the viewport, wait for fonts and data, and replace the rectangle with locator.screenshot() when the subject is one node.
The screenshot is clipped at the viewport edge
A viewport capture only contains what the browser can render in that view. Scroll the target into view, capture the element, or use fullPage: true when the entire document is required.
Images or fonts are missing
Wait for the specific resources, verify that the test environment can reach them, and avoid taking the screenshot immediately after navigation. A network-idle condition alone may not cover a font served from a separate connection or an image loaded by script.
Visual tests fail intermittently
Disable animations, freeze clocks and random data where possible, use a fixed viewport and device scale, and keep browser and operating-system dependencies consistent. Do not enlarge a diff threshold until you know which pixels are changing.
Transparent output appears white
Use PNG, set omitBackground: true, and ensure the page or target actually has transparent pixels. JPEG output cannot preserve an alpha channel.
Recommended Free Tools
Performance, files and operational trade-offs
- Element capture is usually smallest. It avoids storing unrelated page pixels and reduces visual-diff noise.
- Rectangles are efficient but maintenance-heavy. They are excellent for fixed dashboards or multi-element regions, but responsive redesigns require recalculating coordinates.
- Full-page capture costs more memory and time. Long pages, large images and high device scale increase output size.
- CSS scale is a practical default. Use device scale when consumers require physical high-density pixels.
- Choose output type deliberately. PNG supports lossless pixels and transparency; JPEG is smaller for photographic content but has no transparency.
For repeatable pipelines, name files with the test or URL, retain the browser version used to create baselines, and clean temporary screenshots after upload or comparison.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP or PDF, while its cleaning steps accept consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture. Each step can be turned off.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.
cURL
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(`${res.status} ${res.statusText}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));
See the ScreenshotNeo documentation for request options. Its 63 options include full-page and CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper settings, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration. AI agents can use the MCP tools take_screenshot, get_page_info and capture_pdf from Claude, Cursor or another MCP client.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute| Plan | Included shots | Price |
|---|---|---|
| Free | 1,000 per month | $0, no card |
| Starter | 3,000 | $5 |
| Growth | 15,000 | $15 |
| Pro | 60,000 | $39 |
| Scale | 250,000 | $99 |
| Business | 1,000,000 | $249 |
Yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to start with 1,000 screenshots a month and no card.
Frequently Asked Questions
Can a clip include several separate elements?
Yes. Define a rectangle that covers them all, or wrap the elements in a temporary container and capture that container when the layout permits.
Should I use a clip or locator screenshot for a component library?
Use a locator screenshot for one component; use a clip when the visual contract intentionally covers a fixed region containing multiple components.
Can Playwright return screenshot bytes instead of writing a file?
Yes. Omit the path and keep the returned buffer in memory for an upload, pixel comparison or other post-processing step.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →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.

