How to Capture a Website Screenshot at a Specific Viewport Size
Set a precise browser viewport with Playwright, capture the visible page, and choose the right output scale, page area, and readiness checks.
To capture a website at a specific viewport size, set the browser viewport width and height in CSS pixels before navigating to the page, wait for the content you need, then take a normal viewport screenshot. In Playwright, a regular screenshot captures the visible viewport; set fullPage: true only when you want the whole scrollable page. The dimensions below are examples—replace them with the size your task requires.
Capture a viewport screenshot with Playwright
This complete Node.js example opens Chromium, sets a 1280 × 800 CSS-pixel viewport before navigation, waits for the page load event, and saves the visible viewport as a PNG:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewportSize({ width: 1280, height: 800 });
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'screenshot.png' });
} finally {
await browser.close();
}
})();
Install Playwright and its Chromium browser in your project with:
npm install playwright
npx playwright install chromium
Run the script with node capture.js after saving it as capture.js. Playwright recommends setting the viewport before navigation for responsive pages. Its setViewportSize() method also resets the screen size. See the Playwright Page API.
Set the viewport before navigating
The viewport controls the page area available to the website’s layout, in CSS pixels. Changing it can trigger responsive breakpoints, alter columns and menus, and affect which content is visible. Set it before page.goto() so the page loads using the intended dimensions.
For finer control over both screen and viewport dimensions, configure them on the browser context when creating it. This can matter when a test or site reads both values:
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
screen: { width: 1280, height: 800 }
});
const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
Choose a page readiness condition
The right readiness condition depends on the site. The example uses waitUntil: 'load', which waits for the page load event. For a page whose visible content is rendered later by JavaScript, wait for a meaningful selector instead of relying on an arbitrary delay:
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main article').waitFor({ state: 'visible' });
await page.screenshot({ path: 'screenshot.png' });
You can also wait for a known application state or a deliberate delay if the target site requires it. There is no single wait condition that guarantees every page is visually ready. Network activity can continue indefinitely on pages with analytics or live updates, so choose a condition that represents the content you need.
Viewport, full-page, clipped, and device-scale screenshots
| Capture type | What it includes | Playwright option |
|---|---|---|
| Viewport | The currently visible page area at the configured viewport size. | Default: page.screenshot() |
| Full page | The entire scrollable page, which can be much taller than the viewport. | page.screenshot({ fullPage: true }) |
| Clipped region | A rectangle within the rendered page, defined by its position and dimensions. | page.screenshot({ clip: { x, y, width, height } }) |
| Element | A selected element and its contents. | locator.screenshot() |
For example, this captures a 600 × 400 CSS-pixel rectangle starting 100 pixels from the left and 80 pixels from the top:
await page.screenshot({
path: 'region.png',
clip: { x: 100, y: 80, width: 600, height: 400 }
});
Use clipping when the viewport should stay the same but you need only one part of the page. Use full-page capture when the entire scrollable document matters. A page screenshot does not include browser controls, operating-system chrome, or a device frame. Playwright documents these capture options in its screenshot guide and Page API.
CSS pixels and output pixels
Viewport width and height are CSS-pixel dimensions. The screenshot’s raw pixel dimensions also depend on the device scale factor. With scale: 'css', the output uses one image pixel per CSS pixel. With scale: 'device', output follows the device scale factor and can be larger on high-DPI contexts.
// Output dimensions follow CSS pixels.
await page.screenshot({ path: 'css-scale.png', scale: 'css' });
// Output dimensions follow the device scale factor.
await page.screenshot({ path: 'device-scale.png', scale: 'device' });
To control device scale explicitly, set it on the browser context:
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
deviceScaleFactor: 2
});
const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png', scale: 'device' });
Here the CSS layout viewport remains 1280 × 800, while device-scale output can contain twice as many pixels in each dimension. Device scale changes output pixel density; it does not change the CSS layout viewport.
Other useful screenshot options
Playwright’s screenshot options let you specify output path and format, capture area, and background behavior. Common options include:
path: output filename. The extension determines the format when a path is provided.type: explicitly choose'png'or'jpeg'where supported by the API.quality: JPEG quality from 0 to 100; applies to JPEG output.fullPage: capture the full scrollable page instead of only the viewport.clip: capture a rectangle withx,y,width, andheight.scale: choose'css'or'device'output scaling.omitBackground: omit the default background for a transparent PNG when applicable.animations: disable or allow animations during capture.caret: hide or show the text caret.timeout: set the maximum time in milliseconds for the screenshot operation.
Check the current Playwright API reference for supported options and their precise behavior in your installed version.
Common variations
Capture a responsive mobile layout
Set the target CSS viewport width and height before loading the page. A mobile-sized viewport does not automatically reproduce every characteristic of a physical phone; device emulation can also involve touch, screen dimensions, and device scale. For a layout check, viewport size may be all you need. For device-specific testing, create a browser context with the relevant emulation settings.
Capture an element instead of the viewport
Use a locator when the target is one component, chart, or card. The element’s screenshot is sized to the element rather than the full viewport:
await page.locator('#report').screenshot({ path: 'report.png' });
Use Chrome DevTools Protocol directly
If you already control a Chromium browser through the Chrome DevTools Protocol, its Page.captureScreenshot command supports format, clip-region, and beyond-viewport capture settings. This is a lower-level route than Playwright; the details are documented in the Chrome DevTools Protocol Page domain.
Or skip the browser setup
ScreenshotNeo captures a URL through one API request. Set the requested viewport using its viewport parameter; see the ScreenshotNeo API documentation for the accepted parameter names and response details.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-d viewport=1280x800 \
-o screenshot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server provides screenshot tools for AI agents, including Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. See ScreenshotNeo for product details and the API documentation for configuration.
Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.
Performance, reliability, and cost
- Keep the capture area small when possible. Viewport screenshots usually produce smaller files and require less work than full-page captures of long documents.
- Choose output scale deliberately. Device-scale images can be substantially larger than CSS-scale images. Use the pixel density your downstream use requires.
- Wait for the content you need. A targeted selector wait can avoid capturing too early; a fixed delay can add avoidable time and still miss late content.
- Close the browser in cleanup code. The
finallyblock in the example releases the browser even if navigation or capture fails. - Expect page-specific differences. Fonts, animations, lazy-loaded images, consent dialogs, and dynamic content can affect repeatability. Configure readiness and page state for your use case.
- Account for infrastructure. Local Playwright has no per-screenshot API charge, but browser execution consumes compute, memory, and storage. Hosted capture APIs trade browser maintenance for service pricing; compare plan limits and failure/billing behavior against your volume.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The layout has the wrong breakpoint or columns. | The viewport was set after navigation, or the dimensions are not the intended CSS pixels. | Set width and height before goto(); verify the page’s responsive layout at those CSS dimensions. |
| The image dimensions are larger than expected. | Device-scale output multiplies CSS dimensions by the device scale factor. | Use scale: 'css' for one output pixel per CSS pixel, or adjust deviceScaleFactor. |
| The screenshot is cut off at the viewport bottom. | A regular screenshot captures only the visible viewport. | Use fullPage: true for the whole document or a clip rectangle for a selected region. |
| Content is missing or appears half-rendered. | The capture ran before the relevant content appeared, or the site renders asynchronously. | Wait for a meaningful visible selector or application state before capturing. |
| The capture hangs or times out. | Navigation may be waiting for a condition that the page never reaches, or the page is slow. | Choose a suitable navigation readiness condition, wait for the content you need, and set explicit navigation and screenshot timeouts appropriate to your environment. |
| A clip operation fails or captures the wrong area. | Clip coordinates and dimensions do not describe the intended rectangle. | Check that x/y and width/height are in CSS pixels and that the region lies within the rendered page. |
| Playwright cannot launch Chromium. | The browser binary may not be installed in the environment. | Run npx playwright install chromium and check that the runtime has the libraries and permissions required for Chromium. |
Frequently asked questions
Does viewport size include browser tabs and toolbars?
No. It describes the page’s browser viewport, not the entire browser window or operating-system screen.
Is a 1280 × 800 viewport a standard?
No. It is an example used in this guide. Choose dimensions that match the requirement you are trying to reproduce.
Can I set width without height?
Playwright’s viewport setting takes both width and height. Pick both values so the visible area and responsive layout are deterministic.
Will a full-page screenshot have the same dimensions as the viewport?
No. It retains the viewport width but extends vertically to include the scrollable page content.
Summary
- Decide whether you need the CSS viewport dimensions, raw image dimensions, or both.
- Set the viewport before navigation.
- Wait for the target content, then capture the viewport by default.
- Choose full-page, clipping, element capture, and output scale only when the task calls for them.
For the documented Playwright behavior, see the Page API and screenshot guide.


