ScreenshotNeo

BlogGuides

Cross-Browser Compatibility Testing: A Practical Guide

Build a focused browser test matrix, automate critical workflows with Playwright, and know when emulation or real-device checks are needed.

By the ScreenshotNeo team4 October 202610 min read

Cross-browser compatibility testing checks that a site or web app works across the browsers, operating systems, and devices its audience uses. Start with audience data and product risk, define a supported-browser policy, automate a small set of important workflows across browser engines, then add targeted real-platform and accessibility checks. No team can test every browser, device, operating system, and version combination; the goal is reliable coverage of the combinations that matter most.

MDN Web Docs puts the selection principle simply: “Since you can’t test every combination of browser and device, it’s enough that you ensure your site works on the most important ones.” Choose those combinations based on the target audience. MDN’s cross-browser testing strategy discusses this audience-based approach.

1. Define which browsers and devices you support

Write down a support policy before building a test matrix. Use your product analytics, contractual requirements, customer reports, and the risk of each workflow. Consider browser family, operating system, desktop or mobile class, and any required browser version boundary. Do not assume one universal browser list or market-share figure applies to every audience.

Prioritize extra coverage for high-impact areas, such as checkout and account access; pages that rely on browser-specific APIs; media playback; complex responsive layouts; and combinations associated with customer reports. Record unsupported combinations and the reason, so support decisions are explicit and reviewable.

2. Build a practical browser test matrix

There are too many combinations of browser, device, operating system, and version to test exhaustively. Use tiers to spend effort where failure matters most:

Tier Coverage Typical checks
Critical Most important audience combinations and risky platforms Core user journeys, responsive layouts, key browser-specific behavior, keyboard access
Smoke Other supported combinations Page loads, navigation works, primary forms submit, no obvious layout breakage
Targeted Known issues or platform-specific capabilities Media, permissions, codecs, touch behavior, or a reported defect on a representative environment

Keep the matrix small enough to run and maintain. A useful matrix identifies each target, its priority, the tests it runs, and whether the environment is emulated or real. Review the matrix when audience patterns, product risk, or support commitments change.

3. Automate core workflows with Playwright

Playwright can run tests in Chromium, Firefox, and WebKit projects, and can also target branded Chrome and Edge channels and mobile device configurations. Its documentation distinguishes browser engine projects from branded browser channels. The default installation includes Chromium, Firefox, and WebKit; install the browser binaries that correspond to your Playwright version. Playwright browser documentation and test projects describe the available targets.

Install and configure a multi-browser project

npm init playwright@latest
npx playwright install

For an existing project, install the matching browser binaries again whenever you update Playwright. A minimal playwright.config.ts might look like this:

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

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 1 : 0,
  reporter: process.env.CI ? 'github' : 'list',
  use: {
    baseURL: 'http://127.0.0.1:3000',
    trace: 'retain-on-failure',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    {
      name: 'mobile-chromium',
      use: { ...devices['Pixel 7'] },
    },
  ],
  webServer: {
    command: 'npm run start -- --port 3000',
    url: 'http://127.0.0.1:3000',
    reuseExistingServer: !process.env.CI,
  },
});

Device profile names are supplied by Playwright and can change with releases. Check the current device emulation documentation before selecting a profile. Use only the projects that match your support policy; adding every project to every test can make feedback slow without improving useful coverage.

Write independent, user-facing tests

Start with a few high-value smoke tests. Prefer accessible roles and labels to selectors tied to internal markup. Keep tests isolated so shared state and order do not cause false failures. Playwright recommends independent tests and stable locators in its test practices.

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

test('a visitor can sign in and reach the account page', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('qa@example.test');
  await page.getByLabel('Password').fill('example-password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Your account' })).toBeVisible();
});

Replace the example credentials and expected heading with a test account and assertions for your application. Do not put production credentials in test code. Add tests for the states users can actually encounter: validation errors, disabled controls, loading states, empty results, dialogs, and recovery after a failed request.

Run a focused project or the whole matrix

npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
npx playwright test

Use a fast critical project set on every change and broader coverage in CI or before a release when runtime permits. Keep trace, screenshot, and test output available for failures so another developer can reproduce the exact run.

4. Use emulation for the checks it can answer

Browser automation can configure a device profile and emulate settings such as viewport, screen size, user agent, touch, locale, timezone, geolocation, permissions, and color scheme. This is valuable for responsive layout checks and many interaction paths. It does not make a desktop machine equivalent to every phone or tablet. Playwright’s emulation guide documents the settings.

Use emulation to check whether content fits a viewport, touch-sized controls work in an emulated touch context, or a localized page renders with the intended locale. Use representative real devices or operating systems when behavior depends on hardware, OS browser policies, actual assistive technology, or media codecs. Playwright notes that codec availability varies by operating system and that its WebKit build is based on upstream WebKit, which may precede inclusion in branded Safari. See Playwright’s browser and platform notes.

5. Add manual, functional, and accessibility checks

Automation is strongest for repeatable assertions. Human review catches awkward behavior and platform details that a smoke test may not express. For important pages, inspect representative widths and orientations and exercise navigation, forms, dialogs, error states, media controls, and touch interactions.

  • Run critical journeys with keyboard-only input and verify visible focus and sensible focus movement.
  • Use a screen reader for key workflows, including navigation, form errors, and dialog entry and exit.
  • Check responsive layouts at representative widths, including overflow, clipped content, and controls that become hard to use.
  • Confirm browser-specific features against current compatibility information before adding a polyfill or changing implementation.

