ScreenshotNeo

BlogHow-to

How to Schedule Mobile Website Screenshots for Visual Regression Testing

Build a repeatable mobile screenshot workflow with Playwright, CI schedules, stable baselines, and practical guidance for reviewing visual changes.

By the ScreenshotNeo team4 October 202610 min read

Schedule mobile website screenshot tests by running a browser-based visual test in CI: trigger it on pull requests or pushes for change review, and add a time-based job when you need periodic checks between code changes. Keep the browser and operating environment consistent with the environment used to create the baseline. Start with a few important mobile pages and states, then expand coverage when your audience, risks, or defects justify it.

This guide uses Playwright Test and GitHub Actions as a concrete, code-owned example. The same principles apply to other CI providers: the scheduler starts the job, while the browser test captures and compares the page. A scheduled screenshot run detects visual drift; it does not by itself determine whether a difference is a defect.

1. Decide what to capture and how to represent mobile

Begin with a small set of pages that represent important mobile journeys. For example, capture a landing page and a conversion state after the relevant interaction. Choose stable states that a test can reach repeatedly. Add further routes and states when they cover meaningful user paths, not just to increase the screenshot count.

Playwright device profiles emulate properties such as the user agent, screen size, viewport, and touch support. This is useful for repeatable mobile-sized coverage, but it is not equivalent to rendering in a physical phone browser. If physical-device behavior is a requirement, evaluate a service that captures on real mobile devices.

You can use a named Playwright device profile or specify an explicit viewport. A named profile is convenient when its emulated characteristics fit your target; an explicit viewport gives a simple, visible size choice. Avoid describing either option as proof that every real device behaves identically.

2. Create a Playwright mobile screenshot comparison

Install Playwright Test in the application repository and install its browser. The first screenshot comparison run creates reference images; later runs compare the rendered page with those references. Review and commit baseline images deliberately.

npm init playwright@latest
npx playwright install chromium

Create tests/mobile-visual.spec.ts:

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

// Keep this project and its browser configuration stable for baseline and CI runs.
test.use({
  viewport: { width: 390, height: 844 },
  deviceScaleFactor: 1,
  isMobile: true,
  hasTouch: true,
});

test('mobile landing page stays visually consistent', async ({ page }) => {
  await page.goto(process.env.BASE_URL ?? 'http://127.0.0.1:3000', {
    waitUntil: 'networkidle',
  });
  await page.getByRole('heading', { name: 'Welcome' }).waitFor();
  await expect(page).toHaveScreenshot('landing-mobile.png', {
    fullPage: true,
    animations: 'disabled',
  });
});

Replace the sample URL and heading with elements from your application. If your page has continuously active network requests, networkidle may never be a useful readiness signal; wait for a specific stable element or application state instead. Playwright supports screenshot assertions and stored references in its visual comparisons guide.

To use a device profile, configure a Playwright project with a profile from playwright.devices. For example:

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

export default defineConfig({
  testDir: './tests',
  projects: [
    {
      name: 'mobile-chromium',
      use: {
        ...devices['Pixel 5'],
        browserName: 'chromium',
      },
    },
  ],
});

Check the installed Playwright version for available profile names. The Playwright emulation documentation describes the device properties that profiles configure.

3. Create and maintain the baseline

  1. Run the test in the same controlled environment you plan to use in CI.
  2. Inspect the generated reference image and confirm that it represents the intended mobile state.
  3. Commit the reference image with the test and relevant application changes.
  4. When a later run reports a difference, inspect the new rendering and diff before updating the baseline.

Do not accept a baseline update just because a test failed. A change may be intentional, caused by a rendering environment change, or a genuine regression. Preserve the old reference until a reviewer understands the difference.

Playwright cautions that rendering can vary with the host operating system, browser version, settings, hardware, power source, headless mode, and other factors. Use the same runner image, browser version, fonts, and capture settings for baseline generation and scheduled comparisons wherever practical. See Playwright’s visual comparison guidance.

4. Run the suite in CI and schedule it

Run screenshot tests on pull requests or pushes so visual changes are reviewed with code changes. A separate scheduled workflow can catch drift caused by periodic deployments, third-party assets, or other changes that do not coincide with a pull request. There is no universally documented ideal schedule interval: choose one based on site risk, change rate, CI capacity, and how quickly you need to notice drift.

Example GitHub Actions workflow, saved as .github/workflows/mobile-visual.yml:

name: Mobile visual regression

on:
  pull_request:
  push:
    branches: [main]
  schedule:
    # Example cadence only; choose an interval that fits your release risk and CI capacity.
    - cron: '17 6 * * 1-5'
  workflow_dispatch:

jobs:
  screenshots:
    timeout-minutes: 20
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npm run build
      - run: npm run start &
      - run: npx playwright test
        env:
          BASE_URL: http://127.0.0.1:3000

Adapt the build and server commands to the application. In a real workflow, ensure the server is ready before the test starts; a dedicated start-and-wait action or a readiness command avoids a race between server startup and navigation. The cron expression is an example, not a recommended universal cadence. GitHub Actions supports scheduled workflows; Playwright’s CI guide covers running its tests in CI and recommends one worker in CI for stability and reproducibility.

Start with one worker to reduce scheduling variation and simplify diagnosis. If the suite becomes too slow, consider sharding across CI jobs while keeping each shard’s browser and operating environment consistent. Save test reports and failure artifacts where your CI setup permits, so reviewers can inspect failed comparisons.

