---
title: Cross-Browser Visual Testing | TestingBot
description: Browsers do not draw pages identically. They use different text rendering,
  different default form control styles, different scrollbar widths and sometimes…
source_url:
  html: https://testingbot.com/resources/courses/visual-regression-testing/cross-browser-visual-testing
  md: https://testingbot.com/resources/courses/visual-regression-testing/cross-browser-visual-testing.md
---

Course

[Visual Regression Testing Tutorial](https://testingbot.com/resources/courses/visual-regression-testing)

Chapter 6 of 10

1. [1 Visual Regression Testing Tutorial](https://testingbot.com/resources/courses/visual-regression-testing)
2. [2 Your First Screenshot Comparison with Playwright](https://testingbot.com/resources/courses/visual-regression-testing/first-screenshot-comparison)
3. [3 Making Visual Tests Stable](https://testingbot.com/resources/courses/visual-regression-testing/stable-screenshots)
4. [4 Thresholds: How Much Difference to Allow](https://testingbot.com/resources/courses/visual-regression-testing/thresholds-and-diff-tolerance)
5. [5 Full Page, Element and Component Snapshots](https://testingbot.com/resources/courses/visual-regression-testing/page-element-and-component-snapshots)
6. [6 Cross-Browser Visual Testing](https://testingbot.com/resources/courses/visual-regression-testing/cross-browser-visual-testing)
7. [7 Visual Testing on a Cloud Grid with TestingBot](https://testingbot.com/resources/courses/visual-regression-testing/visual-testing-on-a-cloud-grid)
8. [8 Visual Regression Testing in CI with GitHub Actions](https://testingbot.com/resources/courses/visual-regression-testing/visual-tests-in-github-actions)
9. [9 A Visual Testing Strategy That Lasts](https://testingbot.com/resources/courses/visual-regression-testing/visual-testing-strategy)
10. [10 Visual Regression Testing Quiz](https://testingbot.com/resources/courses/visual-regression-testing/knowledge-check)

[Exit course](https://testingbot.com/resources/courses)

 Chapter 6 of 10 Intermediate 7 min read 2 quick checks Updated Nov 2026 

# Cross-Browser Visual Testing
On this page
1. [One test, one baseline per browser](https://testingbot.com#one-test-one-baseline-per-browser)
2. [How different are the browsers?](https://testingbot.com#how-different-are-the-browsers)
3. [What cross-browser visual tests actually catch](https://testingbot.com#what-cross-browser-visual-tests-actually-catch)
4. [Browser updates change baselines](https://testingbot.com#browser-updates-change-baselines)
5. [Playwright's engines and the browsers your users run](https://testingbot.com#playwright-s-engines-and-the-browsers-your-users-run)
6. [How many browsers to test](https://testingbot.com#how-many-browsers-to-test)
7. [Summary](https://testingbot.com#summary)

Browsers do not draw pages identically. They use different text rendering, different default form control styles, different scrollbar widths and sometimes different interpretations of the same CSS. Some of those differences are noise; some are real bugs your users see in one browser only. Cross-browser visual testing is how you find the second kind without drowning in the first.

## One test, one baseline per browser[#](https://testingbot.com#one-test-one-baseline-per-browser)

The key design decision: **never compare one browser's screenshot with another browser's baseline.** Compare each browser with its own earlier screenshots. That way a test fails only when a browser's rendering changed, and the normal differences between browsers never show up as failures.

Playwright does this automatically. Add Firefox, WebKit and a mobile preset as projects:

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

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  reporter: [['html', { open: 'never' }], ['list']],
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'iphone-13', use: { ...devices['iPhone 13'] } },
  ],
});
```

Install the extra engines with `npx playwright install firefox webkit` and run the chapter 1 tests:

```bash
npx playwright test --update-snapshots=missing
```

The snapshot folder now has one file per test per project:

```
tests/todo.spec.ts-snapshots/
  todo-empty-chromium-darwin.png
  todo-empty-firefox-darwin.png
  todo-empty-iphone-13-darwin.png
  todo-empty-webkit-darwin.png
  todo-two-items-chromium-darwin.png
  ...
```

The project name in the file name keeps the baselines apart. Run the suite again and all eight tests pass, each against its own baseline.

## How different are the browsers?[#](https://testingbot.com#how-different-are-the-browsers)

To see what would happen without per-browser baselines, we pointed every project at the same file by removing `{projectName}` from the path template (an experiment, not something to copy):

```typescript
snapshotPathTemplate: '{testDir}/ __shared__ /{testFilePath}/{arg}{ext}',
```

We created the shared baselines with Chromium, then ran Firefox and WebKit against them:

| Test | Firefox vs Chromium baseline | WebKit vs Chromium baseline |
| --- | --- | --- |
| empty todo app | 2 pixels | 60 pixels |
| todo list with two items | 95 pixels | 304 pixels |

All four comparisons failed, on a simple page that looks identical to a human in all three browsers. The differences are in text anti-aliasing and the placeholder and checkbox rendering. On a real application with custom fonts, form controls and scrollbars, expect far more.

You could raise tolerances until a shared baseline passes everywhere, but then the tolerance has to absorb the largest browser difference, and it will absorb real regressions of the same size. Separate baselines let every browser keep a strict comparison.

A team wants "one golden image per page" and compares Firefox and WebKit screenshots with the Chromium baseline, with `maxDiffPixelRatio: 0.02` to make it pass. What is the main problem?

 The tolerance has to cover normal browser differences, so regressions of a similar size pass unnoticed in every browser Playwright refuses to compare screenshots from different browsers It uses too much disk space

Cross-browser rendering differences are real and normal. A shared baseline forces the tolerance up to swallow them, which weakens every test. Per-browser baselines keep each comparison strict. Playwright happily compares any two images, so nothing stops you from making this mistake.

## What cross-browser visual tests actually catch[#](https://testingbot.com#what-cross-browser-visual-tests-actually-catch)

With per-browser baselines, a cross-browser visual test fails when one browser's rendering changes. Typical real causes:

- A CSS feature your code just started using is unsupported or behaves differently in one engine (newer layout or colour features often land in browsers months apart).
- A font is served in a format one browser rejects, so it falls back.
- A browser-specific CSS hack or prefix was removed in a refactor.
- Form controls: a custom `select` or date input styled for Chromium looks broken in Firefox or Safari.

Notice what it does **not** catch: a bug that was already there when the baseline was recorded. If the checkout button already overlapped the footer in Safari on the day you approved the Safari baseline, the Safari test passes forever. That is why the first baseline for each browser needs a human look, exactly like in chapter 1, and it is worth comparing the browsers' baselines side by side once when you create them.

## Browser updates change baselines[#](https://testingbot.com#browser-updates-change-baselines)

Every browser release can change rendering slightly. With Playwright the browser builds are tied to the `@playwright/test` version, so this happens only when you upgrade Playwright. Make that its own commit:

1. Upgrade `@playwright/test` (and the Docker image tag, if you use one).
2. Run the visual suite. Expect some failures.
3. Review the diffs. If they are rendering noise from the new browser builds, update with `--update-snapshots=changed` and commit the new baselines in the same pull request as the upgrade.

Mixing an upgrade with feature work makes it impossible to tell which diffs came from your change and which from the browser.

## Playwright's engines and the browsers your users run[#](https://testingbot.com#playwright-s-engines-and-the-browsers-your-users-run)

Playwright's `chromium`, `firefox` and `webkit` are builds it downloads and patches for automation. They are close to the real browsers but not identical:

- `chromium` is the open-source base of Chrome and Edge. To test the branded browsers, set `channel: 'chrome'` or `channel: 'msedge'` in a project's `use`, which runs the installed Google Chrome or Microsoft Edge instead.
- `webkit` is built from upstream WebKit sources, often ahead of what Apple ships in Safari, and on Linux it does not use Apple's text rendering at all. It is a strong signal for Safari layout, not a Safari screenshot.
- Device presets like `iPhone 13` emulate size, pixel ratio and user agent in the WebKit engine; they are not iOS.

For visual testing this matters more than for functional testing, because the pixels are the point. If your Safari users are a large share of revenue, you want baselines from real Safari on macOS, and from real iOS for mobile. You cannot run those in a Linux CI container; that is where a remote browser grid comes in, which is the next chapter.

Your Linux CI runs the `webkit` project and its visual tests pass. A customer reports that a pricing card is cut off in Safari on their Mac. Which statement best explains how both can be true?

 WebKit on Linux and Safari on macOS are the same build, so the customer must have a browser extension installed The `maxDiffPixels` default hides the problem Visual tests cannot detect clipped content Playwright's WebKit on Linux differs from Apple's Safari on macOS, for example in fonts and text rendering, so it can miss Safari-only layout bugs

Playwright's WebKit is built from upstream sources and, on Linux, renders text with Linux fonts and libraries. A card that fits on Linux can overflow with macOS fonts. Testing real Safari on macOS closes that gap. The default pixel allowance is 0, so it hides nothing.

## How many browsers to test[#](https://testingbot.com#how-many-browsers-to-test)

Every browser multiplies your baselines and your review work: three browsers at three breakpoints is nine baselines per test. Choose from your analytics, not from a wish list:

- Chromium (or branded Chrome) almost always.
- Safari/WebKit if a meaningful share of users are on Apple devices, which for most consumer sites they are.
- Firefox if your analytics show a meaningful share, or if you have had Firefox-only bugs before.
- Mobile layouts at your real breakpoints (chapter 4), not every phone model.

You can also run the full matrix less often: all browsers nightly, one browser on every pull request. A Chromium failure on a pull request catches most layout regressions early; the nightly run catches the engine-specific ones within a day.

Run a single project with `--project`:

```bash
npx playwright test --project=chromium
```

## Summary[#](https://testingbot.com#summary)

Keep one baseline per browser and per environment, review each browser's first baseline by eye, update baselines in the same commit as a browser upgrade, and remember that Playwright's engines are stand-ins for the browsers your users run. Next: running the same visual tests on real browsers on remote machines.

[Previous · Chapter 5 Full Page, Element and Component Snapshots](https://testingbot.com/resources/courses/visual-regression-testing/page-element-and-component-snapshots) [Next · Chapter 7 Visual Testing on a Cloud Grid with TestingBot](https://testingbot.com/resources/courses/visual-regression-testing/visual-testing-on-a-cloud-grid)

On this page

1. [One test, one baseline per browser](https://testingbot.com#one-test-one-baseline-per-browser)
2. [How different are the browsers?](https://testingbot.com#how-different-are-the-browsers)
3. [What cross-browser visual tests actually catch](https://testingbot.com#what-cross-browser-visual-tests-actually-catch)
4. [Browser updates change baselines](https://testingbot.com#browser-updates-change-baselines)
5. [Playwright's engines and the browsers your users run](https://testingbot.com#playwright-s-engines-and-the-browsers-your-users-run)
6. [How many browsers to test](https://testingbot.com#how-many-browsers-to-test)
7. [Summary](https://testingbot.com#summary)

Certification

This course has a free, hands-on certificate.

[How it works](https://testingbot.com/resources/courses/visual-regression-testing/certification)
