ScreenshotNeo

BlogHow-to

How to Test a Responsive Website with Screenshots at Common Phone Breakpoints

Test responsive layouts at your site’s actual CSS breakpoints, capture consistent screenshots, and compare changes manually or with Playwright.

By the ScreenshotNeo team4 October 202610 min read

To test a responsive website with screenshots, capture the same page at representative phone widths and on both sides of the site’s own CSS media-query boundaries. A useful starting set is 320, 375, and 425 CSS pixels: Chrome DevTools labels these Mobile S, Mobile M, and Mobile L presets. They are convenient samples, not universal breakpoint standards. The breakpoints in your stylesheet are the authoritative boundaries to test.

For a quick manual check, use Chrome DevTools Device Mode. For repeatable captures and visual regression checks, configure Playwright projects or viewport sizes and compare screenshots with reviewed baselines. Keep the page state and rendering environment consistent between runs.

1. Choose useful phone widths

Start with the Chrome DevTools viewport presets, then add the widths needed to exercise your actual CSS. If a layout changes at 400px, for example, capture at 399px and 400px or 401px. Testing only at a familiar preset can miss a broken transition between samples.

Capture Example width What it helps check
Narrow phone sample 320 CSS px Constrained layouts, text wrapping, and controls that need to fit in a narrow viewport.
Typical preset sample 375 CSS px A middle sample for reviewing the phone layout.
Wider phone sample 425 CSS px How the layout uses additional phone width.
Just below a site breakpoint Breakpoint minus 1px The layout before the media query boundary.
At or just above a site breakpoint Breakpoint or breakpoint plus 1px Whether the new layout activates cleanly.

The 320, 375, and 425px values correspond to Chrome DevTools’ Mobile S, Mobile M, and Mobile L presets. They are tool presets, not a claim about the most common phones or a prescribed set of CSS breakpoints. Record the viewport height too: width is usually the key dimension for width-based media queries, while height affects what a viewport screenshot shows.

2. Find the breakpoints your page actually uses

  1. Inspect the page’s CSS for @media rules, including both min-width and max-width conditions.
  2. Open the page in Chrome, open DevTools, and enable Device Mode.
  3. Switch to Responsive Viewport Mode and enter a width and height, or select a device preset.
  4. Enable “Show media queries” to see breakpoint boundaries, then click near each boundary to inspect the layout on either side.
  5. Write down the page route and the widths you intend to capture so later runs use the same matrix.

Chrome describes Device Mode as a first-order approximation of how a page looks and feels on a mobile device. It is useful for first-pass layout review, but it does not run the site on a physical phone. Confirm important behavior on real target devices when hardware or mobile-browser fidelity matters. See the Chrome DevTools Device Mode documentation.

3. Capture a consistent manual screenshot set

  1. Open the same route and set a specific viewport width and height.
  2. Wait for the page’s fonts, images, and other content to reach the state you want to review.
  3. Set the same login state, content, menu or dialog state, and scroll position used for the other captures.
  4. Capture a viewport screenshot when you are checking a visible interaction or layout detail. Capture a full-size screenshot when you need to inspect the whole vertical page.
  5. Repeat the exact setup at every sample width and on both sides of each important breakpoint.
  6. Name files with enough context to identify the run, such as pricing-375x812-chrome-rev42.png.

Viewport screenshots are useful for checking what a visitor sees without scrolling. Full-page screenshots help review vertical flow and content that falls below the fold; use them alongside viewport shots when a layout issue might appear farther down the page.

4. Automate responsive screenshots with Playwright

For a repeatable manual script, use Playwright’s browser API to visit the route at explicit viewport sizes and save a screenshot for each size. This example uses Node.js and Chromium. Install Playwright, install its Chromium browser, save the script as responsive-shots.mjs, set TARGET_URL, and run it.

npm install --save-dev playwright
npx playwright install chromium
import { chromium } from 'playwright';

const target = process.env.TARGET_URL;
if (!target) throw new Error('Set TARGET_URL to the page to capture.');

