ScreenshotNeo

BlogHow-to

How to Capture a Mobile Web Page Screenshot with an Exact CSS Viewport

Set an exact mobile CSS viewport in Playwright, Puppeteer, or Chrome DevTools, and understand how device scale affects screenshot pixels.

By the ScreenshotNeo team4 October 20268 min read

To capture a mobile web page at an exact CSS viewport, set the viewport width and height in CSS pixels before navigating, then capture the visible viewport. For repeatable automation, Playwright lets you set the context viewport explicitly. Use mobile emulation when the page must respond to mobile browser characteristics such as touch support or a mobile user agent. Decide separately whether the output image should use CSS pixels or device pixels: those dimensions are related, but they are not always the same.

This guide shows how to capture a 390 × 844 CSS-pixel viewport with Playwright, Puppeteer, and Chrome DevTools, and how to avoid confusing viewport size with screenshot image size.

1. Understand CSS viewport size and screenshot pixels

The viewport is the page’s visible CSS layout area. A viewport of 390 × 844 means the browser lays out the page in a region 390 CSS pixels wide and 844 CSS pixels tall. The resulting image file can have different pixel dimensions depending on device scale factor and screenshot scaling.

  • CSS viewport: controls the layout dimensions seen by the page, including responsive breakpoints and media queries.
  • Device pixel ratio (DPR): describes how device pixels relate to CSS pixels. A DPR of 2 means one CSS pixel maps to two device pixels in each dimension.
  • Screenshot scale: determines the image-pixel mapping in APIs that offer a scale option. In Playwright, scale: 'css' produces one image pixel per CSS pixel; scale: 'device' produces one image pixel per device pixel.
  • Capture mode: a viewport screenshot shows the configured visible area. A full-page screenshot includes the full scrollable page, so its height is not the fixed viewport height.

For a 390 × 844 CSS viewport with device scale factor 2, a device-pixel screenshot can be 780 × 1688 pixels. If the required file itself must be 390 × 844 pixels, request CSS scaling where supported or use a device scale factor of 1 and verify the output dimensions.

2. Capture an exact viewport with Playwright

Create a browser context with explicit dimensions before opening the page. The following complete Node.js example captures the visible viewport at 390 × 844 CSS pixels and writes an image with one pixel per CSS pixel.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: true });
  try {
    const context = await browser.newContext({
      viewport: { width: 390, height: 844 },
      isMobile: true,
      deviceScaleFactor: 1,
    });
    const page = await context.newPage();
    await page.goto('https://example.com', { waitUntil: 'networkidle' });
    await page.screenshot({
      path: 'mobile-390x844.png',
      fullPage: false,
      scale: 'css',
    });
    await context.close();
  } finally {
    await browser.close();
  }
})();

Install Playwright and its Chromium browser if they are not already available in your project:

npm install playwright
npx playwright install chromium

Set the target URL, viewport, mobile behavior, scale, and capture mode deliberately:

Setting What it controls Use it when
viewport CSS layout width and height in pixels You need a particular responsive layout or a repeatable screenshot size.
isMobile Mobile browser behavior in the emulated context The page’s behavior depends on mobile-specific browser features.
deviceScaleFactor Mapping between CSS and device pixels You need to control high-DPI rendering. Use 1 for a one-to-one mapping when appropriate.
scale Output image-pixel mapping: css or device You need CSS-pixel-sized output or device-pixel detail.
fullPage Whether to capture the full scrollable document Use false for a fixed-height viewport image; use true for a full-page image.

For a custom CSS viewport without mobile-specific browser behavior, omit isMobile and set the viewport explicitly. If you use a built-in device profile, its settings include a viewport; apply your desired custom viewport after spreading the profile so the custom dimensions take precedence. Device profiles can also represent properties such as user agent, screen size, and touch capability. See the official Playwright emulation documentation and Playwright Page API.

3. Capture with Puppeteer

For Puppeteer, apply device emulation before navigating. Emulation sets device metrics and user agent; changing size after navigation can affect pages that do not expect their viewport to change.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({
      width: 390,
      height: 844,
      deviceScaleFactor: 1,
      isMobile: true,
      hasTouch: true,
    });
    await page.goto('https://example.com', { waitUntil: 'networkidle0' });
    await page.screenshot({
      path: 'mobile-390x844.png',
      fullPage: false,
    });
  } finally {
    await browser.close();
  }
})();

Install Puppeteer with npm install puppeteer if needed. For a named device profile, use Puppeteer’s device descriptor and call page.emulate(device) before navigation. For a custom viewport, use page.setViewport() and explicitly set any additional mobile properties the page requires. The official Puppeteer Page.emulate() documentation describes the device emulation shortcut and its ordering guidance.

4. Capture with Chrome DevTools

  1. Open the target page in Chrome and open DevTools.
  2. Turn on Device Mode and choose Responsive.
  3. Enter the required width and height in the viewport controls, such as 390 and 844.
  4. If mobile behavior matters, choose a mobile device type or configure the intended device pixel ratio and device characteristics.
  5. Use Capture screenshot for the visible viewport. Choose Capture a full size screenshot only when you want the entire scrollable page.

