ScreenshotNeo

BlogHow-to

How to Set a Custom Viewport Size for Puppeteer Screenshots

Set Puppeteer’s viewport before navigation, then capture the visible area or request a full-page image. Learn device emulation, sizing options, and common fixes.

By the ScreenshotNeo team4 October 20266 min read

Use await page.setViewport({ width, height }) before navigating, then take the screenshot with page.screenshot(). The viewport sets the page’s visible layout dimensions; it does not make the screenshot full-page. For a whole-document image, pass fullPage: true separately.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();

  await page.setViewport({
    width: 1280,
    height: 800,
    deviceScaleFactor: 1,
  });

  await page.goto('https://example.com', { waitUntil: 'networkidle2' });
  await page.screenshot({ path: 'screenshot.png' });
} finally {
  await browser.close();
}

Set width and height in CSS pixels. The example also sets deviceScaleFactor, which controls the output pixel scale. Await setViewport() before navigation or capture. Puppeteer recommends setting the viewport before navigation because some sites do not expect their layout to change from phone-sized dimensions after loading. [Puppeteer Page.setViewport reference]

1. Set the viewport before navigation

A viewport belongs to a page, so pages in the same browser can use different dimensions. Set it on the page you will capture. The setViewport() call is asynchronous and returns a promise; await it so navigation and screenshot capture use the requested dimensions.

const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com');
await page.screenshot({ path: 'desktop.png' });

If you change the viewport after the page loads, the site may reflow. For mobile or touch settings, Puppeteer notes that a viewport change can trigger a reload in some cases. Set the final configuration before navigation when you can. [Puppeteer Page.setViewport reference]

2. Understand viewport size versus screenshot size

The viewport controls the page’s layout window. Screenshot options control which part of the page is saved. These are separate decisions:

Goal Setting Effect
Set the visible layout dimensions page.setViewport({width, height}) Configures the page viewport in CSS pixels.
Capture the visible viewport page.screenshot() Captures the current viewport by default.
Capture the whole page page.screenshot({fullPage: true}) Requests a full-page screenshot; fullPage defaults to false.
Capture a particular region page.screenshot({clip: {x, y, width, height}}) Captures the specified rectangle.
// Capture the entire page, which may be taller than the viewport.
await page.screenshot({ path: 'full-page.png', fullPage: true });

// Capture a region in page coordinates.
await page.screenshot({
  path: 'region.png',
  clip: { x: 100, y: 120, width: 600, height: 400 },
});

captureBeyondViewport controls capture outside the viewport. Its documented default is false when there is no clip and true when a clip is supplied. Prefer the explicit fullPage option when you mean the whole page, and use clip when you mean a specific rectangle. See Puppeteer’s ScreenshotOptions reference.

3. Choose dimensions and device scale

For a responsive layout check, choose the width and height that represent the browser viewport you want to reproduce. The CSS viewport and saved image’s pixel dimensions can differ when you set a device scale factor above one. For example, a scale factor of 2 creates a higher-density image for the same CSS-sized viewport. Use scale 1 when you want output pixels to correspond closely to CSS pixels; use a higher value when you need a denser raster image.

await page.setViewport({
  width: 390,
  height: 844,
  deviceScaleFactor: 2,
});

Keep the capture target in mind: increasing the viewport height changes the visible page area, while increasing device scale affects raster density and output size. Neither option is a substitute for fullPage: true.

4. Emulate a named device

For a device profile, use KnownDevices and page.emulate(). Emulation applies a device’s viewport and user agent together. Apply it before navigation so the site loads under the intended device settings. Confirm the device name exists in the Puppeteer version installed in your project; the current documentation example uses iPhone 17 Pro. [Puppeteer Page.emulate reference]

import puppeteer, { KnownDevices } from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.emulate(KnownDevices['iPhone 17 Pro']);
  await page.goto('https://example.com');
  await page.screenshot({ path: 'mobile.png' });
} finally {
  await browser.close();
}

Use manual setViewport() when you need a specific width and height independent of a named device. Use emulate() when you want the device profile’s viewport and user agent together.