const widths = [320, 375, 425];
const height = 812;
const browser = await chromium.launch({ headless: true });

try {
  const page = await browser.newPage({ deviceScaleFactor: 1 });
  for (const width of widths) {
    await page.setViewportSize({ width, height });
    await page.goto(target, { waitUntil: 'networkidle', timeout: 60_000 });
    await page.screenshot({
      path: `responsive-${width}x${height}.png`,
      fullPage: true,
      animations: 'disabled'
    });
  }
} finally {
  await browser.close();
}

Run it with TARGET_URL=https://example.com/pricing node responsive-shots.mjs. Replace the sample widths with your test matrix. To check a breakpoint at 400px, for example, add 399 and 400 or 401. This script takes fresh page captures at each width, which also helps avoid carrying page state from one viewport to another.

networkidle can be unsuitable for pages that keep network connections open or continuously fetch data. In that case, wait for a meaningful selector or a known application-ready signal instead of waiting for all network activity to stop. If the site needs authentication, provide a controlled test account or reuse a Playwright storage state securely; do not commit credentials or session files to source control.

Use Playwright Test for visual comparisons

When captures belong in a test suite, Playwright Test can compare screenshots against approved baselines. A small example uses a test for each width:

import { test, expect } from '@playwright/test';

for (const width of [320, 375, 425, 399, 400]) {
  test(`pricing layout at ${width}px`, async ({ page }) => {
    await page.setViewportSize({ width, height: 812 });
    await page.goto('https://example.com/pricing');
    await expect(page).toHaveScreenshot(`pricing-${width}.png`, {
      fullPage: true,
      animations: 'disabled'
    });
  });
}

Configure the URL and widths for your application. The first run creates candidate screenshots; review them and accept only intentional changes as new baselines. Later runs compare against those files. Playwright’s screenshot guidance explains baseline comparisons and their environment sensitivity in the visual comparisons documentation; device and viewport configuration is covered in Playwright emulation.

5. Review the screenshots for layout failures

At each width, inspect the same areas and interactions. These are practical review checks rather than a universal pass/fail standard:

  • Horizontal overflow or an unexpected horizontal scrollbar.
  • Text, images, or controls clipped by the viewport or their containers.
  • Overlapping elements, especially fixed headers, dialogs, and floating controls.
  • Navigation that wraps unexpectedly or becomes difficult to use.
  • Text that becomes hard to read because of wrapping, spacing, or sizing changes.
  • Buttons, form fields, or other controls that no longer fit or are difficult to reach.
  • Large blank areas or missing content caused by a layout rule activating at the wrong width.

When an issue appears, compare the captures immediately below and above the relevant boundary. That helps distinguish a breakpoint transition problem from a layout that is consistently broken at all phone widths.

6. Keep visual regression results reliable

A screenshot diff is useful evidence, but rendering can change with the operating system, browser version, browser settings, hardware, power state, and headless mode. Playwright recommends controlling the environment used to produce screenshots. Keep these details stable for both baseline creation and comparison:

  • Browser engine and version, operating system, and test runner version.
  • Viewport width and height, device scale factor, and screenshot mode.
  • Route, test data, account state, scroll position, and open UI state.
  • Font availability and readiness, animation behavior, and timing of dynamic content.
  • Locale, timezone, permissions, and any browser settings that affect rendering.

Review visual changes before updating baselines. A changed image may reflect an intentional design update, a changed test environment, dynamic page content, or a real regression. The diff alone does not decide which one it is.

7. Choose the right capture method

Method Best for Trade-off
Chrome DevTools Device Mode Exploratory checks, entering custom dimensions, finding media-query boundaries, and manual captures. Convenient desktop-side simulation; it is not a physical phone run.
Playwright viewport or device projects Repeatable captures and visual comparisons in an automated workflow. Requires test setup and controlled screenshot baselines; output can vary by environment.
Real target phones with remote debugging Confirming behavior on the actual mobile browser and hardware. Requires access to the target devices and more hands-on work.
ScreenshotNeo Capturing screenshots through an API or an MCP server for AI agents. Uses an API request or MCP client rather than your own browser setup; see the product documentation for request options.

