How to Resize a Puppeteer Page Before Taking a Screenshot
Set Puppeteer's viewport before navigation to control the page layout in your screenshot. Learn how viewport size, full-page capture, and device scale factor work together.
Use await page.setViewport({ width, height, deviceScaleFactor }) before taking the screenshot. For responsive pages, set it before page.goto() so the site loads into the layout you intend to capture. Viewport size controls the visible browser area; it does not make the screenshot cover the entire document.
const page = await browser.newPage();
await page.setViewport({
width: 1280,
height: 800,
deviceScaleFactor: 1,
});
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
Replace the dimensions with your target viewport. The values above are examples, not required settings. See Puppeteer’s Page.setViewport() API reference and screenshot guide.
1. Set the viewport before navigation
page.setViewport() resizes the page viewport and returns a promise, so await it. Setting it before navigation lets responsive websites choose their layout using the intended width and height from the start. Puppeteer notes that some sites do not expect phone-sized dimensions.
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setViewport({ width: 390, height: 844, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'mobile.png' });
} finally {
await browser.close();
}
This is a complete Node.js example when run in a project with Puppeteer installed and imported. It uses a mobile-sized custom viewport, but does not enable mobile-device emulation; those are separate choices.
2. Choose the right viewport options
| Option | What it controls | When to set it |
|---|---|---|
width |
Viewport width in CSS pixels. | Set the target responsive breakpoint or layout width. |
height |
Viewport height in CSS pixels. | Set the visible vertical area for a viewport screenshot. |
deviceScaleFactor |
Device pixel ratio used for rendering. | Choose a higher-resolution raster output when needed. Puppeteer’s documented example uses 1. |
isMobile and hasTouch |
Mobile and touch behavior in viewport configuration. | Use when the target requires those behaviors; Puppeteer says applying these settings may reload the page. |
Use positive integer width and height values that match the layout you want. A device scale factor affects output pixel density, not the CSS layout width. If you need a known device profile, use Puppeteer’s device emulation instead of manually approximating it. Its Page API reference documents emulate(device), which sets a user agent and viewport; emulate before navigation.
3. Viewport, full-page, and clipped screenshots
These options solve different problems:
- Viewport screenshot: capture what is visible in the configured viewport. This is the default.
- Full-page screenshot: capture the page beyond the viewport with
fullPage: true. - Clipped screenshot: capture a specified rectangle with
clip.
// Visible viewport only
await page.screenshot({ path: 'viewport.png' });
// Entire page, beyond the viewport
await page.screenshot({ path: 'full-page.png', fullPage: true });
// A rectangular region in page coordinates
await page.screenshot({
path: 'region.png',
clip: { x: 0, y: 0, width: 640, height: 400 },
});
Changing the viewport does not imply a full-page capture. The documented screenshot options include fullPage, clip, and captureBeyondViewport; the documented default for captureBeyondViewport depends on whether a clip is supplied. See Puppeteer’s ScreenshotOptions reference for current option details.
4. Resize after navigation when necessary
You can change the viewport after navigation, but a responsive site may need time to recalculate its layout. If you change viewport settings involving isMobile or hasTouch, Puppeteer may reload the page to apply them. Prefer the pre-navigation setup when capturing a particular responsive layout.
await page.goto('https://example.com');
await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 1 });
await page.screenshot({ path: 'wide.png' });
5. Troubleshoot common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| The screenshot still looks like the old layout. | The viewport was set after navigation, or the site has not finished responding to the resize. | Set the viewport before goto(), then wait for the page’s relevant content before capturing. |
| The image is only as tall as the browser viewport. | fullPage defaults to false. |
Pass { fullPage: true } for a full-page capture. |
| The capture includes the wrong area. | A clip rectangle is absent or its coordinates and dimensions do not describe the desired region. | Set clip with the intended x, y, width, and height. |
| The page reloads after setting the viewport. | Mobile or touch-related viewport properties can trigger a reload in some cases. | Set those options before navigation and wait for navigation and content to settle before capture. |
| The page has a desktop user agent but a narrow layout, or vice versa. | A custom viewport changes dimensions but is not the same as emulating a device profile. | Use page.emulate(device) before navigation when you need that device’s user agent and viewport together. |
| The screenshot is not as sharp as expected. | The configured device scale factor is lower than the desired pixel density. | Set an appropriate deviceScaleFactor and account for the larger output image. |
6. Performance, reliability, and output size
Choose the smallest viewport and capture region that meet the requirement. Full-page captures and higher device scale factors can produce larger images, which take more memory to encode and more time and bandwidth to save or transfer. Set the viewport before navigation to avoid capturing an unintended responsive layout, and wait for the specific content your screenshot depends on rather than relying on an arbitrary delay where possible.
For repeatable captures, keep the viewport dimensions, device scale factor, device emulation choice, and screenshot options fixed between runs. Dynamic page content can still vary independently of viewport configuration.
7. Or skip the browser setup
If you need a screenshot without managing Puppeteer and a browser, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. 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 image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for free and get 1,000 screenshots a month with no card.
FAQ
Does changing the viewport make a full-page screenshot?
No. Set the viewport with setViewport(); pass fullPage: true separately when you want the whole page.
Should I use a custom viewport or emulate a device?
Use a custom viewport for chosen dimensions. Use device emulation when you need a known device profile, including its user agent and viewport.
What values should I use for width and height?
Use the CSS-pixel dimensions that match the responsive layout or visible capture area you need. There is no required universal size.