5. Control noise and interpret differences

  • Wait for a meaningful state. Prefer a visible element or application-ready signal over an arbitrary sleep. A delay can help with known transitions, but it may still capture too early or waste time.
  • Stabilize changing content. Use deterministic test data where possible. Mask or hide areas such as rotating promotions, timestamps, randomized recommendations, or live counters when those pixels are not under test.
  • Handle animation deliberately. Disabling animations can make captures repeatable when motion is irrelevant. Keep animation enabled if the behavior itself is what the test covers.
  • Check fonts and assets. A missing font or late-loading image can alter layout across the whole screenshot. Ensure required assets load before capture.
  • Keep capture settings fixed. Viewport, device scale factor, browser version, color scheme, locale, and other settings can change rendered pixels. Record and hold the settings stable.
  • Review the changed region. A pixel diff is a signal relative to a reference, not a verdict. Check whether the change is intended and whether it affects the mobile experience.

Do not widen comparison tolerances to hide unexplained movement. First identify whether the cause is nondeterministic page content, a changed browser environment, or an actual interface change.

6. Pick tools based on capture needs

Option Capture model Useful when Consider
Playwright Test Code-owned screenshot assertions, references, and device emulation in your CI. You want to own tests, runners, and baseline review. Environment control, maintenance effort, browser coverage, and how reviewers handle baseline changes.
Chromatic with Playwright Playwright integration with hosted visual snapshots; its documentation covers responsive viewport configuration and mobile emulator capture. You want managed capture and hosted visual review. Integration fit, viewport needs, current plan limits, and service capabilities. The cited material does not establish current pricing.
BrowserStack Percy Visual tests across configured mobile browsers using real mobile devices. Physical mobile browser behavior is important to your coverage. Required device and browser coverage, workflow fit, and current plan limits. For mobile browsers, screenshot width is fixed by the device and a supplied width parameter is ignored.

These options do not have identical capture semantics. Chromatic’s cited material describes standardized browsers and mobile emulators; Percy documents real mobile device capture. Choose emulation for controlled, repeatable viewport coverage and real devices when physical-device behavior is central. Relevant documentation: Chromatic setup for Playwright, Chromatic snapshots, and Percy’s mobile browser visual testing.

7. Cost, runtime, and reliability

For a self-hosted Playwright workflow, the main operational costs are CI runner time, browser installation and maintenance, baseline storage, and reviewer time. More pages, states, browser projects, and devices mean more captures and longer runs. The research sources do not establish current prices for Chromatic or Percy, so check their current plan details directly before budgeting.

Keep the initial matrix small: a few important routes, a representative mobile viewport or profile, and stable states. Add coverage in response to observed defects or product requirements. If runtime grows, first remove redundant captures and make page readiness deterministic; then consider CI sharding. Playwright recommends one worker in CI for stability and reproducibility, while its CI guidance also describes sharding for parallel execution.

Reliability depends on repeatable inputs and environment. Pin dependencies and browser installation through the project lockfile and CI setup, use the same runner image where possible, and avoid comparing baselines created under materially different rendering conditions. A scheduled job detects changes only at its next run, so use pull request checks as well when pre-merge feedback matters.

8. Troubleshooting

Symptom Likely cause Fix
Screenshot differs on every run Dynamic content, animation, unstable data, late assets, or a changed capture environment. Stabilize test data and readiness, disable irrelevant animation, mask volatile regions, and keep browser and runner settings consistent.
Reference image is missing The baseline was never generated, is not committed, or is unavailable in the current checkout. Run the test in the intended baseline environment, inspect the generated image, then commit the reference.
Scheduled workflow starts but navigation fails The application server did not start, the URL is wrong, or the test raced server startup. Check build and server commands, verify the base URL from the runner, and add an explicit readiness check.
Test times out waiting for network idle Persistent connections or recurring requests prevent an idle network state. Wait for a stable page element or application-ready signal that matches the page under test.
Layout shifts despite the same viewport A font, image, or other resource loads late or is unavailable in CI. Wait for required resources and check runner logs and network failures; make fonts and assets available in the test environment.
Mobile emulation does not match a physical phone Emulation configures browser properties but does not reproduce all physical-device behavior. Use emulation for repeatable viewport checks; add real-device capture when hardware-specific behavior is required.
Many unrelated tests fail after a runner update Operating system, browser, fonts, or rendering settings changed relative to the references. Restore a consistent environment or review and regenerate baselines intentionally under the new standard environment.

Or skip the browser setup

For one-off captures or workflows where you do not want to maintain a browser runner, ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF. Its screenshot API can capture mobile-sized viewports, and its options include full-page capture with lazy images loaded, 12 device presets, and custom viewport sizes. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d viewport_width=390 \
  -d viewport_height=844 \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://stripe.com",
        "viewport_width": 390,
        "viewport_height": 844,
    },
    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',
  viewport_width: '390',
  viewport_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 Bun.write('shot.webp', res);

Replace the example URL and dimensions with your target page and viewport. Cookie banners are accepted and removed before the shot, along with known newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

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

FAQ

Should a scheduled job replace pull request screenshot tests?

No. A scheduled job checks at its scheduled time; pull request checks give feedback on proposed code changes before merge. Use both when you need both kinds of coverage.

How often should mobile screenshots run?

Choose a cadence based on release frequency, site risk, CI capacity, and how quickly you need to detect drift. The cited documentation does not prescribe a universal interval.

Does a mobile device profile prove the site works on a real phone?

No. It emulates selected browser and device properties. Use real-device coverage when physical hardware behavior is part of the requirement.

Should every mobile page be in the visual suite?

Start with representative, high-value routes and states. Expand when additional coverage addresses a concrete user path, risk, or defect.

When should a baseline be updated?

After a reviewer confirms that the changed rendering is intentional and the new reference matches the intended interface.