This is a comparison of documented uses and trade-offs, not a benchmark of speed, price, or coverage. Emulation is a practical first pass; check important flows on the actual target devices.

8. Or skip the browser setup

For an API capture, set the viewport width and height in the request. The following examples capture the same page at 375 by 812 CSS pixels. ScreenshotNeo’s API documentation lists the request options, including device and viewport settings.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d width=375 \
  -d height=812 \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://stripe.com",
        "width": 375,
        "height": 812,
    },
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  width: '375',
  height: '812'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Repeat the call with the widths in your matrix and save each response under a filename that records its viewport and revision. ScreenshotNeo accepts common screenshot API parameter names, which can simplify switching an existing capture request. Its clean-shot processing accepts cookie and consent banners 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 cost nothing, and each response includes X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

ScreenshotNeo includes 1,000 screenshots per month on the free plan with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan. Sign up for free and capture up to 1,000 screenshots a month with no card.

9. Troubleshooting responsive screenshot tests

Symptom Likely cause What to do
The page looks correct at presets but breaks on a real phone width. The test matrix skipped a site-specific media-query boundary or a width between samples. Inspect the CSS and add captures immediately below and at or above each relevant breakpoint.
Captures differ on every run. Dynamic content, animation, late-loading fonts, or inconsistent test state. Stabilize test data and login state, disable animations where appropriate, and wait for a meaningful ready condition.
The Playwright script times out at networkidle. The page keeps connections open or continues background requests. Wait for a specific page element or application-ready signal instead of network idle.
Many pixels differ after a small code change. Browser, operating system, rendering settings, or device scale factor changed. Compare environment metadata with the baseline run and restore a consistent setup before judging the diff.
Text wraps or clips differently from the expected baseline. A font is missing or was not ready when the screenshot was taken. Ensure the same fonts are installed and loaded before capture, then regenerate a baseline only if the visual change is intentional.
A full-page capture misses content that appears after scrolling. Lazy-loaded content may not have loaded before the screenshot. Scroll through the page or wait for the content to load before capturing; verify the resulting full-page image.
A screenshot shows a bot check, blank page, or failed navigation. The target site did not provide the expected page to the capture session. Check the URL, access requirements, and page response. With ScreenshotNeo, inspect X-Page-Verdict and X-Billed to identify the response outcome.
The image dimensions do not match the intended phone test. The request used a device preset or scale setting that changes output dimensions. Set explicit width and height, check device scale settings, and consult the capture tool’s options.

10. Performance, reliability, and cost

For local Playwright runs, each width requires a page navigation and screenshot. Keep the matrix focused on known breakpoints and representative samples, then add widths when a layout risk or change calls for them. Reuse one browser process for a batch of widths, but create a fresh page or reset application state when isolation matters.

For reliable comparisons, use stable test data and a consistent browser environment. Avoid accepting a new screenshot baseline automatically: inspect the change first. Emulated viewports are efficient for a first pass, while real-device checks are useful where browser or hardware behavior may differ.

ScreenshotNeo pricing is 1,000 shots per month free with no card; Starter is $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 on every plan. Clean shots are billed; bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Review the response billing headers for each capture.

FAQ

Are 320px, 375px, and 425px required breakpoints?

No. They are Chrome DevTools Mobile S, M, and L viewport presets. Test the breakpoints your stylesheet actually defines and use presets as additional samples.

Should I use viewport or full-page screenshots?

Use viewport captures for visible layout and interaction details. Use full-page captures to review the vertical page flow, and use both when you need to check both kinds of behavior.

Can desktop emulation replace testing on a phone?

It is useful for an initial responsive layout pass, but it does not run on physical phone hardware. Check high-impact flows on the actual target devices when fidelity matters.

Why can visual snapshots change without a CSS change?

Rendering depends on the browser and operating environment, settings, hardware, headless mode, and page content. Keep the screenshot environment stable and investigate diffs before updating baselines.