ScreenshotNeo

BlogHow-to

Puppeteer Screenshot Is Cut Off: Fix Viewport and Full-Page Sizing

Fix cut-off Puppeteer screenshots by setting the page viewport, choosing full-page or element capture, and checking for accidental clipping.

By the ScreenshotNeo team4 October 20267 min read

If a Puppeteer screenshot stops at the visible browser area, set the page viewport to the dimensions you need and pass fullPage: true when you want the entire document. The viewport controls the page’s visible dimensions; fullPage asks Puppeteer to capture beyond that visible area. Also check for a clip rectangle that may be cropping the result.

Choose the capture size you actually need

First decide whether you want a screenshot of the initial visible area, the whole document, a rectangle, or one element. These are different capture goals:

Goal Puppeteer setting What it controls
Set the visible page dimensions page.setViewport({ width, height }) The page viewport. Set it before navigation when possible.
Capture the whole document page.screenshot({ fullPage: true }) Requests a full-page screenshot. The default is false.
Capture a rectangle clip: { x, y, width, height } Limits the captured area to the specified region.
Capture one component elementHandle.screenshot() Captures the selected element, scrolling it into view if needed.
Size the browser window or headless screen Window management or screen configuration A separate sizing layer; it does not mean “capture the whole document.”

Puppeteer recommends setting the viewport before navigating: some sites respond to a viewport change as though the device changed, and the page may reload. Full-page capture does not require an oversized viewport; request it explicitly with fullPage: true.

Runnable fix: set the viewport and capture the full page

This CommonJS script uses Puppeteer, sets the viewport before opening the target URL, and saves a full-page PNG. Install Puppeteer in your project with npm install puppeteer, save the script as screenshot.cjs, then run node screenshot.cjs https://example.com.

const puppeteer = require('puppeteer');

async function main() {
  const url = process.argv[2];
  if (!url) {
    throw new Error('Usage: node screenshot.cjs https://example.com');
  }

  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 1000 });
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 });
    await page.screenshot({ path: 'page.png', fullPage: true });
  } finally {
    await browser.close();
  }
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Use a viewport matching the layout you intend to capture. A wide viewport may select a desktop layout; a narrow one may trigger a responsive layout. The height controls the initially visible area and can affect page behavior, while fullPage requests capture of the full document.

Capture only the visible viewport

For a screenshot of just the currently visible area, omit fullPage or set it to false:

await page.setViewport({ width: 1440, height: 1000 });
await page.goto(url);
await page.screenshot({ path: 'viewport.png' });

Capture one element

When the target is a component rather than the page, use an element screenshot. Puppeteer scrolls the element into view if needed, then captures it:

const card = await page.waitForSelector('.product-card');
await card.screenshot({ path: 'product-card.png' });

If the selector matches more than one element, select the intended one explicitly, for example with page.$$('.product-card') and an appropriate index. If the selector never appears, waitForSelector times out; check the selector and whether the content is rendered after navigation.

Find and remove accidental clipping

A clip option deliberately restricts the screenshot to a rectangle. Inspect its coordinates and dimensions if the output is unexpectedly cropped:

await page.screenshot({
  path: 'region.png',
  clip: { x: 0, y: 0, width: 900, height: 600 }
});

That example captures only the specified region. Remove clip for an ordinary full-page capture, or adjust the rectangle when a region is intended. Puppeteer’s captureBeyondViewport option controls whether a capture can extend beyond the viewport; its documented default depends on whether clip is supplied. Check the API reference for the version installed in your project before combining these options.

Viewport, window, screen, and document are different

A common source of confusion is changing one size while expecting another to change:

  • Page viewport: the CSS-visible area controlled by page.setViewport().
  • Full document: the page content beyond the viewport, requested with fullPage: true.
  • Browser content or window size: handled by Puppeteer’s window-management APIs. Its guidance includes Page.resize() for content size and Page.setViewport(null) to remove the default viewport constraint in that context.
  • Headless screen configuration: separate again. Puppeteer documents an 800×600 default screen in headless mode unless a relevant switch changes it.

Changing the browser window or headless screen does not replace the screenshot’s fullPage setting. Use the setting that corresponds to the size you are trying to control.

Practical diagnosis checklist

  1. Name the intended output. Choose viewport, full document, rectangle, or one element.
  2. Set the viewport before navigation. Pick the width and height that produce the layout you want.
  3. Use fullPage: true for the full document. A taller browser window by itself is not a full-page request.
  4. Inspect screenshot options. Remove unintended clip settings and check captureBeyondViewport if you need a clipped capture extending outside the viewport.
  5. Use an element screenshot for a component. Confirm the selector points to the intended element.
  6. Record versions when behavior differs. Note both Puppeteer and browser versions and compare against documentation for that installed version. Screenshot behavior has had version-specific fixes.

Troubleshooting

Symptom Likely cause Fix
Screenshot ends at the visible viewport fullPage was omitted, so its default is in effect. Pass { fullPage: true } to page.screenshot().
Right or bottom edge is missing A clip rectangle limits the capture, or its coordinates and dimensions are too small. Remove clip for a full-page screenshot, or correct x, y, width, and height.
Page uses the wrong responsive layout The viewport dimensions do not match the intended device layout, or the viewport changed after navigation. Set the intended viewport before goto() and capture again.
Changing viewport reloads or changes the page The site reacts to viewport or device-size changes. Set viewport dimensions before navigation and avoid changing them mid-capture unless required.
Element screenshot captures the wrong thing or times out The selector is wrong, matches an unintended element, or the element is not yet present. Verify the selector, wait for the intended element, and choose the matching element explicitly if there are several.
Window resize did not produce a full-page image Window or screen size was changed, but the screenshot still targets the viewport. Request fullPage: true for the document, or use window-management APIs only when you need to change content dimensions.
Installed behavior disagrees with current examples The runtime Puppeteer or browser version differs from the documentation version, or a version-specific issue applies. Record both versions, reduce the script to the relevant options, and consult the matching API docs and changelog.

Performance, reliability, and cost

Full-page captures produce more image content than viewport captures, so they can take longer and use more memory, especially for long documents. Prefer viewport or element capture when that is all you need. Set a navigation timeout appropriate for the target and choose a wait condition deliberately: networkidle2 can be useful for pages that settle after requests, but pages with continuing network activity may not reach it. If so, wait for a meaningful selector or use a bounded delay suited to the page.

For repeatable captures, keep viewport dimensions and capture options stable, set the viewport before navigation, and log the URL plus the Puppeteer and browser versions when a capture fails. Puppeteer is software you run in your own environment, so compute and browser-management costs depend on that environment and workload. This fix itself does not require a paid screenshot service.

Or skip the browser setup

If you need a screenshot without installing and managing a browser, ScreenshotNeo returns an image or PDF from one API request. Its documentation covers the API parameters, including viewport and full-page capture 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}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed, and response headers say whether a page was clean and billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Does fullPage: true change the page viewport?

No. It requests a full-document screenshot. Set the viewport separately to control the page’s layout dimensions.

Should I set the viewport before or after goto()?

Before navigation when possible. Puppeteer notes that viewport changes can affect sites that respond to device-size changes.

Can I use clip and fullPage together?

They express different capture constraints. Check the screenshot API documentation for your installed version, especially the interaction with captureBeyondViewport and its defaults.

Why is an element screenshot not the same as a full-page screenshot?

An element screenshot targets one selected node and scrolls it into view if needed. A full-page screenshot targets the document.

Official Puppeteer references