Puppeteer Screenshot Clip Option: Capture a Specific Region of a Web Page
Capture a precise page rectangle with Puppeteer’s clip option, or use an element handle when the element itself defines the bounds.
To capture a specific rectangular region in Puppeteer, pass clip to page.screenshot() with the rectangle’s x, y, width, and height. Use ElementHandle.screenshot() instead when the desired boundary is a particular DOM element and you want Puppeteer to scroll that element into view.
await page.screenshot({
path: 'region.png',
clip: { x: 100, y: 200, width: 400, height: 300 },
});
The numbers above are examples, not coordinates for a particular page. A clip is a rectangle, not a CSS selector: choose coordinates and dimensions for the page layout and viewport you intend to capture, then inspect the resulting image when layout or browser details matter.
1. Set up a runnable Puppeteer example
Install Puppeteer in a Node.js project. The puppeteer package downloads a compatible browser during installation; if you use puppeteer-core, provide a browser executable through its launch configuration.
npm install puppeteer
Save this as capture-region.mjs and run it with node capture-region.mjs:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage({
viewport: { width: 1280, height: 900 },
});
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({
path: 'region.png',
clip: { x: 100, y: 100, width: 600, height: 400 },
});
} finally {
await browser.close();
}
This example uses a fixed viewport and a fixed rectangle. Adjust both for your target page. Puppeteer documents path as optional: when supplied, the image type is inferred from its extension; without a path, the screenshot is not saved to disk.
2. Understand clip coordinates and options
clip is a ScreenshotClip region passed in the options object to Page.screenshot(). It extends BoundingBox with an optional scale, documented with a default of 1. The required rectangle fields are:
| Field | Meaning | Practical check |
|---|---|---|
x |
Horizontal position of the rectangle | Measure from the page’s capture coordinate origin; verify against your chosen viewport and layout. |
y |
Vertical position of the rectangle | Make sure the vertical position refers to the content you intend to capture. |
width |
Rectangle width | Use a positive size that covers the region needed. |
height |
Rectangle height | Use a positive size that covers the region needed. |
scale |
Optional clip scaling value | Defaults to 1 in the documented type; confirm output dimensions if changing it. |
With a clip supplied, the current Puppeteer ScreenshotOptions reference documents captureBeyondViewport as defaulting to true; without a clip, it defaults to false. Set options deliberately if your capture depends on content beyond the viewport, and review output on the Puppeteer version and browser protocol you deploy.
For an arbitrary crop, define the rectangle directly. The rectangle does not follow a DOM element if the page shifts, reflows, or changes its content. If the region should track an element’s rendered bounds, use an element handle instead.
3. Capture an element by its rendered bounds
Use a selector to get an element handle, then call its screenshot() method. Puppeteer’s guide says this method scrolls the element into view if needed before capturing it. It throws if the element is detached from the DOM.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const card = await page.waitForSelector('main article');
if (!card) throw new Error('Target element was not found');
await card.screenshot({ path: 'article.png' });
} finally {
await browser.close();
}
Choose between the two approaches based on what defines the boundary:
| Need | Use |
|---|---|
| A fixed rectangular crop at known coordinates | page.screenshot({ clip: { x, y, width, height } }) |
| The rendered bounds of a DOM element | elementHandle.screenshot() |
| An element may be offscreen and should be brought into view first | elementHandle.screenshot(); the documented method scrolls it into view if needed |
| The crop must remain at the same coordinates regardless of DOM selection | Use clip, while accounting for page layout and viewport changes |
4. Choose load timing and capture conditions
The screenshot call captures the page state that exists when it runs. Pick a navigation wait condition that matches the page: domcontentloaded waits for the initial document parse, while pages that render asynchronously may need a selector wait or an intentional delay before taking the screenshot.
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('main .report');
await page.screenshot({
path: 'report-section.png',
clip: { x: 80, y: 160, width: 720, height: 480 },
});
Choose a stable viewport before measuring a fixed clip. Responsive breakpoints, dynamic content, font loading, and image loading can move the target relative to fixed coordinates. For a capture that must follow content, prefer the element-handle route and wait until that element is present and rendered.
5. Protocol and version considerations
Puppeteer’s WebDriver BiDi support page lists clip, encoding, and fullPage among supported Page.screenshot parameters. That page documents a subset of parameters, so do not assume every screenshot option behaves identically across all protocols or browser configurations. Check the documentation for the Puppeteer version and protocol you actually use.
The API references used here identify ScreenshotOptions and the screenshot guide as version 25.12.0, while the ScreenshotClip type reference is version 25.10.0. Consult the versioned API pages when upgrading or resolving behavior differences.
6. Troubleshooting common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| The image shows the wrong part of the page | The rectangle coordinates were chosen for a different layout or viewport. | Set the viewport explicitly, re-check the target’s position, and adjust x and y. |
| The crop misses content or has the wrong size | width or height does not match the intended rectangle. |
Review the dimensions and inspect the saved image; use an element screenshot if the DOM element should define the bounds. |
| The captured region is blank or incomplete | The screenshot ran before async content appeared or before the target rendered. | Wait for a meaningful selector or page-specific ready state before capturing. |
| An element screenshot fails because the node is detached | The page replaced or removed the element after lookup. | Wait for the page’s update to finish, then query the element again and capture the fresh handle. |
| Capture behavior differs under BiDi | The selected protocol documents support for only a subset of screenshot parameters. | Check the BiDi support reference for the parameter in question and verify the behavior in your chosen setup. |
| No screenshot file appears | No path was passed, so Puppeteer returned screenshot data without saving it to disk. |
Supply a filename such as region.png or handle the returned data in your program. |
7. Performance, reliability, and cost
A screenshot requires browser navigation and rendering, so make the capture reproducible by fixing the viewport, waiting for the exact content needed, and closing the browser in a finally block. Reuse a browser process for multiple captures when appropriate, while creating a fresh page or context for jobs that need isolation. A rectangle can keep the output focused, but it does not eliminate the cost of loading and rendering the page.
Puppeteer is browser automation software; there is no screenshot API charge from Puppeteer itself. Your costs depend on where and how you run the browser, including compute and network use. This article makes no performance benchmark claims.
8. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request can return an image or PDF; its API parameters include options used by other screenshot APIs, which makes switching straightforward. See the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
Cookie banners are accepted like a visitor and more than 60 known consent platforms are removed before the shot; newsletter popups and chat widgets are removed too, and each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and billing status. An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
9. FAQ
Can I use a CSS selector inside clip?
No. clip describes a rectangular region with numeric coordinates and dimensions. Use an element handle’s screenshot() method when a selector should identify the capture target.
Does clip automatically scroll to a region?
A clip is a coordinate rectangle and does not select or scroll to a DOM element. For an element target, Puppeteer documents that ElementHandle.screenshot() scrolls the element into view if needed.
Can I use clip with WebDriver BiDi?
Puppeteer’s BiDi support page lists clip among supported screenshot parameters. Check that page for the supported subset and your exact setup before relying on other screenshot options.


