Learn
The A/B testing flicker effect, explained
Flicker is the flash of original content before a variant applies, and it exists because client-side tools resolve after render. Apertio resolves the variant before render, so there is no before state to flash from.
A/B testing flicker is the brief flash of the original page before the test variant takes over. A visitor lands on a page, sees the control headline render, and a fraction of a second later the headline swaps to a variant. The page visibly redraws in front of the user. This is also called the flash of original content, and it is a property of how most client-side testing tools work, not a bug you can configure away.
The cause is the order of operations. Client-side tools (Optimizely Web, VWO, Convert) ship a third-party script that runs in the browser. The page first renders its real, deployed content. Then the testing library loads, reads the assignment, and mutates the live DOM to apply the variant. Rendering the default and then changing it after the library loads is what produces the flash. The larger the change and the slower the library loads, the more visible the swap.
The standard fix makes the symptom worse in a different way. Client-side tools ship an anti-flicker snippet: a small inline script that hides the whole page, usually by setting the body to opacity: 0, until the testing library has loaded and applied its variant. The flash is gone, but now the visitor stares at a blank page until the third-party script resolves, or until a timeout fires. A hidden page is not a fixed page. You have traded a visible swap for a blank screen whose duration you do not control, and you have made your page depend on a third-party script for first paint.
The flicker exists because resolution happens after render. Remove that ordering and the flicker has nowhere to come from. Apertio resolves the variant before the component renders, so there is no "before" state to flash from. A variant in Apertio is bounded structured content, a primitive value or an enum key, not a script that edits the DOM. The server (or the edge) reads the visitor’s assignment cookie, resolves a { slotKey: value } map, and the app’s own React components render those values as props on the first paint. The HTML is correct when it arrives. Nothing redraws because nothing was wrong to begin with.
A variant is data, resolved before paint
// slots.ts — engineering declares the experimentable surface once.
// The variant payload is data (a string), never markup or a DOM edit.
import { slot } from '@apertio/core'
export const slots = {
'home.hero.headline': slot.text({
label: 'Hero headline',
default: 'Ship experiments without the flicker',
maxLength: 60,
}),
} Resolved on the server. By the time the browser paints, the text is already in the HTML.
The headline above is resolved on the server before the page is sent. By the time the browser paints, the variant text is already in the HTML. There is no client library waiting to mutate it, so there is no anti-flicker snippet hiding the body and no flash. The single honest constraint: only slots an engineer has declared are testable. A brand-new surface still needs an engineer to add a slot, which is usually a few lines like the snippet above. Engineering is spent once per surface instead of once per test.
Render default, then swap
Client-side tools paint the deployed content, then a third-party script rewrites the DOM once it loads. The rewrite is the flicker.
Hide the page to hide the swap
The anti-flicker snippet sets the body to opacity: 0 until the library resolves, replacing a visible flash with a blank screen on a third-party timer.
Resolve before render
Apertio resolves the variant server-side or at the edge and passes it as props, so the first paint is already correct.
Data, not DOM mutation
A variant is a value the app renders through its own components. Apertio never touches the DOM, so there is no swap to flash.
See zero-flicker rendering in Next.js
Resolve variants server-side or at the edge, with no anti-flicker snippet and no injected script.
Frequently asked questions
- What is the flicker effect in A/B testing?
- It is the visible flash of the original page content before a test variant is applied. Client-side tools render the deployed content first, then a third-party script mutates the DOM to apply the variant, and that swap is the flicker.
- Do anti-flicker snippets fix the flicker?
- They hide the symptom. An anti-flicker snippet hides the whole page, typically by setting the body to opacity: 0, until the testing library loads and applies its variant. The visible swap is replaced by a blank page on a third-party timer, so the page now depends on that script for its first paint.
- How does Apertio avoid A/B testing flicker?
- Apertio resolves the variant before the component renders. A variant is data, resolved server-side or at the edge and passed as props to the app’s own components, so the first paint is already correct. There is no default-then-swap and no anti-flicker snippet.
- Is flicker a problem with all A/B testing?
- No. Flicker is specific to client-side tools that mutate the live DOM after the page loads. Server-side and SDK-based approaches resolve before render and do not flicker. Apertio is in that second group, with the variant constrained to bounded data.