DevTools also supports custom device definitions. A custom device can include dimensions, with device pixel ratio, user agent, and device type as optional fields. Follow the official Chrome DevTools Device Mode documentation for current controls.

5. Choose the right emulation and capture mode

Approach Best for Key control
Playwright Repeatable automated captures and tests Set context viewport explicitly; choose screenshot scale.
Chrome DevTools Quick manual capture and visual inspection Enter viewport width and height; set device type and DPR when needed.
Puppeteer Scripted browser capture using Chrome automation Set viewport or emulate a device before navigation.

Custom dimensions are enough when the question is simply how a responsive layout looks at a particular CSS width and height. Use mobile emulation when browser behavior matters too—for example, when the page responds to a mobile user agent, screen characteristics, or touch support. A device preset is convenient, but for an exact custom viewport, verify that the preset’s dimensions have not replaced the dimensions you need.

Use a viewport capture to preserve a fixed visible area. Use full-page capture when you need all scrollable content, understanding that the resulting image no longer represents a fixed-height viewport. Playwright documents these screenshot modes and the css and device scaling options in its Page API.

6. Make screenshots repeatable

For reliable comparisons, hold the browser and capture settings constant. Keep the viewport width and height, device scale factor, mobile emulation settings, page state, and capture mode the same between runs. This is practical guidance based on the documented controls; it does not imply that captures from different browser versions or changing pages will be identical.

  • Set dimensions explicitly instead of relying on the default browser window.
  • Apply emulation before navigation, especially in Puppeteer.
  • Use the same browser version and device settings for a comparison set.
  • Wait for the page state you need. Network idle can be useful, but pages with long-lived network requests may never become idle; in that case wait for a meaningful selector or a deliberate delay.
  • Keep viewport and full-page captures separate in your workflow because they answer different questions.
  • Check the saved image’s actual pixel dimensions when a downstream system requires an exact file size.

7. Troubleshoot viewport and image-size mismatches

Symptom Likely cause Fix
The image is larger than the requested viewport. Device-pixel output or a device scale factor above 1. Use CSS scaling where available, set the intended device scale factor, and inspect the resulting file dimensions.
The page layout does not look mobile. The CSS viewport is narrow, but mobile browser properties were not emulated and the page relies on them. Enable mobile emulation or specify the needed user agent, screen, and touch settings.
The viewport changed after navigating. Emulation or resizing was applied late, and the page reacted to the change. Set the viewport or emulate the device before navigation, then reload for a consistent capture.
The screenshot is much taller than the requested height. Full-page capture was enabled. Disable full-page mode for a fixed viewport screenshot.
A preset ignores the custom width and height. The preset’s viewport was applied after the custom dimensions. Apply the preset first and override its viewport afterward.
The page appears blank or incomplete. The capture happened before the content rendered, or the page failed to load. Wait for a relevant selector or page state; confirm the navigation completed and the URL is reachable.
Puppeteer throws a navigation or network-idle timeout. The page keeps network connections open or never reaches the selected wait condition. Use a more suitable navigation condition and wait for a specific element or bounded delay instead.

8. Performance, reliability, and cost

Browser automation gives you direct control over viewport and emulation settings, but it also requires launching and maintaining a browser process. Reusing a browser across captures can avoid repeated startup overhead; isolate contexts when captures need separate cookies, storage, or settings. Large full-page images and high device scale factors increase image dimensions and can increase memory use and output-file size.

For repeatable work, explicitly configure the viewport and capture mode and make the page-ready condition specific to the site. A fixed viewport capture generally does less image work than a full-page capture, but page complexity and network behavior also affect completion time. There is no single cost figure for running Playwright, Puppeteer, or DevTools: it depends on where browser automation runs and the infrastructure and volume involved.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. It accepts a URL in one GET request and returns a screenshot or PDF. For API parameters and options, 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
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}`);

Replace the example URL with your target. Configure the required viewport through the API’s supported parameters in its documentation. ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its 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.

FAQ

Does a 390 × 844 screenshot always contain 390 × 844 image pixels?

No. Those values describe CSS viewport dimensions. Device scale factor and screenshot scaling determine how many image pixels represent each CSS pixel.

Should I use a phone preset or enter custom dimensions?

Enter custom dimensions when the target is an exact CSS viewport. Use a phone preset when its additional emulation properties matter, then override its viewport if the preset dimensions differ from your target.

Can a full-page screenshot still have an exact viewport?

The browser can use the exact viewport for layout, but a full-page image includes content beyond the visible viewport and has a taller output. Use viewport capture when the deliverable must show only the configured visible area.

Which method should I use?

Use Playwright or Puppeteer for scripted repeatability, and Chrome DevTools for quick manual inspection. Choose based on whether you need automation and whether mobile browser behavior matters.