To launch a visible Chrome window and request a 1,200 × 800 page content area, use headless: false, remove Puppeteer’s default viewport, and call the experimental page.resize() API:
const browser = await puppeteer.launch({ headless: false });
const page = (await browser.pages())[0];
await page.setViewport(null);
await page.resize({ contentWidth: 1200, contentHeight: 800 });
This sets the content area, not necessarily the outside dimensions of the native window. If you need outer bounds or a maximized window, use page.windowId() with browser.setWindowBounds(). Verify the result in the running page because browser chrome, display limits, the operating system and the window manager affect the final size.
Choose what “window size” means
Puppeteer exposes three related but different sizing controls. Choosing the wrong one is the most common reason a headful window appears to have the “wrong” dimensions.
| Goal | API | What the dimensions represent | Important limitation |
|---|---|---|---|
| Set an emulated page viewport | page.setViewport({width, height}) |
CSS-pixel viewport available to the page | It does not directly guarantee the native window’s outside size; some viewport changes can reload the page. |
| Set visible content area | page.setViewport(null), then page.resize({contentWidth, contentHeight}) |
Page content area, excluding browser UI | Page.resize is marked experimental and must be checked against your installed Puppeteer version. |
| Set native window bounds or state | page.windowId(), then browser.setWindowBounds(id, bounds) |
Browser window bounds or state | Display boundaries and platform window rules can still constrain the usable result. |
page.viewport() reports Puppeteer’s configured viewport settings. It does not inspect the actual native page viewport, so it is not sufficient proof that a visible window reached the requested dimensions.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Set a precise headful content area
Complete runnable example
Install Puppeteer in a Node.js project, then run this script. It opens a visible browser, obtains the first page, removes the default viewport constraint, requests a 1,200 × 800 content area, and waits for the browser’s resize event before reading the measured values.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = (await browser.pages())[0];
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
// Let the native headful window determine the viewport.
await page.setViewport(null);
const resizeEvent = page.evaluate(() => new Promise(resolve => {
window.addEventListener('resize', () => resolve({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight
}), { once: true });
}));
if (typeof page.resize !== 'function') {
throw new Error('This Puppeteer version does not expose page.resize().');
}
await page.resize({ contentWidth: 1200, contentHeight: 800 });
const measured = await Promise.race([
resizeEvent,
new Promise((_, reject) => setTimeout(() => reject(new Error('Resize event timed out')), 10000))
]);
console.log(measured);
// Keep the window open for inspection. Close it when your work is complete.
// await browser.close();
})();
The resize event is registered before the request because the inner dimensions update asynchronously. The measured innerWidth and innerHeight describe the page’s usable content area. outerWidth and outerHeight include browser chrome and therefore will normally differ.
Use your own dimensions
Replace contentWidth and contentHeight with the target CSS-pixel dimensions. For example, page.resize({contentWidth: 1440, contentHeight: 900}) requests a 1,440 × 900 content area. The request is not a promise that the host can provide that size: a small display, tiling window manager, remote desktop session or operating-system policy may reduce it.
Set the outer window bounds or maximize it
Use the bounds API when your requirement concerns the native window rectangle rather than the page content. Get the window identifier from the page and pass bounds or a window state to the browser:
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 errorsconst puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = (await browser.pages())[0];
const windowId = await page.windowId();
await browser.setWindowBounds(windowId, {
width: 1280,
height: 900
});
// For a maximized visible window instead:
// await browser.setWindowBounds(windowId, { windowState: 'maximized' });
console.log(await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight
})));
})();
Outer bounds include title bars, toolbars and other browser UI. Consequently, setting a 1,280 × 900 outer rectangle will not produce a 1,280 × 900 web-content area. If the content dimensions are the acceptance criterion, use page.resize and verify innerWidth/innerHeight.
Rank #2
Viewport sizing versus a real visible window
page.setViewport()
page.setViewport({width: 1200, height: 800}) is appropriate when responsive-layout testing is the goal. It sets the page’s CSS viewport and can be combined with device scale, mobile and touch emulation. It is not a reliable way to measure or control the native headful window’s outside dimensions.
page.setViewport(null)
In a headful window-sizing workflow, null removes Puppeteer’s configured viewport constraint. Without this step, the requested native content size can be constrained by the default viewport emulation, producing confusing measurements.
page.resize()
The current Page API labels resize experimental. Its support and behavior can differ between the Puppeteer package, Chrome build, operating system, display configuration and window manager you have installed. Pin and test the dependency used by your project rather than assuming every version behaves identically.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows 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 reinstallVerify the dimensions instead of trusting configuration
Use browser-side measurements after the resize event:
const size = await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
devicePixelRatio: window.devicePixelRatio
}));
console.log(size);
- innerWidth/innerHeight: the content area in CSS pixels.
- outerWidth/outerHeight: the visible browser window including UI.
- devicePixelRatio: the relationship between CSS pixels and physical display pixels; it does not change the CSS dimensions you requested.
The official window-management example reports an inner size of 600 × 400 and an outer size of 600 × 487. Those are documentation example values, not universal title-bar measurements. Your platform will produce different chrome and borders.
Headful screen and command-line caveats
Do not use headless-only screen assumptions to size a visible window. The official screen-configuration guidance says --screen-info is available only in headless mode, while headful Chrome uses the physical platform screens. Likewise, headless discussions of --window-size should not be treated as a guarantee for a visible Chrome window.
In a container, CI runner or remote desktop, there may be no normal physical display. A virtual display can make headful Chrome launch, but the available bounds still come from that host environment. Record the Puppeteer version, Chrome build, operating system and display setup when diagnosing inconsistent dimensions.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Common failures and fixes
“page.resize is not a function”
Your installed Puppeteer version does not expose the experimental API, or the object is not the Page instance you expect. Check typeof page.resize, confirm the locked package version, and upgrade or pin a version that supports the method. If changing dependencies is not possible, use setWindowBounds for native bounds or setViewport for CSS viewport emulation.
The browser is still headless
Launch with {headless: false}. Also check that a CI environment is not replacing your launch options and that Chrome is allowed to connect to a display.
The page remains at the old size
Call await page.setViewport(null) before page.resize. Register the resize listener before requesting the change, then read dimensions after the event. A fixed timeout alone can race the asynchronous update.
Rank #4
Outer dimensions do not equal the requested content dimensions
This is expected: browser UI occupies part of the outer rectangle. Decide whether your requirement is content or native bounds, then use the corresponding API and measurement.
The requested size is clipped or ignored
Inspect the host display and window manager. A maximized state, screen edge, remote session, desktop scaling policy or operating-system restriction can override the requested bounds. Verify actual values in the page and treat them as the runtime result.
A viewport change unexpectedly reloads the page
Some viewport settings can trigger a reload. Set the viewport before navigation when possible, or wait for navigation and application state again after changing it. For native content sizing, prefer the setViewport(null) plus resize sequence.
Practical reliability checklist
- Pin the Puppeteer dependency and record its version.
- Launch with
headless: falseand ensure a usable display exists. - Choose content sizing, viewport emulation or outer bounds before writing code.
- For content sizing, call
setViewport(null)beforeresize. - Check that
page.resizeexists because it is experimental. - Listen for the browser’s resize event before issuing the request.
- Validate
innerWidth,innerHeight,outerWidthandouterHeight. - Add a timeout and a recovery path for automation that cannot wait indefinitely.
- Test on the actual OS, display and window manager used in production.
Or skip the browser setup
If your actual goal is a website screenshot rather than interactive browser control, ScreenshotNeo provides a single API request and an MCP server for AI agents. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
Here is the same idea as a direct request (see the ScreenshotNeo API documentation for options):
Recommended Free Tools
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo also supports custom content sizing, device presets, retina scale, full-page lazy-image loading, CSS-selector element capture, dark mode, PDFs, custom CSS and JavaScript, clicks, waits, blocked resources, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage reporting and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.
AI workflows can call its MCP tools take_screenshot, get_page_info and capture_pdf from Claude, Cursor or another MCP client. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.
Frequently Asked Questions
Can I use --window-size to guarantee a headful Chrome size?
No. Headless command-line sizing behavior does not guarantee the dimensions of a visible native window. Use the headful APIs and verify runtime measurements.
What does Puppeteer’s page.viewport() tell me?
It reports Puppeteer’s configured viewport settings, not a measurement of the actual native page or window. Use browser-side innerWidth and innerHeight after resizing.
Should I close the browser immediately after resizing?
Only when the capture or test is complete. Keep it open while inspecting the result, and call browser.close() in production cleanup code.
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.

