Implementation

Once you've signed up for a mPulse account, you will be given an API key.

To integrate mPulse into your site, you will need to include the mPulse Loader Snippet, which loads Boomerang in a performant way.

mPulse Non-Blocking Loader Snippet

Paste the following code snippet into every page of your site at the top of the HEAD, but after sensitive META tags.

See the mPulse non-blocking loader snippet tutorial for more information.

A minified version of this snippet is provided below. You should use the minified version in a production environment.

Replace [API KEY GOES HERE] with your mPulse API key.

<script>
(function() {
    // Boomerang Loader Snippet version 14
    if (window.BOOMR && (window.BOOMR.version || window.BOOMR.snippetExecuted)) {
        return;
    }

    window.BOOMR = window.BOOMR || {};
    window.BOOMR.snippetStart = new Date().getTime();
    window.BOOMR.snippetExecuted = true;
    window.BOOMR.snippetVersion = 14;

    // NOTE: Set mPulse API Key
    window.BOOMR.url = "//c.go-mpulse.net/boomerang/" +
        "[API KEY GOES HERE]";

    var // document.currentScript is supported in all browsers other than IE
        where = document.currentScript || document.getElementsByTagName("script")[0],
        // Parent element of the script we inject
        parentNode = where.parentNode,
        // Whether or not Preload method has worked
        promoted = false,
        // How long to wait for Preload to work before falling back to iframe method
        LOADER_TIMEOUT = 3000;

    // Tells the browser to execute the Preloaded script by adding it to the DOM
    function promote() {
        if (promoted) {
            return;
        }

        var script = document.createElement("script");
        script.id = "boomr-scr-as";
        script.src = window.BOOMR.url;

        // Not really needed since dynamic scripts are async by default and the script is already in cache at this point,
        // but some naive parsers will see a missing async attribute and think we're not async
        script.async = true;

        parentNode.appendChild(script);

        promoted = true;
    }

    // Non-blocking iframe loader (fallback for non-Preload scenarios) for all recent browsers.
    // For IE 6/7, falls back to dynamic script node.
    function iframeLoader(wasFallback) {
        promoted = true;

        var dom, doc = document, bootstrap, iframe, iframeStyle, win = window;

        window.BOOMR.snippetMethod = wasFallback ? "if" : "i";

        // Adds Boomerang within the iframe
        bootstrap = function(parent, scriptId) {
            var script = doc.createElement("script");
            script.id = scriptId || "boomr-if-as";
            script.src = window.BOOMR.url;

            BOOMR_lstart = new Date().getTime();

            parent = parent || doc.body;
            parent.appendChild(script);
        };

        // For IE 6/7, we'll just load the script in the current frame, as those browsers don't support 'about:blank'
        // for an iframe src (it triggers warnings on secure sites).  This means loading on IE 6/7 may cause SPoF.
        if (!window.addEventListener && window.attachEvent && navigator.userAgent.match(/MSIE [67]\./)) {
            window.BOOMR.snippetMethod = "s";

            bootstrap(parentNode, "boomr-async");
            return;
        }

        // The rest of this function is IE8+ and other browsers that don't support Preload hints but will work with CSP & iframes
        iframe = document.createElement("IFRAME");

        // An empty frame
        iframe.src = "about:blank";

        // We set title and role appropriately to play nicely with screen readers and other assistive technologies
        iframe.title = "";
        iframe.role = "presentation";

        // Ensure we're not loaded lazily
        iframe.loading = "eager";

        // Hide the iframe
        iframeStyle = (iframe.frameElement || iframe).style;
        iframeStyle.width = 0;
        iframeStyle.height = 0;
        iframeStyle.border = 0;
        iframeStyle.display = "none";

        // Append to the end of the current block
        parentNode.appendChild(iframe);

        // Try to get the iframe's document object
        try {
            win = iframe.contentWindow;
            doc = win.document.open();
        }
        catch (e) {
            // document.domain has been changed and we're on an old version of IE, so we got an access denied.
            // Note: the only browsers that have this problem also do not have CSP support.

            // Get document.domain of the parent window
            dom = document.domain;

            // Set the src of the iframe to a JavaScript URL that will immediately set its document.domain to match the parent.
            // This lets us access the iframe document long enough to inject our script.
            // Our script may need to do more domain massaging later.
            iframe.src = "javascript:var d=document.open();d.domain='" + dom + "';void 0;";
            win = iframe.contentWindow;

            doc = win.document.open();
        }

        if (dom) {
            // Unsafe version for IE8 compatibility. If document.domain has changed, we can't use win, but we can use doc.
            doc._boomrl = function() {
                this.domain = dom;
                bootstrap();
            };

            // Run our function at load.
            // Split the string so HTML code injectors don't get confused and add code here.
            doc.write("<bo" + "dy onload='document._boomrl();'>");
        }
        else {
            // document.domain hasn't changed, regular method should be OK
            win._boomrl = function() {
                bootstrap();
            };

            if (win.addEventListener) {
                win.addEventListener("load", win._boomrl, false);
            }
            else if (win.attachEvent) {
                win.attachEvent("onload", win._boomrl);
            }
        }

        // Finish the document
        doc.close();
    }

    // See if Preload is supported or not
    var link = document.createElement("link");

    if (link.relList &&
        typeof link.relList.supports === "function" &&
        link.relList.supports("preload") &&
        ("as" in link)) {
        window.BOOMR.snippetMethod = "p";

        // Set attributes to trigger a Preload
        link.href = window.BOOMR.url;
        link.rel  = "preload";
        link.as   = "script";

        // Add our script tag if successful, fallback to iframe if not
        link.addEventListener("load", promote);
        link.addEventListener("error", function() {
            iframeLoader(true);
        });

        // Have a fallback in case Preload does nothing or is slow
        setTimeout(function() {
            if (!promoted) {
                iframeLoader(true);
            }
        }, LOADER_TIMEOUT);

        // Note the timestamp we started trying to Preload
        BOOMR_lstart = new Date().getTime();

        // Append our link tag
        parentNode.appendChild(link);
    }
    else {
        // No Preload support, use iframe loader
        iframeLoader(false);
    }

    // Save when the onload event happened, in case this is a non-NavigationTiming browser
    function boomerangSaveLoadTime(e) {
        window.BOOMR_onload = (e && e.timeStamp) || new Date().getTime();
    }

    if (window.addEventListener) {
        window.addEventListener("load", boomerangSaveLoadTime, false);
    }
    else if (window.attachEvent) {
        window.attachEvent("onload", boomerangSaveLoadTime);
    }
})();
</script>

