How to Compare Mobile Website Screenshots Across iPhone Screen Sizes
Compare iPhone layouts by CSS viewport width, repeatable page state, and reviewed screenshot baselines. Here is a practical Safari and Playwright workflow.
To compare a website across iPhone sizes, capture the same route and page state at a small set of CSS viewport widths, then compare each capture with a baseline made at that same width. Include widths around your CSS breakpoints. Use Safari Responsive Design Mode for quick manual checks, or Playwright screenshot assertions for repeatable regression checks. Treat an emulated viewport as a useful layout check, not proof of identical behavior on a physical iPhone.
1. Compare CSS viewport widths, not image dimensions
Responsive CSS responds to the browser viewport. iPhone specifications also list physical pixel dimensions and a display scale factor; those hardware pixels are not the same thing as CSS viewport dimensions. For example, Apple lists the iPhone 13 mini at 360 × 780 points and 1080 × 2340 pixels at 3x, the iPhone 16 at 393 × 852 points and 1179 × 2556 pixels at 3x, the iPhone 16 Plus at 430 × 932 points and 1290 × 2796 pixels at 3x, and the iPhone 17 Pro Max at 440 × 956 points and 1320 × 2868 pixels at 3x. Check Apple’s current device dimensions table for the model you need. In automation, set the viewport explicitly; do not infer it from the PNG’s pixel dimensions.
A screenshot may have more output pixels than CSS pixels when device scale factor is greater than one. Keep the viewport and scale factor fixed between baseline and comparison runs so you are comparing like with like.
2. Pick a useful iPhone width matrix
You rarely need a capture for every model name. Choose representative widths from the range your product supports, and add widths immediately below and above each breakpoint that changes a meaningful layout. A breakpoint-centered matrix catches transitions such as navigation collapsing, columns stacking, cards resizing, and sticky controls moving.
| Capture | Example viewport width | What it helps reveal |
|---|---|---|
| Narrow layout | 360 CSS px | Overflow, cramped controls, and long text wrapping |
| Common middle width | 393 CSS px | A representative modern iPhone layout |
| Wide phone layout | 430–440 CSS px | Unused space, stretched cards, and alignment issues |
| Just below a breakpoint | Your breakpoint minus 1 px | The layout immediately before a media query takes effect |
| Just above a breakpoint | Your breakpoint plus 1 px | The layout immediately after the transition |
The named widths are practical sample points, not a required universal device list. Use the actual breakpoints and supported range of your site. If landscape matters, create a separate landscape set; orientation changes both width and height.
3. Make captures comparable
Before comparing pixels, control the inputs. Each capture should use the same route, content, interaction state, orientation, browser project, and capture settings. A baseline is only useful when it represents the same conditions as the new capture.
- Use the same URL and wait for the same page-ready condition.
- Set viewport width and height explicitly for every target.
- Keep browser engine, browser version, operating system, fonts, and device scale factor consistent.
- Put the page in the same state: signed-in status, selected tab, open menu, consent state, and scroll position.
- Stabilize changing content such as timestamps, carousels, ads, and animation, or exclude it from the comparison deliberately.
- Save and review one baseline per viewport. A narrow layout and wide layout should not share a reference image.
Check that the page has a responsive viewport declaration, commonly <meta name="viewport" content="width=device-width, initial-scale=1">. Apple’s archived Safari guidance discusses width=device-width for iOS web apps; for a general responsive site, validate the actual viewport behavior rather than copying a device-specific width. See the archived Safari viewport documentation.
4. Inspect layouts manually in Safari
Safari Responsive Design Mode is suited to hands-on inspection and breakpoint exploration. Apple describes it as a way to test media queries and dynamic styles across screen sizes, with viewport presets and controls for viewport dimensions and display pixel ratio. See Apple’s Responsive Design Mode documentation.
- Open the page in Safari and enable the Develop menu in Safari settings if it is not visible.
- Choose Develop → Enter Responsive Design Mode.
- Select or enter a target viewport, and inspect the same route and interaction state at each width.
- Resize around each layout transition. Record the last width before the change and the first width after it.
- Use Web Inspector to identify the element or media query responsible for an unexpected change.
- Repeat in landscape if that orientation is part of your support target.
This is a quick visual workflow, but the reviewer drives it manually. For automated, versioned comparisons, use screenshot baselines.
5. Automate comparisons with Playwright
Playwright Test’s toHaveScreenshot() creates reference screenshots on its initial run and compares later captures against them. Its device emulation can configure viewport, screen size, user agent, and touch capability. Keep a stable browser and host environment: Playwright cautions that rendering can vary with operating system, browser version and settings, hardware, power source, and headless mode. A pixel difference is a review signal, not automatic proof of a defect. See the official visual comparisons and emulation documentation.
Install and create a runnable test
npm init -y
npm install --save-dev @playwright/test
npx playwright install chromium
Save the following as tests/iphone-screenshots.spec.ts. Replace the example URL and breakpoint widths with your site values.
import { test, expect } from '@playwright/test';
const targets = [
{ name: 'narrow-360', width: 360, height: 780 },
{ name: 'middle-393', width: 393, height: 852 },
{ name: 'wide-430', width: 430, height: 932 },
// Example only: replace 767/769 with the edges of your own breakpoint.
{ name: 'below-breakpoint', width: 767, height: 900 },
{ name: 'above-breakpoint', width: 769, height: 900 },
];
test.describe('responsive iPhone viewport screenshots', () => {
for (const target of targets) {
test(target.name, async ({ page }) => {
await page.setViewportSize({ width: target.width, height: target.height });
await page.goto('https://example.com/products', { waitUntil: 'networkidle' });
// Prefer an app-specific ready marker if network traffic never becomes idle.
// await page.getByRole('heading', { name: 'Products' }).waitFor();
// Reduce motion so transitions do not land at different animation frames.
await page.emulateMedia({ reducedMotion: 'reduce' });
await expect(page).toHaveScreenshot(`${target.name}.png`, {
fullPage: true,
animations: 'disabled',
});
});
}
});
Run it once to create reference screenshots, review those files, and commit the approved references with the test. Then run the same command on later changes:
npx playwright test tests/iphone-screenshots.spec.ts
When a test reports a difference, inspect the actual and expected images before accepting a new baseline. If a design change is intentional, update only after review:
npx playwright test tests/iphone-screenshots.spec.ts --update-snapshots
Do not update baselines simply to make a failing run pass; that can record a layout regression as the new expected result.
Useful Playwright settings
| Setting | When to use it | Effect or caution |
|---|---|---|
viewport |
Every responsive target | Sets the CSS viewport in width and height. |
deviceScaleFactor |
When checking high-density raster output | Controls output scale; keep it fixed for a given baseline. |
isMobile and hasTouch |
When mobile browser behavior and touch matter | Viewport-only checks do not reproduce every mobile interaction behavior. |
devices['iPhone ...'] |
When a named Playwright device profile is useful | Profiles include emulated parameters; Playwright notes they assume a platform and user agent. |
fullPage |
When below-the-fold layout matters | Captures the full page, but very long pages produce large images and may exercise lazy-loading differently. |
animations: 'disabled' |
When motion creates unstable pixels | Reduces animation variance; still ensure data and page state are stable. |
maxDiffPixels |
When a small amount of rendering noise is acceptable | Sets a tolerance. Keep it low enough that meaningful shifts still fail. |
stylePath |
When known volatile elements must be hidden for a deterministic test | Applies a stylesheet during capture; do not hide elements whose layout is what you intend to test. |
Playwright’s snapshot documentation describes the comparison options, including maxDiffPixels and stylePath. Keep platform and browser project names stable because snapshots are associated with the browser and platform configuration.
6. Read the differences, then decide what to fix
Compare the same viewport against its own baseline first. Then compare widths side by side to understand how the responsive design changes. Look for horizontal overflow, clipped controls, unexpected wrapping, gaps that grow too large, sticky elements covering content, and breakpoint transitions that leave an awkward in-between state. A single full-page image is useful for structure; a focused element screenshot can make small details easier to inspect.
Do not expect different widths to be pixel-identical: responsive design intentionally changes composition. The question is whether each width follows the intended layout rules and whether any change from that width’s baseline is acceptable.
7. Choose the right validation method
| Method | Best for | Tradeoff |
|---|---|---|
| Safari Responsive Design Mode | Quick manual inspection and finding breakpoints | Human-driven; it does not create automated baseline history by itself. |
| Playwright screenshot assertions | Repeatable visual regression checks in development or CI | Needs a consistent browser and host environment, plus reviewed baselines. |
| Physical iPhone validation | Investigating behavior that may depend on real device or browser conditions | Requires device access and coverage effort. Emulation fidelity varies by behavior and is not quantified here. |
Emulation is a practical way to cover layout widths; use a physical device when a bug appears tied to actual iPhone browser or device behavior. Neither a screenshot nor one browser run replaces functional and accessibility checks.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Mobile layout appears zoomed out or desktop-sized | The page lacks an appropriate viewport meta tag, or mobile emulation is not enabled where needed. | Check the document’s viewport declaration and confirm the test context’s mobile settings. |
| Screenshot dimensions do not match the CSS width | Image pixels include device scale factor, while responsive CSS uses viewport units. | Set viewport explicitly and record scale factor separately; do not derive CSS width from image dimensions. |
| Snapshots fail on a different developer machine or CI runner | OS, browser version, fonts, hardware, or headless rendering differs. | Generate and compare in the same environment; use a consistent CI image and browser install. |
| Images or page sections are missing | Capture began before app content or lazy-loaded media was ready. | Wait for an app-specific ready marker, scroll or otherwise trigger lazy content, and verify the page state before capture. |
| Every run has small scattered differences | Animations, timestamps, randomized content, ads, or rotating content vary. | Disable motion, freeze or fixture dynamic data where possible, and mask only content outside the test’s purpose. |
| Breakpoint-edge screenshots look unexpectedly alike | The chosen widths may not straddle the actual CSS breakpoint, or the tested route does not use that rule. | Inspect the CSS and capture at one pixel below and above the real media-query boundary. |
| Baseline update hides a real bug | Snapshots were refreshed without inspecting the diff. | Review actual-versus-expected images and approve only intentional visual changes. |
| Emulated view looks right but a real iPhone differs | Emulation checks viewport layout but does not guarantee the full identity of a physical browser/device. | Reproduce on the affected physical device and browser when the issue depends on device-specific behavior. |
9. Performance, reliability, and cost
Screenshot work scales with the number of routes, page states, viewport targets, browser projects, and baseline updates. Start with the key routes and breakpoint edges rather than capturing every model at every possible width. Keep screenshots focused when full-page output is not needed, and run broader matrices when changes affect shared responsive components. This keeps review effort manageable without treating a smaller matrix as complete device certification.
For reliable checks, keep the browser version and host environment consistent, wait for meaningful page readiness, stabilize dynamic content, and review snapshots as code changes. A larger pixel tolerance may reduce noise but can also let real layout shifts pass. There is no universal tolerance that fits every site; choose one based on the rendering stability and the size of changes that matter.
Playwright is an open-source browser automation framework; the practical costs are the compute and maintenance time for the browser runs, environment consistency, and baseline review. Physical-device checks add access and coordination effort. The sources cited here do not establish a universal cost or runtime benchmark.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a URL; its API documentation covers the available options, including 12 device presets and custom viewports. For exact width comparisons, request the same route at each target viewport and retain the outputs with your baseline set.
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}`);
Adapt the target URL and viewport options for the route and width you are capturing. 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.
Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.
FAQ
Should I compare iPhone screenshots at physical pixel resolution?
For responsive layout, compare CSS viewport widths. Physical pixel resolution and scale factor describe screenshot density, not the media-query width.
Do I need a baseline for every iPhone model?
No. Choose widths across your supported range and around the breakpoints that change your layout. Add model-specific checks when a requirement depends on that model.
Can automated screenshots prove the page works on a real iPhone?
No. They provide repeatable visual coverage at configured conditions. Investigate device-dependent behavior on the affected physical device.
When should I update a screenshot baseline?
After reviewing the visual difference and confirming it represents an intentional change. Keep the updated reference with the code change that caused it.


