How to set screenshot dimensions for a recurring website capture
Set a stable CSS viewport, capture extent, and output scale for recurring website screenshots. See runnable Playwright, Puppeteer, and shot-scraper examples.
For recurring website screenshots, set a fixed browser viewport width and height in CSS pixels before navigating, then choose whether each run captures the visible viewport or the full scrollable page. Set output scale separately: a scale factor can multiply bitmap dimensions without changing the page’s CSS layout. Keep these settings and the browser configuration stable across runs.
This guide shows how to do that with Playwright, Puppeteer, and shot-scraper, how to schedule repeatable captures, and how to diagnose common differences.
1. Understand which dimensions you are setting
“Screenshot dimensions” can mean the size of the browser viewport, the extent of the page included, or the number of pixels in the saved image. These settings interact, but they are not interchangeable.
| Setting | What it controls | Example |
|---|---|---|
| Viewport width and height | The browser’s CSS-pixel viewing area. Responsive layouts may change when these values change. | 1280 × 800 CSS pixels |
| Capture extent | Whether the screenshot covers the current viewport, the full page, or a selected region or element. | Viewport or full page |
| Output scale | How many bitmap pixels represent each CSS pixel in the output image. | Scale factor 2 |
| Clip or element bounds | A specific rectangle or element to capture, where supported by the tool. | A chart or header |
For example, a 390 × 844 CSS-pixel viewport captured at scale factor 3 produces a 1170 × 2532 pixel image. The CSS viewport remains 390 × 844, so the site still lays out as a narrow mobile view. The larger output contains more bitmap pixels; it does not turn that mobile layout into a desktop one.
2. Choose a stable capture configuration
- Pick the layout you need. Use a viewport width and height that represent the intended desktop, tablet, or mobile state. The width often determines responsive breakpoints; height determines how much of the page appears in a viewport screenshot.
- Choose the capture extent. Use a viewport capture for a fixed visible region. Use full-page capture when the complete scrollable document is needed. If you need just one component or rectangle, use an element or clip capture where available.
- Choose output scale. Use scale 1 for an image whose pixel dimensions match the CSS viewport. Use a higher scale when you need a denser image, accepting larger files and more capture or transfer work.
- Set the values before navigation. Responsive sites can select layout and resources during load. Configure the viewport before opening the target page rather than resizing after it loads.
- Save the configuration centrally. Put dimensions, scale, full-page choice, browser version, and other relevant capture options in the same script or configuration used by every scheduled run.
Keep per-site dimensions when the pages have different comparison targets. Consistency means reusing the intended settings for each recurring capture, not forcing every site into one viewport.
3. Playwright: set the viewport before navigation
Playwright’s page viewport size is configured in CSS pixels. This runnable Node.js example sets it before navigation, takes a viewport screenshot by default, and can be switched to full-page capture.
import { chromium } from 'playwright';
const target = process.env.TARGET_URL ?? 'https://example.com';
const width = Number(process.env.VIEWPORT_WIDTH ?? 1280);
const height = Number(process.env.VIEWPORT_HEIGHT ?? 800);
const fullPage = process.env.FULL_PAGE === 'true';
if (!Number.isInteger(width) || width <= 0 ||
!Number.isInteger(height) || height <= 0) {
throw new Error('VIEWPORT_WIDTH and VIEWPORT_HEIGHT must be positive integers');
}
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({ viewport: { width, height } });
await page.goto(target, { waitUntil: 'networkidle', timeout: 60_000 });
await page.screenshot({ path: 'capture.png', fullPage, animations: 'disabled' });
} finally {
await browser.close();
}
Install the package and browser with npm install playwright and npx playwright install chromium. Run with TARGET_URL=https://example.com VIEWPORT_WIDTH=1440 VIEWPORT_HEIGHT=900 node capture.mjs; add FULL_PAGE=true to capture the full document. The example disables animations to reduce one source of run-to-run variation. Choose a wait condition appropriate for the target: pages with persistent network activity may never reach network idle, so a selector or explicit delay can be more appropriate.
Playwright also supports device scale factor through browser context options. To request a denser image while preserving the CSS viewport, create a context with { viewport: { width, height }, deviceScaleFactor: 2 } and use its page. Check the installed Playwright version and the screenshot options for your desired output format and scale behavior. Playwright recommends setting the viewport before navigation because many sites do not expect a phone’s viewport to change after load. Playwright Page API.
4. Puppeteer: set viewport and capture extent
Puppeteer provides viewport configuration on the page and a separate fullPage screenshot option. This complete Node.js example uses a fixed viewport before navigation.
import puppeteer from 'puppeteer';
const target = process.env.TARGET_URL ?? 'https://example.com';
const width = Number(process.env.VIEWPORT_WIDTH ?? 1280);
const height = Number(process.env.VIEWPORT_HEIGHT ?? 800);
const fullPage = process.env.FULL_PAGE === 'true';
if (!Number.isInteger(width) || width <= 0 ||
!Number.isInteger(height) || height <= 0) {
throw new Error('Viewport dimensions must be positive integers');
}
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width, height, deviceScaleFactor: 1 });
await page.goto(target, { waitUntil: 'networkidle2', timeout: 60_000 });
await page.screenshot({ path: 'capture.png', fullPage });
} finally {
await browser.close();
}
Install with npm install puppeteer, save as capture.mjs, and run TARGET_URL=https://example.com VIEWPORT_WIDTH=1280 VIEWPORT_HEIGHT=800 node capture.mjs. Set FULL_PAGE=true for the full scrollable page. A deviceScaleFactor above 1 increases output resolution; use 1 when you want output pixel dimensions aligned with CSS pixels. Puppeteer’s screenshot options include full-page capture, clipping, image type, JPEG quality, and transparent background via omitBackground. Consult the version-specific Puppeteer ScreenshotOptions reference when using those options.
5. shot-scraper: command-line and repeated captures
shot-scraper exposes screenshot dimensions and scale as command-line options. A single viewport capture can be made with:
shot-scraper https://example.com --width 1280 --height 800 --output capture.png
For a higher-resolution output, add a scale factor. For example, width 390 and height 844 at scale factor 3 produce 1170 × 2532 output pixels:
shot-scraper https://example.com --width 390 --height 844 --scale-factor 3 --output mobile.png
Use the tool’s full-page option when the entire document is required; do not treat a larger viewport height as equivalent to full-page capture. For recurring or multiple captures, put the shots in a shared configuration and apply the same scale factor consistently. This helps prevent dimensions from drifting between runs while allowing different sites to use different intended viewports. See the shot-scraper documentation for the installed release’s configuration and CLI syntax.
6. Make scheduled captures repeatable
Dimensions alone do not guarantee identical screenshots. Page content, fonts, timing, browser versions, and network results can also change. Use this checklist when setting up a recurring job:
- Record viewport width and height in CSS pixels.
- Record capture extent: viewport, full page, clip, or element.
- Record output scale and image format.
- Set viewport before navigation on every run.
- Keep the browser automation package and browser version stable, and update them deliberately.
- Use the same wait rule and any required selector or delay.
- Use a consistent locale, timezone, and authentication state if those affect the rendered page.
- Decide how to handle animations, video, rotating content, and lazy-loaded images.
- Save the actual output dimensions and failure details with the scheduled job so changes are diagnosable.
If the goal is to compare a specific responsive layout over time, use a fixed viewport and scale. If the goal is to compare what a user sees on several device classes, define a separate stable configuration for each device layout.
7. Performance, reliability, and file size
A larger viewport can cause a page to lay out more content at once, while a full-page capture can require additional rendering and image encoding. Increasing scale multiplies pixel count: doubling both output dimensions produces four times as many pixels. That can increase memory use, file size, and storage or transfer cost. Choose the smallest extent and scale that answer the task.
Full-page screenshots of long or dynamically changing pages may be slower and can differ if content loads while the capture is being prepared. Lazy-loaded images may need scrolling or a tool feature that loads them before capture. Fixed-position elements can appear differently in full-page captures depending on browser behavior. For reliable comparisons, wait for a meaningful page-ready condition and avoid capturing while content is still shifting.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The layout is mobile in one run and desktop in another | Viewport width differs, or it was changed after navigation. | Set the same width before navigation and use the same context configuration on each run. |
| The image file is larger than the viewport dimensions | Device scale factor or scale-factor option is above 1. | Use scale 1 for CSS-pixel-aligned output, or document the expected multiplied dimensions. |
| The screenshot is only the visible area | Viewport capture is the default in many flows. | Enable the tool’s full-page option; increasing viewport height only captures a taller viewport. |
| Full-page output is unexpectedly huge or fails | The document is very long, scale is high, or the browser runs out of memory. | Use a lower scale, capture specific elements or clips, or split the page into sections. |
| Images or fonts are missing | Capture happened before resources finished loading, or lazy loading requires scrolling. | Wait for a relevant selector or resource condition, scroll lazy content into view, and check network access. |
| Captures vary despite fixed dimensions | Dynamic data, animations, rotating banners, timestamps, fonts, or browser changes. | Stabilize the page state where possible, disable animations, pin browser dependencies, and compare only relevant regions. |
| Automation times out waiting for network idle | Analytics, streaming, or other requests keep the network active. | Wait for a page-specific selector or a bounded delay instead of requiring a fully idle network. |
| Requested dimensions are ignored or rejected | Values are malformed, non-positive, or passed using another tool’s option syntax. | Validate positive integer width and height and check the documentation for the installed tool version. |
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF. Its API uses familiar screenshot parameter names, and the ScreenshotNeo API documentation lists the available options, including viewport sizing, full-page capture, and output format.
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,
)
r.raise_for_status()
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())));
Set the width and height options for the intended viewport and choose full-page capture separately when needed; use the docs for exact parameter names and supported values. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An 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.
10. Frequently asked questions
Should I use the same dimensions for every website?
Use the same dimensions for runs intended to compare the same layout. Different sites or device targets can have separate fixed configurations.
Does full-page capture change the viewport?
No. It changes the captured extent to include the scrollable document. The viewport still determines the page’s responsive layout.
How do I know the actual output dimensions?
Inspect the saved image’s pixel width and height. Compare them with the CSS viewport and scale factor; full-page output also depends on document height.


