beta
Blog

Animated pages make screenshot diffs flaky: freeze them, or wait

A page still moving when it is captured is shot on a different frame each time, and every frame is a difference. deploydiff now freezes the animations the browser knows about, and can wait for the ones a script draws.

deploydiff

A capture is taken once the page has loaded: no request in flight for half a second, and the fonts in. A page still moving at that moment is shot on whatever frame it has reached. A chart drawing its curves, a spinner, a badge fading in. The next capture catches another frame, and the comparison reports a difference that nobody made.

One such page is enough to spoil a diff batch. It fails on every deploy, people learn that it always fails, and the day it fails for a real reason, nobody looks.

Two kinds of motion

The browser keeps a list of the animations it runs: CSS animations, CSS transitions, and those started through the Web Animations API. Motion driven by a script is not on that list. A chart library drawing frame by frame, a canvas, a carousel on a timer: to the browser, that is only a page that a script keeps redrawing.

So there are two settings, one for each.

Freezing what the browser knows about

Freeze animations is on by default. Before the screenshot, every animation on the browser's list is brought to its end, and one that loops forever, such as a spinner or a pulsing badge, is removed. Both sides of a comparison are captured in the same state, whatever frame each one had reached.

It adds no time to a capture, so it costs nothing. Animations tied to the scroll position are left as they are at the top of the page, which is where it is captured. Each capture records how many animations the freeze ended and how many it removed, so you can tell whether it did anything on a page.

Waiting for what it does not

Wait after load is a pause of 0.5 to 5 seconds, once the page has loaded and its fonts are in, before the freeze and the rest of the preparation. It is for motion a script drives and that settles on its own: the chart finishes drawing, the counter reaches its number.

Unlike the freeze, it is not free. The wait is added to every capture it applies to, and a capture is billed by how long its sandbox runs. So set it on the page that needs it, rather than on the whole project.

A real case: emooki's price charts

emooki is a site about property prices. Its top-list pages chart, year by year, the median price per square metre in the main towns of a French département, and the curves are animated as they draw in.

Captured as soon as it had loaded, that page passed or failed depending on how far the curves had got: caught part-way, at a different point each time, they were sometimes close enough to match and often not. The freeze could do nothing there. Each capture recorded zero animations ended and zero removed, because the curves are drawn by a script.

With a two-second wait on that page, the chart has finished before the screenshot. Against a capture taken without the wait, the difference is the curves and nothing else. Since then, the page has matched its reference at every capture.

A comparison's page in the deploydiff dashboard for emooki's top list of the Yonne: a 99.74% match, 13,371 px diff, verdict Fail. The diff image shows the reference on the left, the candidate on the right, and between them only the traces of the price charts' curves.
A capture without the wait against one taken after two seconds: what differs is the curves, and nothing else.

Which one to use

Both settings are part of the project's capture config, and a page can override either one. The details are in the projects and pages documentation.

See what changed on every deploy

Start on the free Discovery plan, no credit card needed.

Animated pages make screenshot diffs flaky: freeze them, or wait — deploydiff