MDN recommends keyboard and screen-reader checks as useful low-fidelity accessibility checks. Its testing introduction and automated testing guide explain how manual and automated checks complement each other.

6. Capture screenshots to compare browser output

Screenshots help diagnose visible differences: wrapping, spacing, missing assets, overlays, and responsive breakpoints. They do not establish that a workflow works or that a page is accessible. Pair visual review with functional and accessibility checks.

For a local page, a browser automation screenshot can be saved from a test:

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

test('capture the pricing page', async ({ page }) => {
  await page.goto('/pricing');
  await page.screenshot({ path: 'artifacts/pricing.png', fullPage: true });
});

For a remote URL, a screenshot API can capture a page without maintaining a browser process in your own script. ScreenshotNeo is a website screenshot API and MCP server. Its screenshots can help with visual review, while your browser test suite remains responsible for interactions and assertions.

7. Diagnose and report browser-specific failures

When a test or user report fails in one configuration, reproduce it in that browser and device context before changing code. Keep a report that another person can act on:

  1. Record the browser name and exact version, OS, device class, viewport, and whether the run used emulation.
  2. List the steps, expected result, and actual result.
  3. Capture relevant console and network errors, plus a screenshot or recording when it clarifies the failure.
  4. Check for unsupported feature usage, layout assumptions, font or rendering differences, input behavior, browser policy, and failed network resources.
  5. Confirm compatibility claims against current documentation before selecting a workaround or polyfill.

A screenshot is useful for a rendering symptom, but it cannot show why an event handler failed or whether a request was blocked. Preserve logs and traces alongside visual artifacts when the failure is functional.

8. Keep the matrix current without slowing every change

Browser versions, automation frameworks, and device profiles change. Update Playwright and reinstall the matching browser binaries together. Review the critical matrix after browser releases that affect supported behavior, when audience data or customer reports shift, and before important launches. Keep a lightweight smoke run in CI; add deeper suites where the defect risk justifies their runtime and upkeep.

For reliability, isolate test data, avoid dependence on execution order, and distinguish product failures from environment failures. A retry can help identify intermittent infrastructure problems, but repeated retries should not hide a flaky test. Retain enough failure artifacts to compare runs and make the first failure actionable.

Or skip the browser setup

To capture a remote page as an image, make one request to ScreenshotNeo. See the ScreenshotNeo API documentation for request options and response details.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
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('shot.webp', Buffer.from(await res.arrayBuffer())));

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed; response headers report the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is available on every plan. Use it for page capture and visual review, then run real cross-browser workflows where behavior needs testing.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

Performance, reliability, and cost trade-offs

Each additional browser project increases execution time and maintenance work. Run the smallest critical matrix on routine changes, parallelize independent tests where CI resources allow, and reserve broader coverage for scheduled or release runs. Keep traces and screenshots focused on failures to make artifacts useful and manageable.

Local automation gives control over workflows and assertions, with the cost of maintaining dependencies, browser binaries, test data, and CI capacity. Real-device checks add fidelity for platform-dependent risks but require access to representative environments. Screenshot capture is comparatively narrow: it gives a visual artifact, not proof of cross-browser functionality. ScreenshotNeo’s billing rules mean blank pages, bot checks, failed loads, timeouts, and cache hits are not billed; consult its documentation for API configuration and account usage details.

Troubleshooting common problems

Symptom Likely cause What to do
Browser executable is missing Playwright was updated without installing its matching browser binaries Run npx playwright install after updating the package.
A test passes in Chromium but fails in Firefox or WebKit Different engine behavior, unsupported feature, timing assumption, or test relying on implementation details Reproduce in the failing project, inspect trace and console output, and verify feature support. Fix the application or make the test reflect user-visible behavior.
Mobile layout test looks unlike a real phone Device emulation approximates settings but not all hardware, OS policies, or browser capabilities Use emulation for viewport and interaction checks; validate platform-sensitive behavior on a representative real device.
Visual comparison changes between runs Dynamic content, animations, fonts, network timing, or different browser binaries affect rendering Stabilize test data and wait for meaningful page state; keep browser versions consistent and inspect the changed region before updating expectations.
Test hangs while navigating The page never reaches the selected load state, or a request is stalled Wait for the page state your workflow needs instead of assuming every page becomes network-idle; inspect network activity and set a justified timeout.
Screenshot API returns an unexpected page The remote page may show a bot check, consent flow, blank state, or failed load Inspect the response and page verdict headers, verify the target URL and access requirements, and consult the API documentation for available capture options.
Screenshot request fails or produces no file Invalid credentials, malformed URL, network error, or non-success response handling Check the key and URL, inspect HTTP status and response headers, and handle the response before writing it as an image.

FAQ

Which browsers and devices should I test?

Choose from your actual audience, support commitments, customer reports, and product risks. Define a small critical set and a broader smoke set rather than copying a universal list.

How do I test my website in different browsers?

Automate core workflows in separate Playwright projects for the browser engines you support, then use targeted manual and real-platform checks for risks automation cannot reproduce.

Can I use emulation instead of a real device?

Use emulation for viewport, responsive layout, and many input checks. It is not equivalent to a real device for operating-system behavior, hardware, codecs, browser policies, or assistive technology.

How often should I update my browser test suite?

Keep Playwright and its browser binaries aligned, and review coverage after relevant browser releases, product changes, audience shifts, and before important launches.