If you've run a test from a visual editor, you've probably seen it: the page loads with the old headline, and a beat later the new one snaps into place. That's flicker. Client-side testing tools all have to deal with it, because their script applies the variant after the browser has started painting.
From inside the browser you can either show the original and swap it, so the visitor sees the flash, or hide the page until the script is done. The second option is the "anti-flicker snippet", and most tools turn it on by default.
How long the page stays hidden
An anti-flicker snippet makes the page invisible, usually with opacity: 0 on the body or a class like Google Optimize's async-hide. It reveals the page when the testing script finishes or a timeout fires, whichever comes first, so the timeout is your worst case. The defaults are generous:
- Google Optimize shipped its snippet with a 4,000 ms default (Google's developer docs). Optimize shut down on September 30, 2023, but copies of that snippet are still sitting in plenty of
<head>tags. - Webflow Optimize also defaults to 4,000 ms. Enterprise plans can set anything from 0 to 30,000 ms, and Webflow's help page warns that lower values bring back flicker (Webflow help).
Optimizely recommends loading its snippet synchronously in the head instead (Optimizely support), which blocks rendering until the script has downloaded and run.
On fast wifi with a warm cache, the script usually wins and the page appears within a few hundred milliseconds. On a slow phone, your visitor waits for the timeout.
What it does to Core Web Vitals
Largest Contentful Paint can't happen while the page is invisible, so LCP absorbs the whole wait. Vercel's guide on A/B testing and Core Web Vitals says the failsafe commonly sits at 4 seconds and LCP takes all of it (Vercel KB). Google rates LCP as good at 2.5 seconds or less, measured at the 75th percentile (web.dev).
Published measurements are rare. DebugBear tested one site and recorded an LCP of about 6.0 seconds with body hiding and about 2.7 seconds with the hiding overridden (DebugBear). That's one site, and your numbers will differ, but they'll move in the same direction.
The same Vercel guide also covers layout shift. Without anti-flicker, swapping content in can push CLS past 0.1. With it, CLS can look healthy for the wrong reason, since the browser doesn't record shifts that happen while the page is hidden. A clean CLS score on a tested page might only mean nobody could see the problem.
The browser team's own advice
Chrome's guidance on flicker-free client-side testing suggests blocking="render" with a strict execution budget of under 100 ms, says not to combine it with anti-flicker snippets, and recommends testing on the server wherever you can (Chrome for Developers). The people who build the browser think the cleanest fix is to stop deciding in the browser.
Deciding before the first byte
A Next.js server already renders the page, so it can render the right variant from the start. You can build that yourself in about 100 lines; our guide to A/B testing in the App Router shows how. evolveAB does the assignment in the Next.js proxy, which reads a signed config bundle from memory (no network call), sets a sticky cookie and rewrites the request to that variant's cached render. The HTML arrives with the variant already in it, so there's nothing to hide or swap and no testing script blocking the head.
That has a cost too. Our code in the proxy takes 0.1 to 0.35 ms, but on Vercel any proxy adds roughly 20 ms to a first page view; one that does nothing measured 18 to 23 ms in our tests. Twenty milliseconds before the first byte is an easy trade against up to four seconds of blank page, as long as nobody pretends it's zero.
We also measure each variant's page speed in visitors' browsers and compare it with control. Once there are enough page views to be sure, auto-rollback pauses a variant that's clearly slower: LCP 20% worse, CLS up by 0.05 or INP 50 ms slower. A variant shouldn't win on sign-ups by quietly making the page slower.
Measuring it on your own site
You don't need to switch tools to see what anti-flicker costs you. Run a throttled Lighthouse or WebPageTest trace on a tested page and look at the gap between first byte and first paint, then find the timeout in your snippet (it's usually a plain number in the code). If it says 4000 and your mobile LCP hovers around 2.5 seconds, you know where part of it goes.
Originally published on the Evolve blog.