ScreenshotNeo

BlogHow-to

How to screenshot a website at different device pixel ratios

Control viewport size and device pixel ratio independently to capture consistent website screenshots. See manual Chrome steps, runnable automation code, and fixes for common issues.

By the ScreenshotNeo team4 October 20267 min read

To screenshot a website at different device pixel ratios (DPRs), keep the CSS viewport dimensions fixed and change the browser’s emulated DPR. Then choose whether the saved image should use CSS-pixel dimensions or device-pixel dimensions. DPR and viewport size are separate controls: changing DPR alone does not change the CSS layout width.

For a manual capture, use Chrome DevTools Device mode. For repeatable automated captures, configure a Playwright browser context with deviceScaleFactor, and set screenshot scale to device or css explicitly. [MDN: devicePixelRatio] [Playwright screenshots]

What DPR changes in a screenshot

window.devicePixelRatio is the ratio of physical display pixels to CSS pixels. At DPR 1, one device pixel corresponds to one CSS pixel. At DPR 2, two device pixels correspond to each CSS pixel in each dimension.

Suppose a page is rendered in a 390 × 844 CSS-pixel viewport. A device-scale screenshot at DPR 2 will generally be about 780 × 1688 image pixels, while a CSS-scale screenshot will generally be about 390 × 844 pixels. These are dimensional expectations, not guarantees of exact bounds: browser implementation, clipping, full-page sizing, and output handling can affect the final dimensions. Since both dimensions grow with DPR, image pixel area grows approximately with the square of DPR.

DPR affects rendering density and device characteristics. The CSS viewport controls responsive layout breakpoints. Keep viewport width and height fixed when comparing sharpness or pixel density; change viewport width deliberately when comparing responsive layouts.

Capture manually with Chrome DevTools

  1. Open the page in Chrome and open DevTools.
  2. Turn on the Device toolbar. Select Responsive or a device preset, then enter fixed viewport width and height for comparable captures.
  3. In the Device toolbar, open the options menu and enable Add device pixel ratio if the DPR selector is not visible.
  4. Select the desired DPR. Keep the viewport dimensions unchanged if you are isolating DPR.
  5. Open the Device toolbar options menu and choose Capture screenshot for the visible viewport or Capture full size screenshot for the scrollable page.
  6. Record the viewport, DPR, capture scope, browser version, zoom, and whether the run used emulation alongside the image.

Chrome describes Device mode as a collection of DevTools features for simulating mobile devices. Emulation is useful for layout checks, but it does not reproduce every behavior of a physical phone. Test on a real device when device-specific behavior matters. [Chrome DevTools Device Mode]

Automate DPR screenshots with Playwright

Set the viewport and device scale factor in the browser context before navigating. This ensures the page’s initial render sees the intended dimensions and emulated device density. The following complete Node.js example captures DPR 1 and DPR 2 outputs at the same viewport, both device-scale and CSS-scale, plus a full-page device-scale image.

import { chromium } from 'playwright';

const url = process.argv[2] ?? 'https://example.com';
const viewport = { width: 390, height: 844 };

const browser = await chromium.launch({ headless: true });
try {
  for (const dpr of [1, 2]) {
    const context = await browser.newContext({
      viewport,
      deviceScaleFactor: dpr,
    });
    const page = await context.newPage();
    await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
    await page.screenshot({ path: `page-dpr${dpr}-device.png`, scale: 'device' });
    await page.screenshot({ path: `page-dpr${dpr}-css.png`, scale: 'css' });
    if (dpr === 2) {
      await page.screenshot({ path: 'page-full-dpr2.png', fullPage: true, scale: 'device' });
    }
    await context.close();
  }
} finally {
  await browser.close();
}

Save as screenshot.mjs, install Playwright with npm install playwright, install its browser with npx playwright install chromium, then run node screenshot.mjs https://example.com. The code makes one context per DPR so each capture starts with the intended emulated characteristics.

Choose screenshot scale deliberately

  • deviceScaleFactor sets the emulated device density in the context.
  • scale: 'device' saves at device-pixel scale.
  • scale: 'css' saves one screenshot pixel per CSS pixel.
  • fullPage: true captures beyond the viewport. Omit it for the visible viewport.

Do not confuse the emulated DPR with screenshot output scale. To compare DPRs, hold viewport, screenshot scale, page state, and capture scope constant, then change only deviceScaleFactor. Playwright also supports element screenshots, image formats, animation controls, and injected styles for stabilizing dynamic pages. [Playwright screenshot options]

Use Puppeteer for automated captures

Puppeteer can emulate device characteristics through a page’s device metrics override and save page or element screenshots. This runnable example sets a fixed viewport and DPR, navigates, and captures the viewport. Install with npm install puppeteer, save as capture.cjs, then run node capture.cjs https://example.com 2.

const puppeteer = require('puppeteer');

