ScreenshotNeo

BlogHow-to

How to Monitor a Website for Visual Changes on Mobile and Desktop Viewports

Build repeatable mobile and desktop screenshot checks with Playwright, review visual diffs against approved baselines, and understand hosted alternatives.

By the ScreenshotNeo team4 October 20267 min read

To monitor a website for visual changes on mobile and desktop, capture the same pages and interaction states at each chosen viewport, compare each screenshot with an approved baseline, and review every difference before updating that baseline. Playwright Test provides screenshot assertions with toHaveScreenshot(). Keep capture conditions consistent so rendering noise does not obscure real changes.

1. Choose what to monitor

Start with a small set of important pages and states. A useful suite might cover the home page, a product detail page, an open navigation menu, and a key checkout step. Add states where responsive layout or content changes materially. Avoid capturing every route by default: a focused set is easier to maintain and review.

Choose viewport widths that exercise your actual responsive layouts and breakpoints. A narrow mobile viewport and a desktop viewport are a practical starting point, but the right dimensions depend on the site. A screenshot at one width does not cover the behavior at another width.

2. Set up Playwright screenshot comparisons

Install Playwright Test and its browser binaries in your project. The following example defines separate desktop and mobile projects and checks the same page in each. The first run creates reference screenshots; subsequent runs compare against them.

npm init playwright@latest

Use a configuration like this in playwright.config.ts:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  projects: [
    {
      name: 'desktop-chromium',
      use: { browserName: 'chromium', viewport: { width: 1440, height: 900 } },
    },
    {
      name: 'mobile-chromium',
      use: {
        browserName: 'chromium',
        viewport: { width: 390, height: 844 },
        isMobile: true,
        hasTouch: true,
      },
    },
  ],
});

Create tests/home.visual.spec.ts:

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

test('home page visual baseline', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000', { waitUntil: 'networkidle' });
  await expect(page).toHaveScreenshot('home.png', { fullPage: true });
});

Start the application at the configured address, then generate the initial baseline with:

npx playwright test tests/home.visual.spec.ts --update-snapshots

Commit the generated reference screenshots with the test. On later runs, omit --update-snapshots so Playwright reports differences instead of silently replacing the approved reference. Review the diff first; update snapshots only when the visual change is intentional.

Capture an interaction state

For menus and other interactive elements, establish the state before taking the screenshot. Prefer accessible locators and deterministic test data.

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

test('mobile navigation open', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000');
  await page.getByRole('button', { name: 'Open menu' }).click();
  await expect(page.getByRole('navigation')).toBeVisible();
  await expect(page).toHaveScreenshot('home-mobile-menu-open.png');
});

3. Make captures repeatable

A visual comparison is only useful when the page is in a known state. Control the inputs that can change pixels between runs:

  • Use stable test accounts, fixtures, and seeded data. Avoid timestamps, random IDs, rotating banners, and live inventory in screenshot regions.
  • Wait for the page content that matters. If the app uses asynchronous rendering, wait for a specific locator or application-ready signal instead of relying only on a fixed delay.
  • Disable or freeze animations and transitions for visual checks where motion is not the thing being tested. Make this part of the test setup consistently.
  • Keep browser version, operating system, fonts, device scale settings, and headless configuration consistent between baseline creation and comparison.
  • Use the same color scheme, locale, timezone, and test data each run when these affect displayed content.

Playwright notes that screenshot output may vary with the host operating system, browser version, browser settings, hardware, power source, and headless mode. A baseline created on one environment can therefore produce noisy differences in another. Run baseline updates and comparisons in the same controlled CI image or developer environment. See the Playwright visual comparisons documentation.

4. Run checks in development and CI

Run the visual suite locally when changing layout or styles, and in CI for changes that should not introduce unreviewed visual regressions. A typical CI sequence is:

  1. Install dependencies and the pinned Playwright browser version.
  2. Start the application with deterministic test configuration.
  3. Run the visual tests for the configured desktop and mobile projects.
  4. Inspect failed screenshots and diffs in the test artifacts.
  5. Update and commit baselines only after a reviewer accepts the visual change.

When diagnosing a failure, compare the actual screenshot, expected baseline, and diff. A failed assertion is a review signal, not proof that the application is wrong: it may reflect an intended design change or an unstable capture condition.

5. Configure viewports and device emulation