5. Resize the browser content area only when needed

A page viewport is not the same thing as the browser window’s content area. If you specifically need to size the browser content area, Puppeteer’s window-management guide shows removing the default viewport with page.setViewport(null), then calling page.resize({contentWidth, contentHeight}) and waiting for the asynchronous resize event. The Page reference labels resize() experimental, so use it only for this distinct window-management use case. [Puppeteer window management guide] [Puppeteer Page.resize reference]

6. Wait for the page you intend to capture

Viewport configuration does not guarantee that the page content is ready. Choose a navigation wait condition that fits the site, then add an explicit wait for a selector or application state if needed. networkidle2 can be useful for pages whose relevant content loads after initial navigation, but pages with ongoing network activity may never become idle. Do not assume that the viewport caused missing content until you have checked readiness and any lazy-loaded sections.

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('main');
await page.screenshot({ path: 'ready.png' });

For a full-page screenshot with lazy-loaded images, scrolling through the document before capture can prompt content to load. Whether this is necessary depends on the site’s loading behavior.

7. Common problems and fixes

Symptom Likely cause Fix
Screenshot has the default size The viewport call was omitted, not awaited, or applied to a different page. Call and await page.setViewport() on the same page before navigation.
Page looks mobile or desktop unexpectedly The configured CSS viewport width triggers responsive breakpoints, or a device profile set a different user agent and viewport. Check the dimensions and whether the page uses emulate(). Use manual dimensions if you need precise sizing.
Screenshot is only as tall as the viewport Viewport dimensions set the layout window, not the capture extent. Pass fullPage: true for the whole page, or specify clip for a region.
Content is cut off or missing The page was captured before content appeared, or content is lazy-loaded below the fold. Wait for a meaningful selector or state; scroll to load lazy content when required, then capture.
Changing viewport reloads the page Some mobile or touch configurations can trigger a reload. Set viewport or device emulation before navigation.
KnownDevices[name] is undefined The chosen device is not included in the installed Puppeteer version. Check the supported names for that version or configure dimensions manually.
Unexpectedly large image file The viewport is large, the scale factor is high, or the capture is full-page. Reduce dimensions or scale, avoid full-page capture when unnecessary, or choose a compressed output format and quality supported by screenshot options.

8. Performance, reliability, and cost

Large viewports, high device scale factors, and full-page captures produce more pixels and can take more time and memory to render and encode. Capture only the region and resolution your task needs. Reuse a browser for multiple pages when appropriate, but configure each page’s viewport explicitly so one capture’s settings do not become an assumption for another.

For repeatable results, set viewport or device emulation before navigation, wait for a page-specific ready condition, and specify capture options such as full-page or clipping explicitly. Puppeteer’s documentation examples define the API behavior; they do not establish a universal capture-time guarantee. Browser and page behavior also depends on the target site and content.

Running Puppeteer requires managing a browser process and its runtime environment. If you need screenshots without setting up browser capture infrastructure, ScreenshotNeo provides a one-request screenshot API. It supports viewport dimensions, device presets, retina scale, full-page capture, and other capture options; see the ScreenshotNeo API documentation.

9. Or skip the browser setup

ScreenshotNeo returns an image or PDF from a single GET request. Here is a runnable cURL example for a 1280 by 800 viewport:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  -d width=1280 \
  -d height=800 \
  -o shot.webp

See the ScreenshotNeo docs for request parameters and examples. Cookie banners, popups, and chat widgets are removed before the shot, and each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed; response headers identify the page verdict and billing status. An 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 free for ScreenshotNeo.

FAQ

Does setViewport() resize my monitor or browser window?

No. It configures the page viewport. Browser content-area resizing is a separate, experimental operation.

Can each tab have its own viewport?

Yes. Set the viewport on each Puppeteer Page you plan to capture.

Does a custom viewport capture the whole page?

No. Use fullPage: true for a full-page capture.

Where should I check the available options?

Consult the Puppeteer API reference for your installed version: setViewport, screenshot options, and emulation.

References