ScreenshotNeo

BlogHow-to

How to Resize a Page with Puppeteer

Use page.setViewport() to change responsive page dimensions. Use Puppeteer’s experimental page.resize() when you need to size the browser window’s content area.

By the ScreenshotNeo team4 October 20267 min read

To change the dimensions Puppeteer uses to render a page, call await page.setViewport({ width, height }). Set it before navigating when possible. If you mean resizing the browser window until its content area has particular dimensions, clear the default viewport with await page.setViewport(null), then use await page.resize({ contentWidth, contentHeight }). The latter is experimental, so check that your installed Puppeteer version and runtime support it.

Choose what you need to resize

Goal Use What changes
Test a responsive layout or capture a page at specific dimensions page.setViewport({ width, height }) The page viewport used for rendering
Set the browser window’s content area to specific dimensions page.setViewport(null), then page.resize({ contentWidth, contentHeight }) The browser window, with the requested size for page content
Capture the whole document page.screenshot({ fullPage: true }) The screenshot’s capture area; it does not require changing the viewport

These operations are related but not interchangeable. A viewport setting is not a measurement of the live browser window, and a full-page screenshot is not a window resize.

Set the page viewport

For responsive testing and most screenshot jobs, set the viewport before you navigate. Puppeteer’s documentation warns that some sites do not expect phones to change size, and recommends setting the viewport before navigation. Changes to isMobile or hasTouch can reload the page.

import puppeteer from 'puppeteer';

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

  await page.setViewport({
    width: 640,
    height: 480,
    deviceScaleFactor: 1,
  });

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

Save this as an ES module, for example resize.mjs, in a project where Puppeteer is installed, then run node resize.mjs. The viewport object requires width and height; deviceScaleFactor controls the device pixel ratio used for rendering. Await setViewport() before navigating or capturing.

Change the viewport after navigation

You can change the viewport on an already loaded page. This is useful for checking a breakpoint, but responsive scripts may run again, and some mobile or touch changes can cause a reload.

await page.goto('https://example.com');
await page.setViewport({ width: 390, height: 844 });

// Let the page respond to the changed viewport before inspecting or capturing.
await page.screenshot({ path: 'page-mobile.png' });

Resize the browser window’s content area

If you need the browser window itself to fit a target content size, Puppeteer’s window-management guide uses setViewport(null) to remove the default viewport constraint, then calls page.resize(). The resize is asynchronous: wait for the browser’s resize event before reading the resulting dimensions.

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  args: ['--screen-info={800x600}'],
});
try {
  const page = (await browser.pages())[0];

  // Remove the default viewport constraint before resizing the window.
  await page.setViewport(null);

  const resized = page.evaluate(() => new Promise(resolve => {
    window.addEventListener('resize', resolve, { once: true });
  }));

  await page.resize({ contentWidth: 600, contentHeight: 400 });
  await resized;

  const dimensions = await page.evaluate(() => ({
    innerWidth: window.innerWidth,
    innerHeight: window.innerHeight,
    outerWidth: window.outerWidth,
    outerHeight: window.outerHeight,
  }));
  console.log(dimensions);
} finally {
  await browser.close();
}

This pattern uses puppeteer-core, which does not bundle a browser. Configure its executable according to your environment if one is not already available. The guide’s example reports an inner size of 600×400 and an outer size of 600×487; outer dimensions depend on the environment and browser chrome, so do not treat those numbers as universal.

Page.resize is marked experimental in the API reference. Confirm support in the version you have installed before depending on it. This example also uses --screen-info, which applies to headless Chrome; headful Chrome uses the platform’s physical screens.

Use device emulation when you mean a device

A viewport of phone-like dimensions does not, by itself, emulate a phone’s user agent. If you need a device preset, use Puppeteer’s device emulation, which sets both the user agent and viewport. Emulate before navigation when the site may behave differently after detecting a phone.

import puppeteer from 'puppeteer';
import { devices } from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.emulate(devices['iPhone 13']);
  await page.goto('https://example.com');
  await page.screenshot({ path: 'page-device.png' });
} finally {
  await browser.close();
}

Use a device entry available in the Puppeteer version you installed. If you only need responsive breakpoints, setViewport() is usually enough; use device emulation when the user agent and device metrics matter too.