Playwright projects can use explicit viewport dimensions, and Playwright also provides device parameter presets for browser emulation. Use a preset when its device characteristics match the scenario you want to cover; otherwise specify the viewport and relevant settings directly. Emulated mobile dimensions and touch behavior are useful responsive checks, but they do not establish that the page has been tested on a physical iOS or Android device. See Playwright device emulation.

For hosted workflows, Chromatic documents viewport configuration globally or at test level for Playwright and other integrations. Percy supports responsive testing by supplying widths; its documentation says each responsive width counts as a separate screenshot toward monthly screenshot usage. These are workflow details, not a universal recommendation: choose repository-managed baselines or a hosted review flow based on your team’s needs. Chromatic viewport configuration, Chromatic with Playwright, and Percy responsive testing describe their respective approaches.

6. Understand the options

Approach Viewport handling Review and baseline workflow Practical consideration
Playwright screenshot comparisons Browser projects, explicit viewport settings, or device emulation Reference screenshots follow the project’s snapshot workflow; update references after review Keep rendering environment consistent to reduce noise
Chromatic Configure viewports in supported integrations, including Playwright Hosted snapshots and visual review workflow Its FAQ says smaller viewport checks are not iOS or Android physical-device tests
Percy Provide responsive widths for snapshots Hosted build results and responsive comparisons Each configured responsive width counts as a screenshot toward monthly usage

Sources: Playwright screenshot comparisons, Playwright emulation, Chromatic Playwright workflow, Chromatic viewports, Chromatic mobile FAQ, and Percy responsive testing.

7. Troubleshooting common failures

Symptom Likely cause Fix
Many pixels differ on an unchanged page Browser, OS, fonts, hardware, or rendering mode differs from the baseline environment Run both baseline updates and comparisons in a consistent environment and pin the browser version
Only one viewport fails A breakpoint-specific layout, overflow, or mobile navigation state changed Open the actual, expected, and diff images for that project; confirm the configured dimensions match the intended viewport
Screenshot is blank or missing content Capture began before the relevant app content loaded, or navigation did not reach the expected page Assert a page-specific locator is visible before capture and verify the navigation URL and test server readiness
Text or images shift between runs Fonts or remote assets load inconsistently, or dynamic content changes Use stable assets and test data; wait for the relevant content and font readiness before capture
Menu screenshot shows the closed state The interaction did not complete or the locator targeted the wrong control Use a role-based locator, perform the action, and assert the menu is visible before taking the screenshot
Baseline updates hide an unexpected change Snapshots were updated before reviewing the diff Restore the approved references, rerun without update mode, review the diff, and update only intentional changes

8. Performance, reliability, and cost

Capture work grows with the number of pages, states, viewport projects, and browsers. Keep the monitored set aligned with important user journeys, and add coverage where a particular responsive layout or state is at risk. Full-page captures include more content and can take longer to render and compare than a focused viewport capture; use the smallest capture that answers the check.

Reliability comes from repeatability: stable inputs, explicit readiness conditions, and the same rendering environment for baseline and comparison. Hosted tools can provide capture and review workflows, but the cited documentation does not establish a current pricing comparison or a universal value winner. For Percy, account for its documented per-width screenshot usage. Check each service’s current terms before budgeting.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It can capture a page at a selected viewport and return an image or PDF; see the API documentation. This is useful for repeatable captures, but it does not replace baseline storage and visual-diff review in the Playwright workflow above.

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 -o mobile.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com", "width": 390, "height": 844},
    timeout=90,
)
open("mobile.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  width: '390',
  height: '844',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('mobile.webp', Buffer.from(await res.arrayBuffer())));

Change width and height for each viewport you need to capture. ScreenshotNeo removes known cookie and consent banners, newsletter popups, and chat widgets before capture, with each step switchable. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and responses identify page verdict and billing status in headers. Its MCP server exposes screenshot tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does a mobile viewport screenshot mean the site was tested on a phone?

No. A configured narrow viewport or emulated device checks responsive rendering in a browser context. It is distinct from testing on a physical mobile device.

Should every visual difference fail CI?

It should prompt review. Accept and update a baseline when the difference is intended; investigate when it is unexpected or caused by unstable rendering.

How many viewport widths should I monitor?

Use widths that exercise the breakpoints and layouts your site relies on. The appropriate set is site-specific; adding a width creates another capture and review case.