Minified

Replace [API KEY GOES HERE] with your mPulse API key.

<script>
(function(){if(window.BOOMR&&(window.BOOMR.version||window.BOOMR.snippetExecuted)){return}window.BOOMR=window.BOOMR||{};window.BOOMR.snippetStart=(new Date).getTime();window.BOOMR.snippetExecuted=true;window.BOOMR.snippetVersion=14;window.BOOMR.url="//c.go-mpulse.net/boomerang/[API KEY GOES HERE]";var e=document.currentScript||document.getElementsByTagName("script")[0],a=e.parentNode,s=false,t=3e3;function n(){if(s){return}var e=document.createElement("script");e.id="boomr-scr-as";e.src=window.BOOMR.url;e.async=true;a.appendChild(e);s=true}function o(e){s=true;var t,o=document,n,i,d,r=window;window.BOOMR.snippetMethod=e?"if":"i";n=function(e,t){var n=o.createElement("script");n.id=t||"boomr-if-as";n.src=window.BOOMR.url;BOOMR_lstart=(new Date).getTime();e=e||o.body;e.appendChild(n)};if(!window.addEventListener&&window.attachEvent&&navigator.userAgent.match(/MSIE [67]\./)){window.BOOMR.snippetMethod="s";n(a,"boomr-async");return}i=document.createElement("IFRAME");i.src="about:blank";i.title="";i.role="presentation";i.loading="eager";d=(i.frameElement||i).style;d.width=0;d.height=0;d.border=0;d.display="none";a.appendChild(i);try{r=i.contentWindow;o=r.document.open()}catch(e){t=document.domain;i.src="javascript:var d=document.open();d.domain='"+t+"';void 0;";r=i.contentWindow;o=r.document.open()}if(t){o._boomrl=function(){this.domain=t;n()};o.write("<bo"+"dy onload='document._boomrl();'>")}else{r._boomrl=function(){n()};if(r.addEventListener){r.addEventListener("load",r._boomrl,false)}else if(r.attachEvent){r.attachEvent("onload",r._boomrl)}}o.close()}var i=document.createElement("link");if(i.relList&&typeof i.relList.supports==="function"&&i.relList.supports("preload")&&"as"in i){window.BOOMR.snippetMethod="p";i.href=window.BOOMR.url;i.rel="preload";i.as="script";i.addEventListener("load",n);i.addEventListener("error",function(){o(true)});setTimeout(function(){if(!s){o(true)}},t);BOOMR_lstart=(new Date).getTime();a.appendChild(i)}else{o(false)}function d(e){window.BOOMR_onload=e&&e.timeStamp||(new Date).getTime()}if(window.addEventListener){window.addEventListener("load",d,false)}else if(window.attachEvent){window.attachEvent("onload",d)}})();
</script>

IFRAME-less Loader Snippet v12+

