Documentation
NAV Navbar
  • Advanced Implementation Guide
  • Advanced Implementation Guide

    Introduction

    This article is an in-depth technical guide to help you get familiar with the different implementation methods Kameleoon supports. The implementation process in itself is simple, since you only need to add a JavaScript installation tag into the HTML source code of your pages. However, the details are extremely important, so we will focus on them: where exactly should the tags be placed, what are the pros and cons of our different implementations, and when is the Kameleoon application file loaded and parsed by the browser. All these factors are important to take into consideration when optimizing the setup of Kameleoon for performance, while ensuring all the functional depth of the platform remains intact.

    Understanding all this will let you take an informed decision about which type of implementation method best fits your website and requirements. We also have a recommended setup which you should follow if you are not sure or have any doubts about which installation type to use.

    List of Installation Tags & Features

    The table below lists our different types of implementation methods and features. Rows represent the types of implementation, while columns represent their inherent characteristics (mostly related to performance and flickering) and features (ability to track a visitor across domains, possibility to launch our application file via a Tag Manager).

    Definitions of these characteristics and features, as well as code for each implementation are provided in two later sections.

     FlickerMay block page loadingPrioritized script loadingCross Domain TrackingAffected by ITPUse with Tag Manager
    JavaScript file (Synchronous Loading) NoYesYesNoNoNo
    JavaScript file (Asynchronous Loading)YesNoYesNoNoYes
    JavaScript file (Asynchronous Loading with Anti-Flicker)NoNoNoNoNoNo
    Dual JavaScript & iFrame filesNoNoYesYesNoYes

    Description of Characteristics & Features

    This section defines and explains the characteristics and features presented in the previous table.

    Flicker

    The Flicker column indicates if this type of installation can induce a problem commonly occuring with JavaScript based A/B testing solutions, called the flicker effect. When your webpage is loading, it is possible that the original page displays for a split second instead of the variation. This twinkling is called flicker effect or flickering. Of course, this will confuse the visitor and can greatly distort the results of any experiment. We therefore strongly recommend making sure Kameleoon does not produce ANY flicker effect. Our platform includes built-in advanced techniques to completely eradicate flickering, but for this to happen, our installation recommendations must be followed.

    Flickering has two causes:

    To eliminate flickering due to the first reason, you just need to select an installation tag that has "No" in the corresponding Flicker column (in fact, all except the asynchronous JavaScript file will do the job). These methods guarantee that Kameleoon's code will be executed before any rendering of the page by the browser. In the case of synchronous loading, this is guaranteed automatically as long as the tag is included in the HTML <head> section, since the browser will not display anything until the Kameleoon application file is downloaded and executed. However, loading any resource in a blocking way is not a good practice, and we added a special anti-flickering technique to all the other asynchronous methods. Technically, we use a special CSS rule (* { visibility: hidden !important; background-image: none !important; }) that will "hide" the page being loaded. We remove this rule as soon as Kameleoon's application code has been run, OR if a customer specified time out is reached.

    Even if you use a correct implementation method, flickering effects can still occur, if the underlying engine of your A/B testing solution is not optimized to avoid them. In the case of Kameleoon, we guarantee these optimizations for any modification done by our graphical editor tool. For avanced variations that use custom JavaScript code, we provide APIs to guarantee this as well, but you must of course use them. Any modification on an element, or waiting for an element to appear on the page, should be done via our standard JavaScript API method (namely Kameleoon.API.runWhenElementPresent()), NOT via hand-coded pollers or other custom code.

    May block page loading

    If the servers (usually our Content Delivery Network, but it can also be your own CDN or server) hosting the Kameleoon application file are down or not responding, this characteristic mentions wether the loading of your website will be entirely blocked. Only one type of implementation implies this potential danger, the JavaScript file (Synchronous Loading) tag. All other methods will leave your website entirely functional even if all our hosting servers are down (which is, of course, something that should never happen in the first place).

    Technically, to avoid blocking if the hosting server is not available, we load the Kameleoon application file asynchronously. Still, since we do include a "blocking CSS rule" hiding the entire page's contents, in order to prevent flickering, we have to combine this with a timeout technique. Otherwise we would show a blank page indefinitely, which is not any better than blocking the loading of the page in the browser. After a given period of time (which we call the timeout period), if the Kameleoon application file is still not loaded, the tag will show the usual page's contents (which were hidden to avoid flickering). This way, we guarantee that in no circumstances can Kameleoon ever bring your website down.

    The timeout is controlled by the kameleoonLoadingTimeout JavaScript variable which you can set according to your needs (in the Kameleoon installation tag). By default it is equal to 1000 milliseconds, and we suggest leaving it as is. It represents the maximum amount of time the Kameleoon installation tag can "block" the display of your site while it is waiting for the Kameleoon application file.

    Prioritized script loading

    All static resources that an HTML page references (such as JavaScript files, CSS styles, Iframes, images ...) need to be downloaded by the browser before being used according to their type. For CSS or images they will just get displayed, for JS files and Iframes, some code will be executed, and so on. Browsers usually load resources by putting them in their network queue and then downloading them in a given order of priority. This order of priority is not clearly documented and is browser-dependent, but two important factors are to be considered for our purposes. First, a browser can only download a resource once it has been "discovered". Second, major browsers will assign a higher priority to the scripts that are included in the page statically, compared to the ones that are loaded dynamically via some JavaScript code. Eg, if you want a JS file to be loaded with higher priority, it's better to use this:

    <script type="text/javascript" src="resources/scripts/example.js" async></script>
    

    rather than this:

    <script type="text/javascript">
        var scriptNode = document.createElement("script");
        scriptNode.type = "text/javascript";
        scriptNode.src = "resources/scripts/example.js";
        document.head.appendChild(scriptNode);
    </script>
    

    Prioritized script loading means that the Kameleoon application file will be put at the top of the browser network queue. As a result, it will almost always load faster compared to a non-prioritized setup. This is thus a recommended option for Kameleoon, although the downside is that other resources will be delayed. Since we deem A/B testing an important feature that needs to load as soon as possible (compared to other technologies related to tracking or analytics, which can load later since they don't act on their host pages), we consider this to be a reasonable trade-off.

    Cross Domain Tracking

    Kameleoon offers support for cross-domain tracking which makes it possible to link sessions on several related sites as a single session. For instance, you may wish to consider that a visit started on https://portal.myecommercesite.com and continued on https://transaction-engine.myecommercesite.com (which are two websites that you own) form a single visit.

    This feature is very important for accurate data collection across different domains, if you own several of them. If an installation tag which doesn't support cross domain tracking has been chosen, then a visit that starts in one domain will be tracked as an entirely new visit once it reaches another related domain. All data gathered on one domain (such as number of page views, time spent on site...) will be reset on another domain, and thus targeting based on these kind of criteria can also produce unexpected results when cross domain is not used. For instance, let's suppose you have a personalization triggering at the fourth page viewed. A visitor goes to your first website, sees 3 pages, then loads a fourth in a new domain website. With cross-domain tracking, the personalization will indeed trigger; without it, it won't, since the page view on the new domain will be considered the first one of a new visit.

    Affected by ITP (Intelligent Tracking Prevention)

    Intelligent Tracking Prevention is a technology implemented by Apple in their Safari browsers (both mobile on iPhones and desktop on Macs). Mozilla has implemented a similar technology in their Firefox browser. Basically, the goal of this technology is to prevent unwanted, third-party tracking. Mostly this is intended as a way to prevent advertising trackers to track you accross several sites on the Web, and serve you targeted ads. However, unfortunately, this conflicts with the first-generation implementation of our cross-domain tracking feature. So if you're using the standalone iFrame setup, ITP can prevent data storage and loading via the cross domain Local Storage to work reliably on the mentionned browsers (Apple Safari, Mozilla Firefox, and more browsers are expected to implement this as well in the future).

    Our best (and newest) installation tag - Dual JavaScript & iFrame files - includes support for solving this conflict between ITP and cross-domain tracking. The only constraint is that you must host a static resource (an HTML file that never changes - you can just copy it once at setup and leave it untouched) on your main domain.

    Technically, instead of saving content via the browser's Local Storage on a third party Kameleoon domain (by default, SITE_CODE.kameleoon.eu), we will use your main domain to do so. Thus, the Kameleoon application storage space won't be considered third party but first party, and should not be affected by ITP. The iFrame file you will host contains a small, static code that only handles the reading and writing of Kameleoon data, independently of the domain of the current page.

    Use with Tag Manager

    Use with Tag Manager indicates whether the chosen implementation method allows you to use a tag manager or not. Kameleoon is compatible with all major Tag Management Systems (TMS). However, if possible, we really recommend you install Kameleoon directly in the source code of your pages, and not via a TMS. The reason for this is again related to the flicker effect. Using a TMS delays the load of Kameleoon and automatically creates a very noticeable flickering effect. This is especially problematic if your TMS is loaded at the bottom of your HTML page.

    However, we know that for some customers the use of a TMS (such as Google Tag Manager, Tag Commander, Tealium, etc) is mandatory. Inside a TMS, loading external JavaScript code synchronously is inherently impossible. Also, our anti-flicker prevention technology is not designed to work properly within a TMS. The implementation methods that allow being placed inside a TMS are the asynchronous JavaScript file, the iFrame standalone file, and the dual JavaScript & iFrame files. For the two last methods, the flickering prevention code has to be removed.

    Description of installation tags

    The installation tags presented on the right should ALWAYS be added in the <head> section of your HTML code. Never place the Kameleoon installation tags in the <body>, especially at the end of the page.

    In addition, it is highly recommended that you add these tags as high as possible in the <head> section. Ideally, they should be placed just after the initial opening <head> tag, so that the browser will load the Kameleoon application file before anything else. Any resources (CSS, other scripts...) placed before Kameleoon increase the risk of flickering.

    JavaScript File (Synchronous Loading)

    <script type="text/javascript" src="//static-bp.kameleoon.com/css/customers/SITE_CODE/0/kameleoon.js"></script>
    

    See the example on the right on how to install the Kameleoon application file synchronously. Make sure you replace the SITE_CODE placeholder with your own site code.

    This approach loads the Kameleoon script synchronously, without flickering. However, flickering is avoided because the loading of the page is blocked until the Kameleoon code is downloaded and executed, which is not recommended.

    JavaScript File (Asynchronous Loading)

    Standard implementation

    <script type="text/javascript" src="//static-bp.kameleoon.com/css/customers/SITE_CODE/0/kameleoon.js" async="true"></script>
    

    Tag Manager implementation

    var scriptNode = document.createElement("script");
    scriptNode.src = "//static-bp.kameleoon.com/css/customers/SITE_CODE/0/kameleoon.js";
    scriptNode.type = "text/javascript";
    scriptNode.async = true;
    scriptNode.setAttribute("data-tagmanager", true);
    document.head.appendChild(scriptNode);
    

    According to best practice, JavaScript external scripts should be loaded asynchronously. This ensures that page loading is not blocked while scripts are downloaded by the browser.

    To install Kameleoon application file asynchronously, without any attempt to avoid the flicker effect that can happen, use this method. Don't forget to replace the SITE_CODE placeholder by your own.

    JavaScript File (Asynchronous Loading with AntiFlicker)

    <script type="text/javascript">
        // Duration in milliseconds to wait while the Kameleoon application file is loaded
        var kameleoonLoadingTimeout = 1000;
    
        var kameleoonQueue = kameleoonQueue || [];
        var kameleoonStartLoadTime = new Date().getTime();
        if (! document.getElementById("kameleoonLoadingStyleSheet") && ! window.kameleoonDisplayPageTimeOut){
        var kameleoonS = document.getElementsByTagName("script")[0];var kameleoonCc = "* { visibility: hidden !important; background-image: none !important; }";
        var kameleoonStn = document.createElement("style");kameleoonStn.type = "text/css";kameleoonStn.id = "kameleoonLoadingStyleSheet";
        if (kameleoonStn.styleSheet){kameleoonStn.styleSheet.cssText = kameleoonCc;}else{kameleoonStn.appendChild(document.createTextNode(kameleoonCc));}kameleoonS.parentNode.insertBefore(kameleoonStn, kameleoonS);
        window.kameleoonDisplayPage = function(fromEngine){if (!fromEngine){window.kameleoonTimeout = true;} if (kameleoonStn.parentNode){kameleoonStn.parentNode.removeChild(kameleoonStn);}};
        window.kameleoonDisplayPageTimeOut = window.setTimeout(window.kameleoonDisplayPage, kameleoonLoadingTimeout);}
    </script>
    <script type="text/javascript" src="//static-bp.kameleoon.com/css/customers/SITE_CODE/0/kameleoon.js" async="true"></script>
    

    In this implementation method, the Kameleoon application file is still loaded asynchronously without blocking the page. It's still contained within a JavaScript file. However, until the Kameleoon code is executed, the page will be hidden via the help of a simple CSS rule. See the paragraph about flickering for details.

    Don't forget to replace the SITE_CODE placeholder by your own site code. Also pay attention to the kameleoonLoadingTimeout variable in the code, which can be changed according to your requirements.

    Standalone iFrame

    Standard implementation

    <script type="text/javascript">
        var kameleoonIframeURL = "https://SITE_CODE.kameleoon.eu";
        // Duration in milliseconds to wait while the Kameleoon application file is loaded
        var kameleoonLoadingTimeout = 1000;
    
        var kameleoonIframeOriginElement = document.createElement("a");
        kameleoonIframeOriginElement.href = kameleoonIframeURL;
        var kameleoonIframeOrigin = kameleoonIframeOriginElement.origin || (kameleoonIframeOriginElement.protocol + "//" + kameleoonIframeOriginElement.hostname);
        var kameleoonQueue = kameleoonQueue || [];
        var kameleoonStartLoadTime = new Date().getTime();
        var kameleoonProcessMessageEvent = function(event){if (kameleoonIframeOrigin == event.origin && event.data.slice && event.data.slice(0,9) == "Kameleoon"){window.removeEventListener("message", kameleoonProcessMessageEvent);window.kameleoonExternalIFrameLoaded = true;eval(event.data);Kameleoon.Analyst.load();}};
        if (window.addEventListener){window.addEventListener("message", kameleoonProcessMessageEvent, false);}
        if (! document.getElementById("kameleoonLoadingStyleSheet") && ! window.kameleoonDisplayPageTimeOut){
        var kameleoonS = document.getElementsByTagName("script")[0];var kameleoonCc = "* { visibility: hidden !important; background-image: none !important; }";
        var kameleoonStn = document.createElement("style");kameleoonStn.type = "text/css";kameleoonStn.id = "kameleoonLoadingStyleSheet";
        if (kameleoonStn.styleSheet){kameleoonStn.styleSheet.cssText = kameleoonCc;}else{kameleoonStn.appendChild(document.createTextNode(kameleoonCc));}kameleoonS.parentNode.insertBefore(kameleoonStn, kameleoonS);
        window.kameleoonDisplayPage = function(fromEngine){if (!fromEngine){window.kameleoonTimeout = true;} if (kameleoonStn.parentNode){kameleoonStn.parentNode.removeChild(kameleoonStn);}};
        window.setTimeout(function(){}, 25);
        window.kameleoonDisplayPageTimeOut = window.setTimeout(window.kameleoonDisplayPage, kameleoonLoadingTimeout);}
        var iframeNode = document.createElement("iframe");
        iframeNode.src = kameleoonIframeURL;
        iframeNode.id = "kameleoonExternalIframe";
        iframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";
        document.head.appendChild(iframeNode);
    </script>
    

    Tag Manager implementation

    var kameleoonIframeURL = "https://SITECODE.kameleoon.eu";
    // Duration in milliseconds to wait while the Kameleoon application file is loaded
    var kameleoonLoadingTimeout = 1000;
    
    var kameleoonQueue = kameleoonQueue || [];
    var kameleoonStartLoadTime = new Date().getTime();
    var kameleoonIframeOriginElement = document.createElement("a");
    kameleoonIframeOriginElement.href = kameleoonIframeURL;
    var kameleoonIframeOrigin = kameleoonIframeOriginElement.origin || (kameleoonIframeOriginElement.protocol + "//" + kameleoonIframeOriginElement.hostname);
    var kameleoonProcessMessageEvent = function(event){if (kameleoonIframeOrigin == event.origin && event.data.slice && event.data.slice(0,9) == "Kameleoon"){window.removeEventListener("message",
    kameleoonProcessMessageEvent);window.kameleoonExternalIFrameLoaded = true;window["eval"](event.data);Kameleoon.Analyst.load();}};
    if (window.addEventListener){window.addEventListener("message", kameleoonProcessMessageEvent, false);}
    var iframeNode = document.createElement("iframe");
    iframeNode.src = kameleoonIframeURL;
    iframeNode.id = "kameleoonExternalIframe";
    iframeNode.setAttribute("data-tagmanager", true);
    iframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";
    document.head.appendChild(iframeNode);
    

    The Standalone iFrame method also uses asynchronous loading with flickering prevention. The main difference is that this method supports our proprietary cross-domain tracking technology. This is our current official recommended implementation method.

    Don't forget to replace the SITE_CODE placeholder by your own site code. Also pay attention to the kameleoonLoadingTimeout variable in the code, which can be changed according to your requirements.

    Dual JavaScript & iFrame files

    Standard implementation (Multiple Domains)

    <link rel="preload" href="https://SITECODE.kameleoon.eu/kameleoon.js" as="script">
    <script type="text/javascript">
        var kameleoonIframeURL = "https://www.customerdomain.com/path/to/kameleoon-iframe.html";
        // Duration in milliseconds to wait while the Kameleoon application file is loaded
        var kameleoonLoadingTimeout = 1000;
    
        var kameleoonIframeOriginElement = document.createElement("a");
        kameleoonIframeOriginElement.href = kameleoonIframeURL;
        var kameleoonIframeOrigin = kameleoonIframeOriginElement.origin || (kameleoonIframeOriginElement.protocol + "//" + kameleoonIframeOriginElement.hostname);
        var kameleoonQueue = kameleoonQueue || [];
        var kameleoonLightIframe = false;
        var kameleoonStartLoadTime = new Date().getTime();
        if (! document.getElementById("kameleoonLoadingStyleSheet") && ! window.kameleoonDisplayPageTimeOut)
        {
            var kameleoonS = document.getElementsByTagName("script")[0];
            var kameleoonCc = "* { visibility: hidden !important; background-image: none !important; }";
            var kameleoonStn = document.createElement("style");
            kameleoonStn.type = "text/css";
            kameleoonStn.id = "kameleoonLoadingStyleSheet";
            if (kameleoonStn.styleSheet)
            {
                kameleoonStn.styleSheet.cssText = kameleoonCc;
            }
            else
            {
                kameleoonStn.appendChild(document.createTextNode(kameleoonCc));
            }
            kameleoonS.parentNode.insertBefore(kameleoonStn, kameleoonS);
            window.kameleoonDisplayPage = function(fromEngine)
            {
                if (! fromEngine)
                {
                    window.kameleoonTimeout = true;
                }
                if (kameleoonStn.parentNode)
                {
                    kameleoonStn.parentNode.removeChild(kameleoonStn);
                }
            };
            window.setTimeout(function() {}, 25);
            window.kameleoonDisplayPageTimeOut = window.setTimeout(window.kameleoonDisplayPage, kameleoonLoadingTimeout);
        }
        if (location.href.indexOf(kameleoonIframeOrigin) == -1)
        {
            kameleoonLightIframe = true;
            var kameleoonProcessMessageEvent = function(event)
            {
                if (kameleoonIframeOrigin == event.origin && event.data.slice && event.data.slice(0,9) == "Kameleoon")
                {
                    window.removeEventListener("message", kameleoonProcessMessageEvent);
                    window.kameleoonExternalIFrameLoaded = true;
                    if (window.Kameleoon)
                    {
                        eval(event.data);
                        Kameleoon.Analyst.load();
                    }
                    else
                    {
                        window.kameleoonExternalIFrameLoadedData = event.data;
                    }
                }
            };
            if (window.addEventListener)
            {
                window.addEventListener("message", kameleoonProcessMessageEvent, false);
            }
            var iframeNode = document.createElement("iframe");
            iframeNode.src = kameleoonIframeURL;
            iframeNode.id = "kameleoonExternalIframe";
            iframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";
            document.head.appendChild(iframeNode);
        }
    </script>
    <script type="text/javascript" src="//SITECODE.kameleoon.eu/kameleoon.js" async></script>
    

    Standard implementation (Single Domain)

    <link rel="preload" href="https://SITECODE.kameleoon.eu/kameleoon.js" as="script">
    <script type="text/javascript">
        // Duration in milliseconds to wait while the Kameleoon application file is loaded
        var kameleoonLoadingTimeout = 1000;
    
        var kameleoonQueue = kameleoonQueue || [];
        var kameleoonStartLoadTime = new Date().getTime();
        if (! document.getElementById("kameleoonLoadingStyleSheet") && ! window.kameleoonDisplayPageTimeOut)
        {
            var kameleoonS = document.getElementsByTagName("script")[0];
            var kameleoonCc = "* { visibility: hidden !important; background-image: none !important; }";
            var kameleoonStn = document.createElement("style");
            kameleoonStn.type = "text/css";
            kameleoonStn.id = "kameleoonLoadingStyleSheet";
            if (kameleoonStn.styleSheet)
            {
                kameleoonStn.styleSheet.cssText = kameleoonCc;
            }
            else
            {
                kameleoonStn.appendChild(document.createTextNode(kameleoonCc));
            }
            kameleoonS.parentNode.insertBefore(kameleoonStn, kameleoonS);
            window.kameleoonDisplayPage = function(fromEngine)
            {
                if (! fromEngine)
                {
                    window.kameleoonTimeout = true;
                }
                if (kameleoonStn.parentNode)
                {
                    kameleoonStn.parentNode.removeChild(kameleoonStn);
                }
            };
            window.setTimeout(function() {}, 25);
            window.kameleoonDisplayPageTimeOut = window.setTimeout(window.kameleoonDisplayPage, kameleoonLoadingTimeout);
        }
    </script>
    <script type="text/javascript" src="//SITECODE.kameleoon.eu/kameleoon.js" async></script>
    

    Tag Manager implementation (Multiple Domains)

    var kameleoonIframeURL = "https://www.customer-domain.com/kameleoon-iframe.html";
    // Duration in milliseconds to wait while the Kameleoon application file is loaded
    var kameleoonLoadingTimeout = 1000;
    
    var kameleoonIframeOriginElement = document.createElement("a");
    kameleoonIframeOriginElement.href = kameleoonIframeURL;
    var kameleoonIframeOrigin = kameleoonIframeOriginElement.origin || (kameleoonIframeOriginElement.protocol + "//" + kameleoonIframeOriginElement.hostname);
    var kameleoonQueue = kameleoonQueue || [];
    var kameleoonLightIframe = false;
    var kameleoonStartLoadTime = new Date().getTime();
    if (location.href.indexOf(kameleoonIframeOrigin) == -1) {
        kameleoonLightIframe = true;
        var kameleoonProcessMessageEvent = function (event) {
            if (kameleoonIframeOrigin == event.origin && event.data.slice && event.data.slice(0,9) == "Kameleoon") {
                window.removeEventListener("message", kameleoonProcessMessageEvent);
                window.kameleoonExternalIFrameLoaded = true;
                if (window.Kameleoon) {
                    window["eval"](event.data);
                    Kameleoon.Analyst.load();
                }
                else {
                    window.kameleoonExternalIFrameLoadedData = event.data;
                }
            }
        };
        if (window.addEventListener) {
            window.addEventListener("message", kameleoonProcessMessageEvent, false);
        }
        var iframeNode = document.createElement("iframe");
        iframeNode.src = kameleoonIframeURL;
        iframeNode.id = "kameleoonExternalIframe";
        iframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";
        document.head.appendChild(iframeNode);
    }
    var scriptNode = document.createElement("script");
    scriptNode.src = "//SITECODE.kameleoon.eu/kameleoon.js";
    scriptNode.type = "text/javascript";
    scriptNode.async = true;
    document.head.appendChild(scriptNode);
    

    Tag Manager implementation (Single Domain)

    var scriptNode = document.createElement("script");
    scriptNode.src = "//SITECODE.kameleoon.eu/kameleoon.js";
    scriptNode.type = "text/javascript";
    scriptNode.async = true;
    scriptNode.setAttribute("data-tagmanager", true);
    document.head.appendChild(scriptNode);
    

    The Dual JavaScript & iFrame implementation method is our most advanced one. The iFrame is loaded only if the page URL does not correspond to the main domain of the website, and only contains code used to save and restore visitor data in the Local Storage. This allows better performance for the pages hosted on the main domain, as loading a script (that is preloaded on modern browsers) is a lot quicker than loading an iFrame (iFrames seem to have higher penalties in the network queue).

    You need to provide the correct value for the kameleoonIframeURL variable in the installation code, and replace the SITE_CODE placeholder by your own site code. Be careful: there are two places where this needs to be done. Also pay attention to the kameleoonLoadingTimeout variable, which can be changed according to your requirements.

    Recommended implementation Method

    We provide an official recommended implementation method that we feel is best, according to our own extensive expertise related to Kameleoon performance impact on the hosting website. It would be false to claim Kameleoon has a totally null impact on performance. Every script or resource you add to your site inevitably carries some overhead. However, performance has always been a top priority for our engineers at Kameleoon, who have worked hundreds of hours, tweaking our code and technology, to obtain the best results possible. We claim to have the most performance optimized solution on the market - and we hope this article can convince you of this.

    At the time of writing, the official recommended method is the Standalone iFrame. Note that this recommended implementation method tries to strike a balance between the features offered by our platform and the minimization of the performance impact Kameleoon will have on your website. It is not necessarily the fastest approach, but if you wish to use the full range of features offered by our plateform, we encourage you to follow it.

    Special Case: Using your own CDN or hosting server (self-hosting)

    It is important to note that the Kameleoon application file can safely reside either on the Kameleoon CDN or on your own CDN (or servers). Hosting the Kameleoon application file on your own servers can give a small but noticeable performance boost, by removing the additional DNS query and SSL handshake needed if you use the Kameleoon CDN. Also, you may wish to self-host for security reasons (if the Kameleoon application file is served from your own servers, you can ensure your internal security policies are followed and you are responsible for the security of the hosting servers, instead of entrusting us with this responsibility).

    If you want to self-host the Kameleoon application file, follow these instructions (this is a separate article about the different options for using Kameleoon as an On-Premises platform rather than a SaaS platform).

    Common Mistakes

    <script type="text/javascript" src="resources/scripts/kameloon-loader.js"></script>
    

    while the kameloon-loader.js script contains for instance the following usual installation code:

    var kameleoonIframeURL = "https://SITE_CODE.kameleoon.eu";
    // Duration in milliseconds to wait while the Kameleoon application file is loaded
    var kameleoonLoadingTimeout = 1000;
    
    var kameleoonIframeOriginElement = document.createElement("a");
    kameleoonIframeOriginElement.href = kameleoonIframeURL;
    var kameleoonIframeOrigin = kameleoonIframeOriginElement.origin || (kameleoonIframeOriginElement.protocol + "//" + kameleoonIframeOriginElement.hostname);
    var kameleoonQueue = kameleoonQueue || [];
    var kameleoonStartLoadTime = new Date().getTime();
    var kameleoonProcessMessageEvent = function(event){if (kameleoonIframeOrigin == event.origin){window.removeEventListener("message", kameleoonProcessMessageEvent);window.kameleoonExternalIFrameLoaded = true;eval(event.data);Kameleoon.Analyst.load();}};
    if (window.addEventListener){window.addEventListener("message", kameleoonProcessMessageEvent, false);}
    if (! document.getElementById("kameleoonLoadingStyleSheet") && ! window.kameleoonDisplayPageTimeOut){
    var kameleoonS = document.getElementsByTagName("script")[0];var kameleoonCc = "* { visibility: hidden !important; background-image: none !important; }";
    var kameleoonStn = document.createElement("style");kameleoonStn.type = "text/css";kameleoonStn.id = "kameleoonLoadingStyleSheet";
    if (kameleoonStn.styleSheet){kameleoonStn.styleSheet.cssText = kameleoonCc;}else{kameleoonStn.appendChild(document.createTextNode(kameleoonCc));}kameleoonS.parentNode.insertBefore(kameleoonStn, kameleoonS);
    window.kameleoonDisplayPage = function(fromEngine){if (!fromEngine){window.kameleoonTimeout = true;} if (kameleoonStn.parentNode){kameleoonStn.parentNode.removeChild(kameleoonStn);}};
    window.setTimeout(function(){}, 25);
    window.kameleoonDisplayPageTimeOut = window.setTimeout(window.kameleoonDisplayPage, kameleoonLoadingTimeout);}
    var iframeNode = document.createElement("iframe");
    iframeNode.src = kameleoonIframeURL;
    iframeNode.id = "kameleoonExternalIframe";
    iframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";
    document.head.appendChild(iframeNode);
    

    While this may technically work, this is an extremely bad practice. It will literally kill the performance of Kameleoon and introduce a huge flicker effect. In fact, you're kind of implementing your own tag manager by doing that: you will suffer all the problems of using a tag manager without any of the associated benefits. Please, really, don't do it.

    FAQ

    Q. Can I use Subresource Integrity (SRI) with the Kameleoon application file (script or iframe)?

    A. Unfortunately no. While we like SRI's idea, and believe it is a good security feature in modern browsers, our application file changes over time. If it did not, we would not be able to provide most of the features Kameleoon is useful for. Eg, we would lose the ability to start and stop experiments instantly, without requiring a redeployment of the customer's web platform. Since the contents of our file changes, so does the hash of this ressource and thus SRI cannot be used (it would block our ressource as soon as it changes on our servers).

    Further Reading

    If you wish to learn even more about the technical details of external JavaScript code loading, here are some useful links.