A/B testing scripts can be loaded in two ways:

  • Synchronously, where scripts are loaded sequentially, one after another, starting with the <head> tag
  • Asynchronously, where some scripts can be loaded simultaneously

Loading a script asynchronously has the advantage of not slowing the page down, but it can cause a "flicker" on the page, where the original page loads, followed shortly by the variation page.

Optimizely uses a synchronous snippet to prevent flickering and has invested heavily in a balanced CDN system to make sure the impact on the page is minimized.

Synchronous and asynchronous loading types explained

A web page consists of a head and a body. Everything in the body is rendered by the browser while the head is used to load external resources (such as scripts and style sheets) and to add meta data to the page. When the page loads in a browser, the browser starts reading the html from top to bottom. The head section has a special characteristic: normally, the browser will not show anything (a white screen) until all the external resources are fully loaded. This is called "synchronous loading."

However, you could override this functionality to make certain elements load without waiting for all external resources to load. This is known as "asynchronous loading."

Here's what a page's <head> tag would look like when all resources are loaded in a synchronous manner:

<html> 
    <head> 
        <script src="1.js" /> 
        <script src="2.js" /> 
        <script src="3.js" /> 
        <link href="4.css" /> 
        <script src="5.js" /> 
    </head> 
    <body>Hello World!</body> 
</html>


When all resources in the head are synchronous, the elements will load in order, like this:


Here's what a page's <head> tag would look like when all resources are loaded in an asynchronous manner:

<html> 
    <head> 
        <script src="1.js" /> 
        <script async src="2.js" /> 
        <script src="3.js" /> 
        <link href="4.css" /> 
        <script src="5.js" /> 
    </head> 
    <body>Hello World!</body> 
</html>


When a script is asynchronous, it will load simultaneously with other scripts, like this:

You can see in the diagram, that scripts 2 and 3 are now able to load at the same time, which speeds up the overall loading of a page. However, the browser will not wait until the snippet is done loading before displaying the elements in the body to a visitor, which can lead to "flickering" (see below).

Synchronous loading: the preferred approach

Optimizely wants to minimize the loading time without the potential of a flicker on the page. To do that, Optimizely does everything possible to reduce the loading time of the snippet, but recommends using the synchronous version for preventing flickering.

To make sure the impact on a website is as small as possible, the Optimizely script is hosted on first class Content Delivery Networks (Akamai and EdgeCast). Content Delivery Networks (CDN) are networks of servers that deliver resources like the Optimizely snippet to visitors. There are thousands of servers in a Content Delivery Network, which are located around the globe to make sure that the Optimizely script is delivered as fast and reliable as possible wherever the end user might be located.

Optimizely has partnered with the best CDNs available and checks for every location which CDN is performing the best. We call this a balanced CDN system. You can read more about CDN balancing on our blog.

Asynchronous loading: strengths and drawbacks

On the plus side, loading asynchronously will prevent any delay in pageload, because the page will attempt to load all elements simultaneously, including your A/B testing scripts.

However, there is a major drawback: when an A/B testing script is loaded much later than the page, a flicker of the page can occur. This is where the original page loads, followed by the variation. This is not desirable, especially when the loading of the A/B testing script is taking more time than is acceptable.

So in the asynchronous example above, a visitor might see "Hello world" in her browser before script 2 is done loading. If the A/B testing script is not loaded before the webpage is shown, it will result in a "flicker." Flickering means that the variation will load on the page shortly after the original page displays. This will make the outcome of your experiment less reliable and could compromise your visitor experience.

When loading asynchronously, you may prefer simply not to load the experiment at all, rather than risking flicker. For instance, imagine that a visitor is reading an article, but the article changes after 5 seconds because the asynchronous snippet is finally done executing and an experiment is executed. To prevent a 5 second delay in execution, an asynchronous snippet is provided with a timeout of 1 second (default setting).

The timeout means that if the A/B testing script is not loaded within a certain time, the A/B test is not executed. A side effect is that if a visitor has a slow connection, the visitor will not be included in the experiment. Or a visitor may see the experiment when they have a fast connection, but won't see it when they return later on a slower connection such as a mobile network. This gives visitors an inconsistent experience. The asynchronous version of the snippet also uses the Optimizely CDN.

An asynchronous implementation would look like this in your site's code, instead of using the Optimizely Snippet:

(function() { 
    var projectId = [YOUR PROJECT ID];
    var protocol = ('https:' == document.location.protocol ? 
    'https://' : 'http://');
    var scriptTag = document.createElement('script');
    scriptTag.type = 'text/javascript';
    scriptTag.async = true;
    scriptTag.src = protocol + 'cdn.optimizely.com/js/' + 
    projectId + '.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(scriptTag, s);
})();
function optimizelyTimeout() {
    window.optimizely = window.optimizely|| [];
    if (!window.optimizely.data) {
    window.optimizely.push("timeout");
    }
}
setTimeout(optimizelyTimeout, 1000);