Measure the resulting size correctly

page.viewport() returns the configured viewport or the connection’s default viewport. It does not verify the live page dimensions. After a window resize, wait for the resize event and inspect browser values such as window.innerWidth and window.innerHeight.

const liveSize = await page.evaluate(() => ({
  innerWidth: window.innerWidth,
  innerHeight: window.innerHeight,
  devicePixelRatio: window.devicePixelRatio,
}));
console.log(liveSize);

For a viewport-only change, the configured settings are useful to inspect:

console.log(page.viewport());

Do not use that value as proof that a window resize completed. For a window resize, measure the live page after the resize event.

Capture a screenshot at the size you need

For a viewport-sized screenshot, set the viewport and capture normally. To capture the entire document, pass fullPage: true; you do not need to enlarge the viewport first. Screenshot clipping and capture beyond the viewport are separate screenshot controls.

await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://example.com');
await page.screenshot({ path: 'full-page.png', fullPage: true });

Common problems and fixes

Symptom Likely cause Fix
The page still looks like the old size The viewport was set after navigation, or the page has not responded to the change yet. Set it before goto() when possible. After a later change, wait for rendering or the relevant page condition before capture.
The page reloads after a viewport change A change to mobile or touch metrics can trigger a reload. Set mobile and touch settings before navigation, or wait for navigation to finish again after changing them.
page.resize is not a function or the call fails The installed Puppeteer version or runtime may not support this experimental API. Check the installed version and its API reference. If you only need page rendering dimensions, use setViewport().
The measured size differs from the requested size You measured before the asynchronous resize completed, or compared content dimensions with outer window dimensions. Wait for the page’s resize event. Compare innerWidth/innerHeight to the requested content size; outer dimensions include browser chrome.
page.viewport() disagrees with the visible page It reports configured settings rather than checking actual live dimensions. Read window.innerWidth and window.innerHeight in the page.
The window-resize sample cannot find a browser puppeteer-core expects a browser supplied by the runtime. Provide a valid browser executable/configuration for your environment, or use the full puppeteer package.
The requested screen geometry has no effect --screen-info is for headless Chrome; headful Chrome uses physical platform screens. Use headless mode with the documented screen configuration, or account for the actual display environment.

Performance, reliability, and cost

  • Set dimensions once, early. Configure the viewport before navigation to avoid extra page work and reduce the chance of a reload when mobile metrics change.
  • Wait for the condition you need. A resize event confirms the window resize was observed; it does not guarantee every application animation or network request has finished. Wait for a page-specific selector or state before capturing when necessary.
  • Keep screenshots purposeful. Use a viewport capture for a specific layout and fullPage: true for the full document. A larger page or full-page capture can require more rendering and image data.
  • Account for environment differences. Browser chrome, headless settings, screen geometry, and installed Puppeteer versions affect window resizing. Prefer viewport sizing when repeatable page dimensions are the real requirement.
  • Browser cost is operational. Self-hosted Puppeteer requires a browser runtime and its associated compute and maintenance. The exact cost depends on where and how often it runs; the documentation provides no universal benchmark.

Or skip the browser setup

If your goal is to get an image of a web page at a chosen URL, ScreenshotNeo is a website screenshot API and MCP server. It returns a PNG, JPEG, WebP, or PDF from one GET request. See the API documentation for the available parameters, including viewport options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
  • Cookie banners are accepted and removed, and known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off.
  • Bot checks, blank pages, timeouts, and failed loads are not billed. Cache hits are not billed either, and response headers indicate the page verdict and billing status.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients.
  • The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.

Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

FAQ

Does changing the viewport resize the browser window?

No. setViewport() changes page rendering dimensions. Use the experimental window-resize API when you specifically need to size the browser window’s content area.

Can I take a full-page screenshot without changing the viewport?

Yes. Use page.screenshot({ fullPage: true }).

Should I use a viewport or a device preset?

Use a viewport for dimensions and responsive layout checks. Use device emulation when the user agent and device metrics also need to match a preset.

Why does my outer window size not match the requested content size?

The requested size is for page content. The outer dimensions include browser chrome and vary by environment.

Sources