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 →Playwright has three different ways to influence screenshot height, and choosing the wrong one produces surprising results. Use clip.height to crop the image to an exact rectangle, change the viewport height to emulate a different browser window or responsive layout, and set fullPage: true to capture the entire scrollable document. These options solve different problems and are not interchangeable.
Choose the setting that matches your goal
| What you need | Use | What changes |
|---|---|---|
| A fixed-height image crop | clip: { x, y, width, height } |
The output is limited to the specified rectangle. |
| A different visible browser area or responsive breakpoint | page.setViewportSize({ width, height }) or a context viewport |
The page is laid out for a different emulated viewport. |
| Everything in the vertical document | fullPage: true |
Playwright captures the full scrollable page instead of only the visible viewport. |
If the image still has an unexpected pixel height, inspect scale. With scale: 'css', one output pixel corresponds to one CSS pixel. With scale: 'device', device pixels are used, so a high-DPI setting can make the file larger than the CSS dimensions.
Set an exact screenshot height with clip.height
Use clipping when the browser may display a normal page but your artifact must be a precise rectangle, such as a 1280×900 preview, a test fixture, or the top section of a landing page. The coordinates are measured from the page, and the clipping object requires x, y, width, and height.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({
path: 'top-900px.png',
clip: { x: 0, y: 0, width: 1280, height: 900 },
scale: 'css'
});
await browser.close();
The resulting file is 1280 CSS pixels wide and 900 CSS pixels high, provided the page and output format permit those dimensions. Clipping does not redesign the page or create additional content; it only bounds the captured region. To capture a lower section, increase y or derive the rectangle from an element.
#1 Best Overall
Clip an element’s box
For a component whose height is known only after layout, read its bounding box and pass the values to clip. Wait for the element first so a late-rendering component does not produce an empty or undersized image.
const card = page.locator('.pricing-card').first();
await card.waitFor({ state: 'visible' });
const box = await card.boundingBox();
if (!box) throw new Error('Pricing card has no layout box');
await page.screenshot({
path: 'pricing-card.png',
clip: box,
scale: 'css'
});
Use locator.screenshot() instead when you simply want the element itself; use page-level clipping when you need a custom rectangle around it.
Change the viewport height
Viewport sizing changes the emulated browser window. It can trigger responsive CSS, alter JavaScript measurements such as window.innerHeight, and change how fixed or sticky elements behave. Set it before navigation when the initial layout must be calculated at the target dimensions.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize({ width: 1280, height: 900 });
await page.goto('https://example.com');
await page.screenshot({ path: 'viewport-900px.png', scale: 'css' });
await browser.close();
A browser context is the better choice when every page in a test should share the same dimensions. Playwright’s context emulation defaults to 1280×720 unless you configure another viewport.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsRank #2
const context = await browser.newContext({
viewport: { width: 1280, height: 900 }
});
const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'context-size.png' });
Changing the viewport can expose site assumptions: menus may switch breakpoints, content may reflow, and a page that expects a conventional window size may behave differently. That is intended when you are testing responsive behavior; it is unnecessary when you only want to crop an image.
Capture the complete scrollable page
Set fullPage: true when the requirement is “everything from top to bottom.” Playwright captures the full scrollable page as if it had a very tall screen. The option is false by default.
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({
path: 'full-page.png',
fullPage: true,
scale: 'css'
});
Full-page capture is not a fixed-height crop. The resulting height depends on the document’s scrollable content. Lazy images, infinite lists, animations, and sticky headers can make the final result vary. Scroll or wait for the content your page loads, and disable animations when deterministic visual tests matter.
Combine viewport, full page, and clipping carefully
A common workflow is to set a stable viewport, navigate, wait for the meaningful content, and then choose either a full-page capture or a clip. Do not expect clip.height to override fullPage into a simple “full page but no taller than N pixels” mode; they express different capture models. If you need a maximum-height preview, use a clip. If you need all content, use full-page and post-process the image if a downstream system imposes a limit.
Rank #3
const page = await context.newPage();
await page.goto('https://example.com');
await page.locator('main').waitFor({ state: 'visible' });
// Exact preview:
await page.screenshot({
path: 'preview.png',
clip: { x: 0, y: 0, width: 1280, height: 900 }
});
// Separate complete-document artifact:
await page.screenshot({ path: 'document.png', fullPage: true });
Why output height can differ from what you expect
CSS pixels versus device pixels
Check scale first. Device scale can multiply output dimensions on high-DPI emulation. Standardize on scale: 'css' when image dimensions must match your CSS measurements.
Content changes after capture starts
Fonts, images, advertisements, and client-rendered components can alter document height. Wait for a selector, a stable application state, or an appropriate load condition before taking the shot. A network-idle wait is useful for pages that finish loading requests, but it is not a guarantee that an infinite feed has ended.
Sticky and fixed elements
These elements may appear in every section of a full-page image because Playwright stitches a tall capture. For a clean document image, hide or restyle the fixed element before capture, or capture a targeted clip instead.
Rank #4
Lazy-loaded content
Full-page capture may not represent content that only appears after user scrolling. Trigger the page’s loading behavior explicitly, wait for the newly inserted elements, and then capture. If the application intentionally uses infinite scrolling, define a stopping condition rather than waiting indefinitely.
Free tools Windows power users keep installed
One-click scans. No signup required.
Reusable helper for predictable heights
async function screenshotAtHeight(page, {
url,
width = 1280,
height = 900,
mode = 'clip',
path = 'shot.png'
}) {
await page.setViewportSize({ width, height });
await page.goto(url, { waitUntil: 'networkidle' });
if (mode === 'full') {
await page.screenshot({ path, fullPage: true, scale: 'css' });
return;
}
await page.screenshot({
path,
clip: { x: 0, y: 0, width, height },
scale: 'css'
});
}
Call the helper with mode: 'clip' for a fixed image or mode: 'full' for the entire document. Keep navigation, readiness checks, and dimensions in one place so visual tests use the same policy.
Troubleshooting screenshot-height problems
- The image is taller than requested: confirm that you used
clip, notfullPage, and setscale: 'css'. - The page layout changed unexpectedly: you changed the viewport, which affects responsive breakpoints. Use clipping if layout must remain unchanged.
- The bottom is blank: content may be lazy-loaded or still rendering. Wait for the relevant selector and application state before capture.
- Full-page output repeats a header: a fixed or sticky element is being included during stitching. Hide it temporarily or capture only the desired region.
clipthrows an error: verify that all four fields are present, numeric, non-negative where appropriate, and within the page’s available geometry.- Tests differ between machines: fix the context viewport, browser version, device scale, fonts, and animation state. Use CSS scale for stable pixel dimensions.
- The capture never settles: pages with continuous analytics or streaming requests may not reach network idle. Wait for a specific selector or use a bounded delay instead.
Performance, reliability, and cost considerations
A clip is generally the smallest operation because it limits the output area. Full-page captures require more rendering, memory, encoding, and often more time as document height grows. Very long pages can create large PNG files; JPEG or WebP may be more practical when lossless pixels are not required. For repeatable tests, keep the viewport and scale fixed, wait on explicit readiness signals, and avoid capturing while animations are active.
Best Value
Playwright itself does not charge per screenshot; your costs come from the browser infrastructure, storage, CI minutes, and any external capture service. Set timeouts and close pages, contexts, and browsers so failed jobs do not accumulate.
Or skip the browser setup
ScreenshotNeo provides a one-request screenshot API when you do not want to operate Playwright. The API can return PNG, JPEG, WebP, or PDF, and it supports viewport and full-page-oriented capture options, element selectors, custom CSS and JavaScript, waits, device presets, retina scale, and image resizing.
Recommended Free Tools
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for authentication and options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
Python and Node.js alternatives
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Frequently Asked Questions
Does changing viewport height crop the screenshot?
No. It changes the emulated browser layout. Use a screenshot clip when the output itself must have a fixed height.
Can Playwright capture only the visible viewport?
Yes. Omit fullPage and clip; the screenshot uses the current viewport.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →What does the default Playwright viewport size mean?
Browser-context emulation defaults to 1280×720 unless you configure another viewport.
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.

