Free tools Windows power users keep installed
One-click scans. No signup required.
If a Puppeteer screenshot has the wrong width, first separate CSS pixels from image pixels. viewport.width and viewport.height are CSS-pixel dimensions; deviceScaleFactor changes the device scale used for rendering. Set both explicitly before navigation, log window.innerWidth and window.devicePixelRatio, and verify the saved file’s dimensions. Then check whether fullPage, clip, or browser-window resizing changed the capture area.
The reliable fix, in one runnable script
This script establishes a 1,280 × 800 CSS-pixel viewport, uses a device scale factor of 1, records the browser’s measurements, captures only the viewport, and reads the resulting PNG width and height. Keeping the measurement and capture in the same run makes a width mismatch much easier to identify.
const puppeteer = require('puppeteer');
const fs = require('fs');
function pngDimensions(path) {
const b = fs.readFileSync(path);
if (b.readUInt32BE(0) !== 0x89504e47 || b.readUInt32BE(4) !== 0x0d0a1a0a) {
throw new Error('The file is not a PNG');
}
return { width: b.readUInt32BE(16), height: b.readUInt32BE(20) };
}
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({
width: 1280,
height: 800,
deviceScaleFactor: 1,
});
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
const metrics = await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
devicePixelRatio: window.devicePixelRatio,
screenWidth: window.screen.width,
screenHeight: window.screen.height,
documentWidth: document.documentElement.scrollWidth,
documentHeight: document.documentElement.scrollHeight,
}));
console.log('Browser metrics:', metrics);
const file = 'shot.png';
await page.screenshot({ path: file, fullPage: false });
console.log('PNG dimensions:', pngDimensions(file));
await browser.close();
})();
With this configuration, the page should report an inner width near 1,280 CSS pixels and a device-pixel ratio of 1. The relationship between CSS width and bitmap width is normally CSS width multiplied by device scale factor, but treat that as a diagnostic expectation rather than a universal guarantee: clipping, browser behavior, and output format can affect the final file. The PNG header is the authoritative measurement for this run.
Understand which width you are measuring
CSS layout width
page.setViewport({ width, height }) defines the emulated content viewport in CSS pixels. A responsive page uses that value for media queries and layout calculations. window.innerWidth reports the resulting CSS content width, while window.innerHeight reports its height.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Device-pixel width
deviceScaleFactor controls the device scale factor. A factor of 2 can make a 1,280-CSS-pixel layout produce a bitmap about 2,560 pixels wide even though window.innerWidth remains about 1,280. This is the usual explanation for a screenshot that appears “twice as wide.” Check window.devicePixelRatio rather than inferring it from the file name or viewport object.
Browser-window width
The emulated viewport is not always the same thing as the operating system’s outer browser window. window.outerWidth, window.screen.width, and headless-mode behavior can differ from the content area. If you need the actual content window to match a desktop-sized display, use the window-resize method described below instead of inflating the CSS viewport.
Apply the fixes in the right order
1. Set the viewport before navigation
Call page.setViewport() immediately after creating the page and before page.goto(). Many sites choose breakpoints, load responsive assets, or run layout code during navigation. Changing the viewport after those decisions can leave a page in a state that does not match a fresh load at the target size.
const page = await browser.newPage();
await page.setViewport({
width: 1440,
height: 900,
deviceScaleFactor: 1,
});
await page.goto(targetUrl, { waitUntil: 'networkidle0' });
2. If using a device profile, emulate before navigation
page.emulate(device) combines a device profile’s user agent and viewport settings. Run it before navigation for the same reason: responsive behavior and server-delivered markup may depend on the initial device context.
Rank #2
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const device = puppeteer.KnownDevices['iPhone 13'];
await page.emulate(device);
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.screenshot({ path: 'iphone.png', fullPage: false });
await browser.close();
})();
Do not set a desktop viewport and then emulate a phone later unless that change is intentional. The later emulation is the setting that should be trusted for the capture.
3. Log all relevant values before taking the shot
const before = await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
devicePixelRatio: window.devicePixelRatio,
screenWidth: window.screen.width,
screenHeight: window.screen.height,
}));
console.log(before);
If innerWidth is correct but the image is wider, inspect deviceScaleFactor first. If innerWidth is already wrong, look for a late setViewport, emulate, or another piece of code that changes the viewport.
Choose the capture area deliberately
Viewport capture
The default screenshot captures the current viewport. Make that choice explicit with fullPage: false when the output must represent exactly the visible CSS viewport.
await page.screenshot({
path: 'viewport.png',
fullPage: false,
});
Full-page capture
fullPage: true captures the full document, not merely the visible viewport. Its height will normally be larger, and a document with horizontal overflow can also be wider than the viewport. Compare the saved image with document.documentElement.scrollWidth and scrollHeight before treating that result as a viewport-width failure.
Recommended Free Tools
const documentSize = await page.evaluate(() => ({
width: document.documentElement.scrollWidth,
height: document.documentElement.scrollHeight,
}));
console.log(documentSize);
await page.screenshot({ path: 'full.png', fullPage: true });
Clipped capture
clip selects a rectangle rather than the whole viewport. Its x, y, width, and height are capture coordinates, so a clip can intentionally produce a file narrower than the viewport. When a clip extends beyond the viewport, captureBeyondViewport controls whether Puppeteer is allowed to capture that area. Remove accidental clip and capture-beyond-viewport settings while diagnosing a basic width mismatch.
await page.screenshot({
path: 'card.png',
clip: { x: 100, y: 120, width: 640, height: 360 },
captureBeyondViewport: false,
});
Resize the real content window when that is the requirement
If your goal is to reproduce an actual desktop content area rather than an emulated viewport, remove Puppeteer’s default viewport and use the window-management API. The resize is asynchronous, so wait for the resize event before reading dimensions.
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.setViewport(null);
const resized = page.evaluate(() => new Promise(resolve => {
window.addEventListener('resize', () => resolve(), { once: true });
}));
await page.resize({ contentWidth: 600, contentHeight: 400 });
await resized;
console.log(await page.evaluate(() => ({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
})));
await page.screenshot({ path: 'window.png' });
await browser.close();
After the resize, the reported content size should be checked in the same run. This approach is different from setting width: 600 in setViewport: it targets the browser content window itself.
Use a repeatable diagnostic checklist
- Record the Puppeteer and browser versions, headless or headful mode, operating environment, viewport object, device scale factor, and screenshot options.
- Record
innerWidth,innerHeight,devicePixelRatio, and document scroll dimensions immediately before capture. - Capture a PNG while diagnosing so its width and height can be read directly from the file header.
- Compare CSS dimensions with bitmap dimensions; do not compare
window.innerWidthdirectly with an image viewer’s pixel count when the device scale factor is greater than 1. - Keep navigation timing and any post-load scripts fixed. A later viewport change can make two otherwise identical runs incomparable.
Troubleshoot the common symptoms
| Symptom | Likely cause | Fix |
|---|---|---|
| The file is about twice as wide as the requested width | deviceScaleFactor or device emulation gives a device-pixel ratio near 2. |
Log window.devicePixelRatio. Set deviceScaleFactor: 1 when a one-to-one bitmap is required, or keep the higher-resolution output and compare it against CSS width correctly. |
window.innerWidth is not the requested width |
setViewport or emulate ran after navigation, or later code replaced the setting. |
Move the call before goto, search for subsequent viewport changes, and log metrics immediately before capture. |
| Only full-page screenshots are unexpectedly wide | The full document or an overflowing element is wider than the viewport. | Run the scrollWidth diagnostic, remove unintended horizontal overflow, or use a viewport capture if the requirement is the visible area. |
| A clipped screenshot has an unexpected width | clip.width defines the selected region, and capture-beyond-viewport behavior may be involved. |
Remove clip while testing, then reintroduce it with explicit coordinates and dimensions. |
| The browser window, rather than the page layout, must match a display size | An emulated viewport is being used for a real-window requirement. | Call page.setViewport(null), resize the content window, wait for the resize event, and then measure innerWidth. |
| Results differ between runs | Browser version, headless mode, viewport, device scale, capture options, or operating environment changed. | Pin and record those inputs. Take the measurements and screenshot in one reproducible script. |
Performance and reliability considerations
A viewport screenshot limits the capture area and is the simplest baseline for width debugging. Full-page capture adds the entire document, so long pages and lazy-loaded content can change both capture time and output dimensions. If the page changes size after navigation, wait for the condition that matters to your page before measuring; otherwise you may be comparing an early layout with a later screenshot.
Rank #4
For visual-regression work, store the diagnostic object beside the image. That makes a change in CSS width, device scale, document overflow, or capture mode visible without guessing from the bitmap. Keep the output format and screenshot options constant when comparing revisions.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.FAQ
Can a high device scale factor be useful?
Yes. It can provide a higher-density bitmap while preserving the same CSS layout. Use it deliberately for the consumer of the image, and compare CSS and device pixels as separate measurements.
Should I use outerWidth to decide the page’s responsive breakpoint?
No. Responsive page layout is normally based on the content viewport, so innerWidth is the more relevant diagnostic value. Use outer dimensions only when investigating the browser window itself.
Why measure the image file instead of trusting the requested viewport?
The requested viewport describes Puppeteer’s input. The saved file is the output after device scaling, clipping, full-page selection, and format-specific behavior. Measuring both catches configuration mistakes that a request log cannot.
Best Value
- Used Book in Good Condition
Or skip the browser setup
ScreenshotNeo is the alternative to try first when you need a URL turned into a screenshot or PDF without maintaining Puppeteer setup. One GET request returns PNG, JPEG, WebP, or PDF, and its cleaning steps are designed for page captures rather than raw browser debugging.
Use the API with the same target URL you would give Puppeteer:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for request options. The equivalent Python and Node.js calls are:
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}`);
- Before capture, it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Each step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers identify the page verdict and whether the request was billed with
X-Page-VerdictandX-Billed. - An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The Free plan includes 1,000 shots per month with no card. Paid plans are Starter ($5 for 3,000), Growth ($15 for 15,000), Pro ($39 for 60,000), Scale ($99 for 250,000), and Business ($249 for 1,000,000). Yearly billing gives two months free, and every feature is included on every plan.
Create a free ScreenshotNeo account to get 1,000 screenshots each month without entering a card.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated 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 matchFrequently Asked Questions
Can a high device scale factor be useful?
Yes. It can provide a higher-density bitmap while preserving the same CSS layout. Use it deliberately for the consumer of the image, and compare CSS and device pixels as separate measurements.
Should I use outerWidth to decide the page’s responsive breakpoint?
No. Responsive page layout is normally based on the content viewport, so innerWidth is the more relevant diagnostic value. Use outer dimensions only when investigating the browser window itself.
Why measure the image file instead of trusting the requested viewport?
The requested viewport describes Puppeteer’s input. The saved file is the output after device scaling, clipping, full-page selection, and format-specific behavior. Measuring both catches configuration mistakes that a request log cannot.
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.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →

