Skip to main content

How anti-flicker snippets from A/B testing tools impact site speed

· 6 min read

This article looks at how the anti-flicker snippets used by A/B testing tools like Optimizely and Adobe Target can negatively impact web performance.

After explaining the problem, we'll look at potential solutions that minimize flicker while also keeping site speed in mind.

What are anti-flicker snippets?

A/B tests and other customizations mean that the content on a website depends on the visitor who's viewing it. These customizations are usually implemented through a dedicated A/B testing service, in order to let marketing teams run tests without having to get developers involved.

The visitor's browser first downloads the page with default content, then browser loads the list of customizations from the A/B testing service, and finally applies them to the page.

However, these customizations introduce flicker. The visitor first sees the default content, and then the content disappears and is replaced.

An anti-flicker snippet is a piece of code that prevents flicker by hiding the original page content until the customizations have been applied.

This graphic shows filmstrips indicating the rendering progress of a website in three scenarios:

  1. Without A/B testing
  2. With A/B testing and flicker
  3. With A/B testing and an anti-flicker snippet

Graphic showing rendering progress with and without A/B testing anti-flicker snippets

What's the problem with anti-flicker snippets?

Hiding content ensures that content customizations don't negatively impact the user experience when they are applied.

However, hiding content with anti-flicker snippets also causes a worse user experience by making the site load more slowly. Visitors to your site spend more time looking at an empty page.

Anti-flicker snippets and Core Web Vitals

Anti-flicker snippets increase your Largest Contentful Paint (LCP) metric. This can also impact your Google rankings, as LCP is one of the Core Web Vitals that's used to assess site experience.

Applying customizations without an anti-flicker snippet can cause content to shift around on the page, if the custom content has a different size than the default content. These shifts in turn increase the Cumulative Layout Shift metric, another Core Web Vital.

So when optimizing your anti-flicker logic you need to balance these two competing concerns. I would lean towards first sorting out LCP issues, and then reviewing and addressing layout shifts one by one.

How to fix poor performance caused by anti-flicker snippets

Server-side customizations and A/B testing

The reason anti-flicker snippets are necessary is that the web server first returns default content and then another tool modifies the content on the client.

If you're able to run implement A/B tests on the server this problem can be avoided entirely. However, this is likely difficult to implement.

Customize the anti-flicker snippet

Anti-flicker snippets typically hide all content in the HTML body tag. This is a drastic solution, and it's done because the snippet does not know which parts of the page will be modified until the customizations have been loaded.

However, as the person running the A/B tests, you will know more about what type of tests you run. Do you test different page headings? Then hide only h1 tags. Are you customizing call-to-action copy on a button? Then hide button as well.

In contrast, you might not be running any customizations on p tags or content in the website header. So these components don't need to be hidden while the customizations are being loaded.

Anti-flicker snippet that only hides content affected by A/B tests

You could still end up with layout shifts, for example if your customized h1 stretches over two lines instead of one. But a small layout shift might be ok, and is less jarring than page content getting swapped out. If it is a problem, specify a minimum height for your h1 and make sure it is always large enough to handle different content lengths.

Load customizations more quickly

The process of how an A/B testing tool loads customizations might look like this:

  1. Load a tag manager
  2. Load additional code for the A/B testing tool
  3. Make a fetch request to get a unique ID for the user
  4. Use that unique ID to load the customizations
  5. Apply the customizations

This process is often sequential and involves establishing connections to multiple servers. Like any other request chain on your website it can be optimized, though this may be harder as you don't have full control over how the third-party works.

Browser resource hints can be a useful tool to optimize sequential request chains that cannot be parallelized.

For example, if the customizations are loaded from c.abtesting.com, you add a preconnect hint for that domain to your document. The browser will establish a server connection before the actual fetch request. That way, when the fetch request is made, only one network round trip is needed, as the existing connection can be used.

Accept the flicker

If your users find that your site loads slowly, you might want to consider just accepting flicker when it happens.

This especially applies in these two cases:

  • you only run tests on a few pages at a time, but the anti-flicker snippet is loaded globally for your site
  • the tests you run don't target the most prominent page content, but instead tweak small UI components or customize below the fold content

Abandon A/B testing

Once you look into it, it might turn out the A/B testing tool isn't actually used very often. In that case you can just remove the tool from your website.

Vendor-specific documentation

Many A/B testing tools have pages explaining the negative speed impact of anti-flicker code and how to mitigate it:

Optimizely
Adobe Target
Google Optimize
VWO

Analyzing a real-world example of the impact of an anti-flicker snippet

As an example of what hiding body content looks like in practice, let's inspect the Asana homepage and look at how the data in the filmstrip seemingly conflicts with the request waterfall.

The request waterfall shows that:

  1. The last render-blocking request finishes after about 0.6 seconds
  2. The LCP image has loaded after 3.1 seconds

Yet, the filmstrip shows no content until 5.7 seconds after the page was opened.

Anti-flicker script hiding body content even after content is ready

Looking a bit deeper, we find that Asana uses Google Optimize. It also looks like Optimize only starts loading relatively late. I haven't confirmed this, but there might be a sequential request chain involving multiple Google Tag Manager requests.

Google Optimize being loaded for A/B tests

The HTML document contains styles that hide the body content, and the async-hide class is applied to the html tag.

<style>
.async-hide {
opacity: 0 !important
}
</style>

If we manually override those styles we can see that the page now starts to render after just 2.1 seconds, instead of the 5.7 seconds from before.

Disabling anti-flicker snippet to improve page speed

Anti-flicker snippets on DebugBear

DebugBear not only monitors site speed over time but also automatically detects when page content is hidden by an anti-flicker snippet.

Track Core Web Vitals and see how your anti-flicker optimizations impact performance.

DebugBear detecting an anti-flicker snippet

Get a monthly email with web performance articles.