A/B test flicker: what causes it and how to fix it
Flicker is the flash of the original page visitors see before a testing script swaps in their variant. What causes it, what it costs, and how to remove it.
The Mockly team
8 min readYou open a page you're testing, and for a moment you see the old headline before the new one snaps into place. That moment is flicker, also called the flash of original content. It's one of the most common complaints about A/B testing tools, and it's more than cosmetic: it can change how visitors behave, slow the page down, and skew the result you're trying to measure.
This post explains where flicker comes from, what the usual fixes cost, how to check whether your own tests flicker, and how to get rid of it for good.
What is A/B test flicker?#
A/B test flicker is a brief flash of a page's original content before an A/B testing script replaces it with the variant the visitor was assigned. It happens with testing tools that run in the browser, because they change the page after the browser has started to show it.
It goes by a few names: flicker, the flicker effect, the flash of original content, or FOOC. They all describe the same thing. The visitor sees two versions of the page in quick succession, the original and then theirs.
Why client-side tests flicker#
Most A/B testing tools run in the browser. They're easy to add, with one script tag, and they let anyone change a page in a visual editor, which is why they're popular. But the way they work makes flicker likely:
- The browser asks for the page, and the server sends every visitor the same HTML: the original.
- The browser starts drawing that HTML as soon as it can.
- Meanwhile, it downloads the testing tool's script, often from another domain, and the settings for the experiments on the page.
- The script decides which variant this visitor gets, then edits the page: it rewrites text, changes styles, and moves or hides elements.
If the browser gets through step 2 before the script finishes step 4, the visitor sees the original first. On a fast computer with the script already cached, the gap can be too short to notice. On a phone with a slow connection, or on a first visit, when nothing is cached yet, it can last a second or more.
Anything that delays the script makes it worse: loading it through a tag manager, other scripts ahead of it in line, a large file of experiment settings, or a change that waits for an element further down the page to load.
Script in the browser
The original shows, then swaps
Anti-flicker snippet
Blank until the script is ready
Chosen on the server
The variant from the first frame
- Original headline
- Variant headline
- The flash: the original, before the swap
- Hidden while waiting
Why flicker matters#
It can skew your results#
A visitor who sees the headline change knows something changed. The variant draws attention because it moved, and that alone can change what people click, for reasons that have nothing to do with the idea you're testing.
Flicker isn't the same for everyone, either. It's worst on slow phones and slow networks, so some visitors see a jarring swap while others see nothing, and the experiment measures a blend of the two. When you ship the winner, it's part of the page, and no one sees a swap. The test measured something different from what you shipped.
Flicker is one way a test misleads you before it starts. Reading its results too often is another, covered in why peeking at A/B tests finds false winners.
It looks broken#
A page that rewrites itself while you read it looks unfinished. On a pricing page or a sign-up form, the pages most worth testing, that's the wrong first impression.
It costs speed, and speed counts in search#
Flicker, and most of the ways to hide it, show up in Core Web Vitals, the measures of page speed that Google collects from real visitors:
- Largest Contentful Paint (LCP) is when the page's main content appears. Good is 2.5 seconds or less. Anything that holds the page back until a testing script is ready delays it.
- Cumulative Layout Shift (CLS) is how much content moves after it appears. Good is 0.1 or less. A variant that's taller or shorter than the original pushes everything below it when it swaps in.
Google says its ranking systems use Core Web Vitals, among many other signals. Good scores won't make a page rank on their own, but a test that hurts them is working against the page you're trying to improve.
Common fixes, and what each one costs#
Load the script before the page draws#
Put the testing script in the page's <head> without async or defer, and the browser waits for it before drawing anything. The variant goes in sooner, so there's less of a flash, or none. But now nothing appears until the script has downloaded and run. Every visitor waits, including those in no experiment, and when the tool's servers are slow, so is your page.
Hide the page with an anti-flicker snippet#
Most browser-based tools offer an anti-flicker snippet: a few lines of inline code that hide the page until the tool reports that the variant is in place, or until a timeout runs out. Google Optimize's snippet, for example, hid the page for up to four seconds by default. Each tool's snippet differs, but in outline they all do this:
// Hide the page as soon as the browser reads this line…document.documentElement.style.opacity = "0"; // …then show it when the testing tool has applied the variant,// or after 4 seconds, whichever comes first.const show = () => document.documentElement.style.removeProperty("opacity");testingTool.onReady(show);setTimeout(show, 4000);The flash is gone, but visitors see a blank page instead, for as long as the tool takes. That delays LCP for everyone on the page. If the timeout runs out first, the page appears without the variant. Then, depending on the tool, the visitor either sees the swap anyway or is quietly left out of the experiment.
Hide only what's being tested#
A gentler version hides only the elements under test. The rest of the page draws as usual, which helps when the tested element is small. But the hidden part still appears late, and the parts most worth testing, such as a hero's headline and image, are often the largest element on the page, so LCP waits for them all the same.
Make the script faster#
Serve the script from your own domain, keep the experiment settings small, connect to the tool's servers early with preconnect, and load the script before other tags. Each of these shortens the gap. None of them closes it, because the browser still draws first and the script still changes the page afterward.
Choose the variant on the server#
The only fix that removes flicker completely changes when the decision is made. Instead of sending everyone the original and editing it in the browser, the server, or a CDN in front of it, picks the visitor's variant and sends HTML that already is that variant. There's nothing to swap, so nothing to see swapping, and no reason to hide anything.
The catch has been effort. In most stacks, testing on the server means feature flags in the application's code, an engineer for each test, and care with caching, since visitors no longer all get the same HTML. That's why so many teams accept flicker as the price of letting marketers run tests.
Side by side:
| Approach | A flash of the original | A blank page while waiting | Delays LCP |
|---|---|---|---|
| Script in the browser | Often | No | Can |
| Script before the page draws | Rarely | Yes, for everyone | Yes |
| Anti-flicker snippet | After a timeout | Yes | Yes |
| Hiding only what's tested | Rarely | Those parts | Can |
| Variant chosen on the server | Never | No | No |
How to check whether your tests flicker#
Flicker is easy to miss on your own computer: your connection is fast, and the testing script is already cached. To see what a first-time visitor on a phone sees:
- Open the page in a private window in Chrome, so nothing is cached.
- Open DevTools. In the Network panel, choose a slow preset such as Slow 4G from the throttling menu.
- In the Performance panel, turn on Screenshots, slow the CPU down in its settings, and record a reload.
- Step through the screenshots. Look for the original content before your variant, and for blank frames where the page is hidden.
To see what the testing script costs, record the page again with the script blocked: in the Network panel, right-click its request and choose Block request URL. Compare the two recordings' LCP. WebPageTest's filmstrip view shows the same frames from other devices and locations.
For real visitors rather than one test run, use field data. Search Console's Core Web Vitals report and Chrome's User Experience Report show LCP and CLS from real Chrome users. A drop that starts when the testing tool went in points at the tool.
How Mockly does it#
Mockly is a website platform with A/B testing built into the code. An experiment is part of the page, written next to everything else:
import { Experiment, Page, Variant } from "mockly"; export default function Home() { return ( <Page title="Duebird" description="Invoicing for small studios."> <Experiment name="headline" goal="signup"> <Variant name="control"> <h1>Invoicing for small studios</h1> </Variant> <Variant name="benefit"> <h1>Get paid in days, not weeks</h1> </Variant> </Experiment> <a href="/signup" track="signup"> Start free </a> </Page> );}When you publish, Mockly renders every variant of every page to HTML ahead of time. When a visitor arrives, the server picks their variant, joins the finished pieces of HTML, and sends the result. Nothing is rendered while the visitor waits.
So the page arrives already as the visitor's variant: no script to wait for, nothing to hide, nothing to swap. It shows in full with JavaScript turned off, and a page without interactive parts loads less than 1.25 KB of JavaScript, for counting goals and timing the page. Each visitor keeps their variant on every page and every visit.
And a test doesn't need an engineer. In the studio's visual editor, Test this turns a selected section into an experiment, and Content mode changes each variant's words without touching the code.
To check the result, the Performance tab in Analytics shows LCP, CLS, and responsiveness from your real visitors, and how long the server took to answer. How Mockly works goes into detail, and Experiments shows everything an experiment can do.
Frequently asked questions#
Does A/B test flicker hurt SEO?#
It can, through page speed. Anti-flicker snippets delay Largest Contentful Paint, and variants that swap in after the page appears can add layout shift. Both are Core Web Vitals, which Google's ranking systems use among many other signals. A test that serves the variant from the server leaves them as they'd be without it. Does A/B testing hurt SEO? covers what else Google asks of tests.
Is testing on the server slower?#
It adds one step to each request: picking the variant. In Mockly, that's a lookup and joining strings, with nothing rendered while the visitor waits, and every response carries its server time in a Server-Timing header, so you can see it in your browser's network panel. In exchange, the browser doesn't download and run a testing script before it can show the page.
Can I fix flicker without changing tools?#
You can make it smaller: load the script early, from your own domain, keep experiments small, and hide only what's being tested. You can't remove it completely while the variant is applied in the browser, because the browser will always be able to draw the page before the script has changed it.