Technical guide · 8 min read
How to Prevent Flicker in Client-Side A/B Tests
Flicker happens when a visitor sees the control before a client-side testing script applies the variation. It is more than a cosmetic issue: it can hurt trust, distort exposure, and make a winning test feel broken. Here is how to diagnose and prevent it.
Why flicker happens
In a typical client-side experiment, the browser first receives and paints the control HTML. A testing script then loads, decides which variation a visitor should receive, and changes the DOM. If the original paint wins that race, the visitor sees a flash of the control—often called flicker, FOOC, or FOUC.
The gap can be only a few hundred milliseconds, but it becomes obvious around hero copy, prices, navigation, or a large call to action. Slow devices, third-party script contention, consent gates, tag managers, and SPA route changes make the gap more likely.
Diagnose the rendering path
Reproduce the test in a throttled mobile browser before changing code. Record a performance trace and look for four timestamps: first contentful paint, experiment-script download, assignment decision, and DOM mutation. The right fix depends on which one is late.
- Late snippet: the experiment code sits below other scripts or is injected through a slow tag manager.
- Late decision: remote configuration, identity, or audience data blocks assignment.
- Late mutation: the variation uses heavy selectors, waits for an element, or repeatedly rewrites the page.
- Hydration conflict: a framework re-renders markup after the variation applies.
Keep a test-specific performance budget. Otherwise an anti-flicker fix can merely trade a visible flash for a slower page.
Practical fixes that preserve UX
Load the smallest possible decision code early in <head>, before render-blocking scripts that do not need priority. Cache the assignment in a first-party cookie or local store so returning visitors do not wait for a new decision. Keep the variation simple and avoid polling the DOM.
An anti-flicker snippet can temporarily hide only the tested element until the decision is ready or a short timeout expires. Scope the selector tightly, set a conservative timeout, and always reveal the control on failure. Hiding the entire document is rarely a good trade: it can worsen perceived speed and Core Web Vitals.
For React and other hydrated applications, make the control and variation agree with the first render where possible. Avoid a visual-editor mutation that fights React’s ownership of the DOM. If the change is important, pass an experiment flag into the application rather than patching rendered markup after the fact.
When to stop fixing client-side flicker
Client-side delivery remains practical for low-risk, visual changes. But a high-traffic landing page, a price presentation, or a flow with framework hydration may deserve an architecture change. In server-side A/B testing, the response is selected before the visitor sees it, removing the late visual correction altogether.
Before launch, QA slow mobile devices, first and repeat visits, consent states, logged-in states, route transitions, and an intentionally unavailable decision service. Then log exposure only after the assigned experience can actually be seen. That discipline protects both the customer experience and the validity of the result.
Put the guide into practice
Build your next experiment with Diti.
Turn a focused customer question into a test your team can preview, launch, and learn from.
Start testing with Diti ↗About this guide
Reviewed by Diti's experimentation team
Diti's product and experimentation team maintains these guides for people planning, launching, and evaluating real product experiments. We update them as our workflow and platform guidance evolves.
Keep learning