Screenery

Screenery / Tools / Compare screenshots

Compare two screenshots

Add a before and an after image to see which pixels changed. You get a highlighted diff, a side-by-side view and a slider, with the changed-pixel count and the regions that changed.

Your images never leave this device. The page decodes them in your browser, compares them in JavaScript, and loads no third-party scripts.

Paste with Ctrl+V or ⌘V. A pasted image goes into the box you last focused, or the first empty one. Drop two files at once to fill both boxes.

0 counts any difference. 0.1 is the default.

How a pixel diff works

The tool reads both images into pixel arrays and compares them one pixel at a time, at the same position. For each pair it converts the colours to YIQ, which splits a colour into brightness and two colour axes, and measures the distance between them. Brightness carries the most weight, because eyes notice it most. When that distance is over the threshold, the tool counts the pixel as changed and draws it red.

The method comes from the open-source pixelmatch library. Screenery's visual-diff gate uses the same colour distance and the same default threshold. For the same two PNGs, the changed-pixel count here should match the gate's. The tool blends translucent pixels over white first, so they compare as they would look on a page.

Then the tool groups the changed pixels into regions. It splits the image into 16-pixel squares. Changed squares that touch form one region, with one box around it. A region count tells you more than a pixel count. A button that moved 6 pixels can be thousands of red pixels, but it is one region.

Any image your browser can decode works: PNG, JPEG, WebP, the first frame of a GIF, and AVIF in most browsers. Each image can be up to 40 million pixels.

Choosing a threshold

The threshold runs from 0 to 1. At 0, any difference at all counts, including a change of one shade of grey. The default of 0.1 ignores tiny colour shifts that nobody would see, and still catches a changed colour, moved text or a missing icon. A higher threshold ignores bigger colour differences.

Anti-aliasing

Browsers draw text and curved edges with in-between shades so they look smooth. Those shades depend on the font renderer, the GPU and the operating system, so the same page captured on two machines differs along every edge.

With Ignore anti-aliasing on, the tool checks each changed pixel's neighbours. If the pixel sits between a darker and a brighter neighbour, next to an area of flat colour in both images, the tool treats it as an edge pixel, draws it yellow and does not count it. The check comes from pixelmatch.

It is off by default, to match Screenery's gate, which counts every anti-aliased pixel as a change. Turn it on when you compare screenshots taken on different machines. For the gate, capture the baseline on the same kind of runner as CI, so both sides render the same way.

Images of different sizes

When the two images differ in size, the tool compares the area they share, starting from the top-left corner, and reports how many pixels it left out. It does not scale or align either image.

A screenshot that got taller usually means something near the top grew and pushed the rest of the page down. Everything below that point then shows as changed. Fix the first change and compare again. By default, Screenery's gate fails a screenshot whose width or height changed.

Do this on every pull request

This page compares two files once. Screenery runs the same comparison in CI, on every screenshot your tests write. You commit a baseline folder of approved screenshots and point the screenery/push@v1 Action at it:

permissions:
  id-token: write
  contents: read
steps:
  - uses: actions/checkout@v4
  # … your Playwright step writes test-results/ …
  - uses: screenery/push@v1
    with:
      project: acme/dashboard
      path: test-results
      diff-baseline: ./screenery-baseline

The Action compares each screenshot with the file of the same name in the baseline before it publishes anything. If one changed, the job fails and the Action pushes nothing. If none did, the push publishes as usual. By default one changed pixel fails the job. You can grade changes as minor, moderate or major and choose which grade fails. To run the same check on your own machine, with no credential and no network:

npx screenery diff ./test-results --baseline ./screenery-baseline

Using Playwright already? See Playwright screenshots. The console can also compare two versions of a published screenshot. See Comparing versions in the console.