(async () => {
  const url = process.argv[2] || 'https://example.com';
  const dpr = Number(process.argv[3] || 2);
  if (!Number.isFinite(dpr) || dpr <= 0) throw new Error('DPR must be a positive number');

  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 390, height: 844, deviceScaleFactor: dpr });
    await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
    await page.screenshot({ path: `page-dpr${dpr}.png` });
    const element = await page.$('main');
    if (element) await element.screenshot({ path: `main-dpr${dpr}.png` });
  } finally {
    await browser.close();
  }
})();

Puppeteer’s screenshot guide demonstrates page capture and navigation waits; choose a readiness condition based on the site. Network idle does not guarantee that lazy images, animations, or user-specific content are ready. [Puppeteer screenshots]

Make captures comparable

For visual comparisons, record and hold constant the following unless it is the variable under study:

  • Browser name and version, operating system, installed fonts, and headless or headed mode.
  • CSS viewport width and height, DPR, and page zoom.
  • Screenshot scale (CSS or device pixels) and scope (viewport, full page, or element).
  • Page state, authentication, locale, timezone, reduced-motion preferences, and readiness condition.
  • Animation behavior, dynamic timestamps, ads, and other changing content.

Page zoom changes devicePixelRatio; pinch zoom does not. Moving a browser window between displays with different pixel densities can also change DPR. Explicit emulation and stable capture settings help avoid accidental variation. Browser output can also differ by operating system, browser version, settings, hardware, power source, and headless mode, so keep the capture environment stable for regression comparisons. [MDN: devicePixelRatio] [Playwright visual comparisons]

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One request returns a screenshot or PDF; the API supports DPR through its device_scale_factor option, along with viewport controls. See the ScreenshotNeo API documentation for the available parameters.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d width=390 \
  -d height=844 \
  -d device_scale_factor=2 \
  -o shot.webp

Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. An MCP server lets AI agents use screenshot tools. 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.

Troubleshooting

Symptom Likely cause What to do
Image dimensions did not change when DPR changed. The screenshot is saved at CSS scale, or the tool’s output scale is independent of emulated DPR. In Playwright, compare scale: 'device' with scale: 'css'. Keep the scale consistent across runs.
Layout changed between DPR captures. Viewport dimensions changed along with DPR, or the site responds to another emulated device property. Set an explicit identical viewport in each context. Inspect window.innerWidth and window.devicePixelRatio in the page.
Screenshot is blurry or unexpectedly large. Output scale differs from expectation, or a high DPR multiplied both image dimensions. Choose CSS scale for CSS-pixel output. Use device scale when pixel density is required; account for approximately quadratic growth in pixel area.
Screenshot cuts off content. A viewport capture was used where full-page capture was intended, or the page has nested scrolling. Use full-page capture for document content. For nested scroll containers, handle that element’s scroll state explicitly.
Images are missing or the page is incomplete. Capture happened before images or client-rendered content were ready; lazy loading may require scrolling. Wait for a page-specific selector or readiness signal. For lazy content, scroll through the page before full-page capture and verify the result.
Captures differ despite matching DPR and viewport. Browser/OS differences, fonts, animation, dynamic content, page zoom, or display changes. Pin the browser and host environment, stabilize page state, disable or freeze animations where appropriate, and record zoom and emulation settings.
Playwright reports an unsupported screenshot option. The installed Playwright version may not support the option used by the example. Update the package and browser installation together, and consult the current screenshot API documentation for the installed version.
Navigation times out. The site keeps connections open or does not reach the selected load condition. Use a less restrictive navigation condition such as domcontentloaded, then wait for a meaningful selector or application-specific signal before capture.

Performance, reliability, and cost

Device-scale output can consume substantially more storage and transfer than CSS-scale output because the pixel count grows in both dimensions. Capture only the resolution and scope needed: full-page device-scale screenshots can be especially large. For repeatable pipelines, reuse browser processes where practical, but create a separate context for each DPR and close contexts after capture so settings do not leak between runs.

Reliability depends on page readiness and environmental consistency as much as on the screenshot call. A successful navigation does not prove that a single-page app finished rendering, that lazy-loaded images appeared, or that a page stopped animating. Use a page-specific readiness condition and preserve the browser, OS, fonts, viewport, DPR, zoom, and screenshot scale used for the baseline. Screenshot automation costs also include browser compute, image storage, and transfer; choose CSS-scale output when device-pixel detail is unnecessary.

FAQ

How do I check the DPR the page is receiving?

Evaluate window.devicePixelRatio in the page. In DevTools, the Console can run that expression; in Playwright, evaluate it with page.evaluate(() => window.devicePixelRatio).

Should I use CSS scale or device scale?

Use CSS scale when image dimensions should correspond to CSS pixels and remain independent of DPR. Use device scale when the output should preserve the emulated device-pixel density.

Does DPR 2 mean a screenshot is twice as large?

Each dimension is generally about twice as large for device-scale output at the same CSS viewport, so total pixel area is about four times as large. File size varies with image content and compression.

Does emulating a phone replace testing on a phone?

No. Emulation helps check layout and rendering conditions, but it does not reproduce every hardware, browser, or input behavior of an actual mobile device.