Short answer: use page.setViewport() to define the page’s CSS layout viewport, and use Chrome’s --window-size=WIDTH,HEIGHT launch flag to size the headless screen/window. They are related but operate at different browser layers. If your test cares about responsive breakpoints, set the viewport. If it cares about window or screen geometry, configure the window and verify the resulting metrics.
Puppeteer’s documented default viewport is 800×600 CSS pixels. In headless Chrome, the screen is also 800×600 unless you provide --window-size (or configure screen information). These values can look interchangeable while producing different results in layout, screenshots, popups, and window-management tests.
What each setting controls
page.setViewport(): the page’s CSS viewport
setViewport() changes the dimensions exposed to the document as its layout viewport. Width and height are CSS pixels, the same coordinate system used by media queries, responsive frameworks, and window.innerWidth/window.innerHeight. Puppeteer’s default viewport is { width: 800, height: 600 }.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.setViewport({width: 1440, height: 900});
await page.goto('https://example.com', {waitUntil: 'networkidle2'});
console.log(await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
dpr: window.devicePixelRatio
})));
await browser.close();
Set the viewport before navigation whenever possible. Changing isMobile or hasTouch can reload the page, so configuring those properties after a page has loaded may trigger another navigation-like lifecycle.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
--window-size: the headless screen/window layer
Pass the switch in launch({args: [...]}):
const browser = await puppeteer.launch({
headless: true,
args: ['--window-size=1440,900']
});
Puppeteer’s screen-configuration guide states that, without --screen-info, headless Chrome has one 800×600 screen unless --window-size is supplied; with the switch, the headless screen is as large as the requested window. This is not a promise that every page metric becomes 1440×900. The active CSS viewport, browser content area, device scale factor, and window decorations are separate concerns.
Window content dimensions with Puppeteer’s window API
When a test needs browser-window content dimensions rather than a fixed viewport, remove Puppeteer’s default viewport constraint and use page.resize():
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.setViewport(null);
await page.resize({contentWidth: 1200, contentHeight: 800});
The inner-window size updates asynchronously. Wait for the resize event before reading window.innerWidth and related values. The official window-management example uses this pattern rather than assuming the resize is instantaneous.
Which one should you use?
| Test or automation goal | Primary control | What to verify |
|---|---|---|
| Reproduce a responsive desktop or mobile layout | page.setViewport({width, height, ...}) |
CSS viewport, media-query behavior, and window.innerWidth |
| Change the headless screen/window size | --window-size=WIDTH,HEIGHT |
Screen and outer-window values in the running browser |
| Set browser content-area dimensions through Puppeteer | setViewport(null), then page.resize({contentWidth, contentHeight}) |
Inner dimensions after the resize event |
| Emulate mobile or touch behavior | Viewport plus isMobile/hasTouch, before navigation |
Layout, input capabilities, and any reload caused by changes |
Start by naming the value your assertion actually depends on: CSS layout viewport, inner content window, outer browser window, or screen bounds. Configure that layer and read it back in page or browser context. Do not treat a matching-looking screenshot as proof that all four dimensions agree.
Recommended Free Tools
A reliable diagnostic script
The following script records the values most often confused in headless tests. It also waits for a resize event when you use the window API.
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
args: ['--window-size=1440,900']
});
const page = await browser.newPage();
await page.setViewport({width: 1280, height: 720});
await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
const metrics = await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
screenWidth: window.screen.width,
screenHeight: window.screen.height,
devicePixelRatio: window.devicePixelRatio,
visualViewport: window.visualViewport && {
width: window.visualViewport.width,
height: window.visualViewport.height,
scale: window.visualViewport.scale
}
}));
console.log(metrics);
await browser.close();
Run the same page once with only setViewport, once with only --window-size, and once with setViewport(null) plus resize. Compare the metric that your production assertion uses. This isolates configuration mistakes from application breakpoints.
Complete Puppeteer patterns
Responsive screenshot at a known CSS viewport
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.setViewport({
width: 375,
height: 812,
deviceScaleFactor: 2,
isMobile: true,
hasTouch: true
});
await page.goto('https://example.com', {waitUntil: 'networkidle2'});
await page.screenshot({path: 'mobile.png', fullPage: true});
await browser.close();
Use this when the question is “what does the page render at 375 CSS pixels?” The device scale factor affects rasterization, not the CSS breakpoint width.
Headless screen configuration
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
args: ['--window-size=1920,1080']
});
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.evaluate(() => ({
inner: [window.innerWidth, window.innerHeight],
outer: [window.outerWidth, window.outerHeight],
screen: [window.screen.width, window.screen.height]
})));
await browser.close();
Do not infer the final inner size from the command-line argument. Read the values after navigation, because content-area sizing and viewport constraints can produce different numbers.
Content-area resizing with an event barrier
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.setViewport(null);
await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
await page.evaluate(() => new Promise(resolve => {
if (window.innerWidth === 1200 && window.innerHeight === 800) return resolve();
window.addEventListener('resize', () => resolve(), {once: true});
}));
await page.resize({contentWidth: 1200, contentHeight: 800});
// Better: install the listener immediately before resize in production code.
console.log(await page.evaluate(() => [window.innerWidth, window.innerHeight]));
await browser.close();
For production, register the listener before calling resize and include a timeout so a missing event cannot hang the job indefinitely:
const resize = page.evaluate(({w, h}) => new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('resize timeout')), 5000);
const done = () => { clearTimeout(timer); resolve(); };
if (window.innerWidth === w && window.innerHeight === h) done();
else window.addEventListener('resize', done, {once: true});
}), {w: 1200, h: 800});
await page.resize({contentWidth: 1200, contentHeight: 800});
await resize;
Why --window-size may not change your viewport
A default viewport is still active
Puppeteer creates pages with its default viewport unless you replace it. A larger headless screen can therefore surround a page that remains constrained to the configured CSS viewport. Use setViewport for layout or clear it with setViewport(null) when using content resizing.
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
You are inspecting the wrong metric
window.innerWidth describes the inner page window; window.outerWidth concerns the outer window; screen.width describes the available screen. A test that reads one cannot prove another changed.
Headless mode differs from headful mode
Headless Chrome has virtual screen behavior. Headful Chrome uses physical platform screens. Puppeteer’s newer default headless mode is intended to match regular Chrome more closely, while the 'shell' setting uses the separate chrome-headless-shell binary and does not completely match regular Chrome. Record the mode in CI and local runs before comparing metrics.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsMobile emulation changes more than width
isMobile and hasTouch affect emulation behavior, not merely the number of pixels. Configure them before navigation and expect a reload when changing them on an existing page.
Troubleshooting checklist
Screenshot has the expected size but the layout is wrong
- Log
window.innerWidthand the relevant media-query result, not only the image dimensions. - Set the viewport before
goto. - Check whether a device scale factor changed raster pixels while CSS pixels stayed constant.
window.innerWidth is smaller than --window-size
- Check whether Puppeteer’s default viewport is constraining the page.
- Try
await page.setViewport(null)beforepage.resize. - Read
outerWidthandscreen.widthto identify which layer received the requested size.
Resize assertions race intermittently
- Wait for the
resizeevent after callingpage.resize. - Add a bounded timeout and log all four width/height pairs.
- Wait for the application’s own layout-ready selector if it performs asynchronous rendering after resize.
Mobile settings trigger unexpected navigation
- Set
isMobile,hasTouch, and viewport dimensions beforegoto. - After changing them, wait for the new document and application readiness before taking a screenshot.
Headless and headful results disagree
- Use the same Puppeteer headless mode in both comparisons.
- Remember that headful Chrome uses the host’s physical screens.
- Capture the browser version, launch arguments, viewport settings, and reported metrics in CI logs.
Performance, reliability, and cost considerations
Viewport changes are inexpensive compared with launching a browser, but repeated navigation and reloads caused by mobile or touch emulation can dominate a test. Reuse a browser process, create isolated pages, set each page’s viewport once, and avoid resizing repeatedly during a single capture unless the test specifically covers responsive transitions.
For deterministic screenshots, wait for the appropriate readiness condition: a selector for critical content, network idle when it is meaningful for the application, and explicit font or image readiness when visual diffs depend on them. A window-size flag alone does not make page rendering deterministic.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
Keep screenshot dimensions within your CI runner’s memory limits. Full-page captures can be much taller than the viewport, and high device scale factors multiply raster memory. If a run fails, preserve the logged CSS, inner, outer, and screen metrics so the failure can be reproduced rather than guessed at.
Or skip the browser setup
For a one-request website screenshot, ScreenshotNeo returns PNG, JPEG, WebP, or PDF from a URL. Its API accepts viewport and device options while handling the browser infrastructure.
cURL (see the ScreenshotNeo documentation):
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}`);
Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Create a free ScreenshotNeo account to start with 1,000 screenshots a month and no card.
FAQ
Does --window-size=800,600 guarantee an 800×600 page?
No. It sizes the headless screen/window layer. A page viewport constraint, content-area dimensions, and device settings can yield different inner values; inspect them in the running page.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchShould I use setViewport(null) for every test?
No. Keep an explicit viewport for responsive layout tests. Clear it when you intentionally want Puppeteer’s window API to determine content dimensions.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Is the 800×600 value a browser limitation?
No. It is Puppeteer’s documented default viewport and the default headless screen in the stated configuration, not a maximum.
Can headless shell be used as a drop-in replacement?
Not completely. Puppeteer documents 'shell' as a separate chrome-headless-shell binary whose behavior does not fully match regular Chrome.
Frequently Asked Questions
Which metric should a responsive test assert?
Assert the CSS layout value used by the application, usually window.innerWidth or a media-query result, after setting the viewport before navigation.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Why does my screenshot look correct while window.innerWidth is wrong?
Raster image dimensions and CSS layout dimensions use different layers; log inner, outer, screen, and device-pixel values to find the mismatch.
The Bottom Line
Use setViewport for CSS layout, --window-size for headless screen geometry, and setViewport(null) plus page.resize() for Puppeteer-managed content dimensions. Verify the exact metric your test consumes instead of assuming the settings are interchangeable.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




