ScreenshotNeo

BlogHow-to

How to capture a webpage screenshot at an exact viewport size

Set a browser’s viewport to exact width and height, choose CSS- or device-pixel output, and verify the saved image dimensions when they must match exactly.

By the ScreenshotNeo team4 October 20266 min read

To capture a webpage at an exact viewport size, set the browser viewport width and height before loading the page, then take a viewport screenshot. With Playwright, use page.setViewportSize({ width, height }) before page.goto(). Choose screenshot scale deliberately: CSS scale gives one output pixel per CSS pixel, while device scale can produce a larger bitmap. If the required deliverable is exactly W × H image pixels, inspect the saved file dimensions; viewport dimensions alone do not guarantee that bitmap size in every browser configuration.

1. Understand viewport size versus image size

The viewport is the browser’s visible page area, measured in CSS pixels. The screenshot file has pixel dimensions. Those dimensions can differ when device-pixel scaling is applied: for example, a device scale factor greater than one can make a CSS-sized viewport render to a larger pixel bitmap.

A viewport screenshot shows the visible area. A full-page screenshot extends to include the scrollable document, so its image height is not limited to the viewport height. If the requirement is a fixed-size image, use a viewport capture rather than full-page capture, and check the resulting file.

Set the viewport before navigation. This lets the page load with the intended dimensions; some sites do not expect a phone-sized viewport to change after loading.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewportSize({ width: 640, height: 480 });
    await page.goto('https://example.com', { waitUntil: 'load' });
    await page.screenshot({ path: 'screenshot.png', fullPage: false, scale: 'css' });
  } finally {
    await browser.close();
  }
})();

Install Playwright and its Chromium browser in your project before running the script. Save it as screenshot.js, then run node screenshot.js. The explicit scale: 'css' setting maps one output pixel to one CSS pixel. Use scale: 'device' when the desired output should follow device pixels; the image may then be larger.

Common adjustments

  • Change width and height to the target viewport in CSS pixels.
  • Keep fullPage: false for the visible viewport. Set it to true only when the entire scrollable page is wanted.
  • Use a consistent browser version and environment when comparing captures over time.
  • For a page that renders content after its load event, wait for a known selector or other application-specific readiness condition before taking the screenshot.

3. Capture with Chrome Headless from the command line

For a one-off capture, Chrome Headless accepts a screenshot flag and a requested window size:

chrome --headless --screenshot --window-size=412,892 https://developer.chrome.com/

The command writes a screenshot in the current working directory. Replace 412,892 with the requested width and height. Treat this as the requested browser capture size, then verify the file’s pixel dimensions if an exact bitmap size is mandatory. The command-line reference does not establish a universal guarantee for every platform, device scale factor, or browser configuration.

4. Verify the output dimensions

When a downstream system requires exactly W × H pixels, inspect the image after capture. If the dimensions differ, check whether device scaling is enabled or whether you captured the full page. Adjust the browser configuration or scale, recapture, and verify again. Do not assume that a correctly sized CSS viewport alone proves the saved bitmap’s dimensions.

5. Choose the right capture method

Need Method Key detail
One quick command-line image Chrome Headless with --screenshot --window-size=WIDTH,HEIGHT Check final bitmap dimensions for strict output requirements.
Repeatable scripted captures Playwright viewport plus screenshot Set viewport before navigation; choose CSS or device scale.
Custom browser-control workflow Chrome DevTools Protocol Page.captureScreenshot supports a clip; viewport metrics expose CSS layout and visual viewport information.

For a lower-level integration, consult the Chrome DevTools Protocol screenshot method and its viewport metrics. It provides more control but requires implementing protocol-level browser control.

6. Make captures reliable and comparable

  • Set dimensions before navigation. This avoids relying on a page adapting after it has already loaded.
  • Control scale. Select CSS or device scaling according to whether the target is CSS-pixel sizing or device-pixel output.
  • Keep the environment fixed. Browser rendering can vary with the host operating system, browser version, settings, hardware, power source, and headless mode, as Playwright documents in its visual comparisons guidance.
  • Wait for the content you need. A page can still be loading images or rendering application content after initial navigation. Wait for the relevant page condition rather than relying on an arbitrary short delay.
  • Validate the artifact. For strict pixel requirements, inspect image width and height and retain the capture settings alongside the output.

Repeated captures can also be affected by dynamic content, fonts, animations, network timing, and responsive breakpoints. When comparing images, keep those inputs stable where possible. If two captures have the same viewport but differ visually, compare their browser versions, device scale, operating systems, page state, and load timing before treating the difference as a code regression.

7. Troubleshooting

Symptom Likely cause What to do
Saved image is larger than the requested width or height Device-pixel scale produces more than one output pixel per CSS pixel. Use Playwright’s scale: 'css' for CSS-pixel output, then inspect the file dimensions.
Image height is much taller than the viewport Full-page capture is enabled or the selected capture mode includes the document. Use a viewport screenshot, such as fullPage: false in Playwright.
Layout does not match the intended mobile or desktop view Viewport was changed after page load, or the requested dimensions cross a responsive breakpoint. Set the intended size before navigation and confirm the target dimensions trigger the expected breakpoint.
Screenshot contains a loading state or missing images Capture ran before the page or its lazy content was ready. Wait for a relevant selector or a page-specific readiness signal before capture.
Same settings produce different pixels on another machine Rendering environment differs. Playwright notes that OS, browser version, settings, hardware, power source, and headless mode can affect rendering. Pin the browser version and standardize the environment and capture settings.
Chrome command does not save where expected The output is written to the current working directory, or the browser executable command differs on the system. Run from the intended directory and invoke the installed Chrome executable for that environment.

8. Performance, reliability, and cost

A local browser capture has no per-request screenshot API fee, but you operate the browser: installation, browser updates, compute, and page-load time are your responsibility. For a small number of screenshots, the command-line route is simple. For recurring jobs, a scripted browser workflow makes viewport, scale, waiting, and output paths explicit. Reusing a browser process for multiple pages can avoid repeated startup overhead, while keeping each page’s viewport and state controlled.

Reliability depends on the site and capture environment. Network failures, bot checks, consent overlays, dynamic content, or slow resources can change what appears in the file. Capturing the same URL and viewport does not ensure pixel-identical output across machines.

Or skip the browser setup

ScreenshotNeo is a website screenshot API: one GET request returns an image or PDF. Its clean-capture steps accept cookie and consent banners like a visitor and remove 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say the page verdict and whether the request was billed. It also provides an MCP server for AI agents, with screenshot, page-info, and PDF tools.

For a quick API call, see the ScreenshotNeo API documentation. This cURL example saves the screenshot response:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

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)

Node.js:

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 Bun.write('shot.webp', res);

ScreenshotNeo supports viewport dimensions, device presets, full-page capture, image formats, and additional capture controls. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account to get started.

FAQ

Should I use CSS pixels or device pixels?

Use CSS scale when the output should map one-to-one to the viewport’s CSS pixels. Choose device scale when you want device-pixel output and accept that the bitmap can be larger.

Does an exact viewport guarantee identical screenshots on every computer?

No. Browser and host rendering conditions can vary. Keep the environment and browser settings consistent for meaningful visual comparisons.

When should I use a full-page screenshot?

Use it when you need the whole scrollable document. For an image bounded by the visible viewport, capture only the viewport.