The mPulse Loader Snippet is continually being improved to make it more performant, reliable and compatible. Using the mPulse Loader Snippet (instead of an inline <script src="..."> tag) ensures Boomerang loads asynchronously and non-blocking, so it won’t affect the page’s performance.

Versions 1 through 10 (v1 - v10) of this snippet utilized an IFRAME to host Boomerang, which got it out of the critical path, to ensure Boomerang was able to load asynchronously and non-blocking.

The latest versions of the mPulse Loader Snippet (v12+) have a significant change, to utilize Preload on modern browsers (instead of an IFRAME) to load Boomerang asynchronously.

The IFRAME-less mPulse Loader Snippet (v12+) has multiple benefits versus older versions (<= v10), as long as the browser supports Preload:

  • Boomerang executes in the main page instead of an IFRAME.
  • No IFRAME is created in the <head> of the document (improves Search Engine Optimization issues in some cases).
  • Avoids the performance cost of creating an IFRAME (20-40ms).
  • Avoids using document.write() (which is being deprecated).
  • Content-Security-Policy (CSP) compliant.

Please note that browsers which don’t support Preload (such as Internet Explorer and Firefox) will still use the IFRAME fallback.

If upgrading from an older version of the snippet (<= v10) to an IFRAME-less snippet (>= v12), please make sure to test the changes to make sure there are no compatibility issues.

Boomerang 1.629.0 or later should be used with the IFRAME-less snippet to avoid compatibility issues.

Loader Snippet Known Issues

  • IFRAME-less (version 12 or newer)
    • Websites using Google Tag Manager (GTM) to inject the Loader Snippet may not see beacons from Firefox 74 or older.
    • These versions of Firefox do not support Preload, so fallback to using the IFRAME loader.
    • boomerang.js is not fetched due to a Firefox bug with setting the iframe.src = "about:blank", which is done for Content Security Policies (CSP) compatibility.
    • Websites that are not using Content Security Policies can change: // An empty frame iframe.src = "about:blank"; to // An empty frame iframe.src = "javascript:void(0)";.
    • Websites that are using Content Security Policies should use a <script async src="//c.go-mpulse.net/boomerang/[API KEY GOES HERE]"> tag to load boomerang.js instead of the Loader Snippet.

Loader Snippet Version History

Version 10: December 18, 2017

  • Escape <body tag injection to avoid server-side parsers that incorrectly string replace <body with something else.
  • Added a version comment to the beginning of the snippet.

Version 11: June 6, 2018

  • <link rel="preload"> support
    • IFRAME-less
    • Removes document.write entirely
  • Removes IE 6 / 7 support
  • Adds the <link> / <iframe> / <script> as the last sibling of the document.currentScript instead of before the first <script> on the page.
  • Depends on the <script> tag being id="boomerang-loader-script".
  • Added BOOMR_mq postMessage() listener.

Version 12: January 17, 2019

  • CSP-compliant (changes IFRAME .src from javascript:void(0) to about:blank to avoid unsafe-inline). CSP compliance is documented in Content Security Policy (CSP).
  • Adds support for IE 6 / 7 back in via sync <script> tag.
  • Adds support for IE 8 with document.domain set via document.write.
  • Keeps track of the BOOMR.snippetVersion and BOOMR.snippetMethod.
  • Removes dependency on the tag if .currentScript doesn’t work.
  • Fixes an issue where if Preload times out at 3 seconds, but still later succeeds, the promotion (<script> tag) would still happen even if the IFRAME method had started.
  • Ensures we track BOOMR_lstart for Preload method.
  • Adds loading="eager" to the IFRAME to avoid lazy loading.
  • Removed BOOMR_mq postMessage() listener for XSS security concerns.

Version 14: January, 2020

  • Keeps a reference to the parentNode during startup in case the first <script> tag is later removed
  • Changes IFRAME src syntax from void(0) to void 0.
  • Comment spelling fix

Version 15: July, 2021

  • Removes document.write logic for IE 8 in favor of sync code was flagging developer warnings in modern browsers even though it wasn’t being run.
  • IE 8 is approx 0.001% of traffic in 2021 (according to mPulse).

Configuration Overrides

When a configuration override is required, the window.BOOMR_config object should be defined above the mPulse loader snippet:

<script>
window.BOOMR_config = window.BOOMR_config || {};

// set global options
window.BOOMR_config.autorun = false;

// set a plugin's options
window.BOOMR_config.History = {
    enabled: true,
    auto: true
};

(function(){
    // ...
    // loader snippet above
    // ...
})();
</script>

Alternatively, for Akamai CDN customers using mPulse Edge injection, Config Overrides can be set in the property's configuration.

📘

Note

Config Overrides can be set in Akamai Control Center's Property Manager, under the mPulse behavior settings. Config Overrides set this way must be in JSON format.