Boomerang | Akamai Developer

Boomerang

Introduction

Boomerang is a JavaScript library for Real User Monitoring (commonly called RUM).

Boomerang measures the performance characteristics of real-world page loads and interactions.

The documentation on this page is for mPulse’s Boomerang.

General API documentation for Boomerang can be found at developer.akamai.com/tools/boomerang/docs/.

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.

Alternatively, Akamai CDN customers can add the mPulse behavior in Akamai Control Center’s Property Manager to automatically inject the minified Loader Snippet. The mPulse behavior allows you to choose the Loader Snippet version. Loader Snippet version choices include:

  • Version 10: Legacy IFRAME loader. Not auto-updated.
  • Version 12: IFRAME-less in supported browsers. Content Security Policy (CSP) compliant. Not auto-updated.
  • Latest: (currently Version 14) Can be updated with enhancements/fixes at any time.
  • Beta: (currently Version 15) Can be updated with enhancements/fixes at any time.

The mPulse Loader Snippet ensures Boomerang loads asynchronously and non-blocking, so it won’t affect the Page Load time. 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 (versions >= v12)
    • Websites using Google Tag Manager (GTM) to inject the Loader Snippet may not see beacons from Firefox <= 74
      • 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

Loder 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 here.
    • 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 <script> tag being id="boomerang-loader-script", will fallback to being a sibling of the first <script> 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 <script> tag, the same as IE 6 / 7
      • The document.write 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.

Single Page Apps

Why

Boomerang monitors Single Page App (SPA) navigations differently than how it monitors navigations on traditional websites. SPA frameworks such as AngularJS, Backbone.js, Ember.js, React, etc. are supported.

On traditional websites, the browser completes a full navigation for every page. During this navigation, the browser requests the page’s HTML, JavaScript, CSS, etc., from the server, and builds the page from these components. Boomerang monitors this entire process.

On SPA websites, only the first page that the visitor loads is a full navigation. All subsequent navigations are handled by the SPA framework itself (i.e. AngularJS), where they dynamically pull in the content they need to render the new page. This is done without executing a full navigation from the browser’s point of view.

Boomerang was designed for traditional websites, where a full navigation occurs on each page load. During the navigation, Boomerang tracks the performance characteristics of the entire page load experience. However, for SPA websites, only the first page triggers a full navigation. Thus, without any additional help, Boomerang will not track any subsequent interactions on SPA websites.

The History boomerang plugin instruments calls and monitors events from the browser’s History API. API calls such as pushState, replaceState, etc. and events such as hashchange and popstate are used to track the SPA navigations beyond the first, initial navigation. Once boomerang detects these events, the Boomerang SPA plugins start monitoring the page’s markup (DOM) for changes. If any of these changes trigger a download, such as a XHR, image, CSS, or JavaScript, then the Boomerang SPA plugins monitor those resources as well. Only once all of these new resources have been fetched do the Boomerang SPA plugins consider the SPA navigation complete.

For more information, see How mPulse XMLHttpRequest (XHR) and Single Page Application (SPA) Monitoring works.

If you are collecting ResourceTiming data in your SPA app, please also see how to manage the ResourceTiming buffer.

Terminology

  • Hard Navigation: the first navigation to the site, plus any of the work required to build the initial view. The Hard Navigation will track at least the length of onload​, but may also include the additional time required to load the framework (for example, Angular) and the first view. A SPA site will only have a SPA Hard Navigation, no “Page Load” beacons.
  • Soft Navigation: any navigation after the first Hard Navigation. A soft navigation is an “in-page” navigation where the view changes, but the browser does not actually fully navigate.

Metrics and Sessions

Page Groups, Custom Timers, Custom Metrics and Custom Dimensions are tracked on SPA websites the same way as on traditional websites (e.g. using XPath, Regex, JavaScript variables, cookies, CSS, etc).

Sessions are also tracked the same way as on traditional websites. The session length will increase every time the route (address bar) changes, and the session will be kept alive as long as user actions occur.

Configuration Options

The Boomerang History plugin allows users to automatically monitor Single Page App’s (SPA) navigations beyond the initial page load for SPA frameworks that leverage the window.history object for keeping state and routing (eg. AngularJS, Backbone.js, Ember.js, React, etc.).

For SPA frameworks that use window.history, all you have to do is to add the standard mPulse Loader Snippet, and check the Enable Single Page App (SPA) Monitoring feature in the mPulse Configure Web App dialog box under Single Page Application Framework.

Page-Level Override for Partial SPA Sites

If your website includes both SPA and non-SPA pages, page-level overrides ensure the SPA pages still track performance data.

If all of your pages are SPA:

  1. Check the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
  2. Insert the standard mPulse Loader Snippet.

If most of your pages are SPA:

  1. Check the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
  2. Insert the standard mPulse Loader Snippet.
  3. Add the following snippet on non-SPA page(s):
window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.autorun = true;
BOOMR_config.History = {
    enabled: false
};

If only one or a few of your pages are SPA:

  1. Uncheck the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
  2. Insert the standard mPulse Loader Snippet.
  3. Add the following snippet on SPA page(s):
window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.autorun = false;
BOOMR_config.History = {
    enabled: true
};

Excluding Certain Requests From Instrumentation

Whenever Boomerang intercepts an XMLHttpRequest, it will check if that request matches anything in the Boomerang XHR excludes list (BOOMR.xhr_excludes). If it does, Boomerang will not instrument, time, or beacon that request. If the excluded XHR happens during a SPA navigation, Boomerang will not track that XHR for purposes of extending the SPA navigation.

The exclude list is defined by creating an xhr_excludes object under the global window.BOOMR object, and adding in the URL parts that you would like to exclude from instrumentation. You can put any of the following in it:

  1. A full HREF
  2. A hostname
  3. A path

Example

BOOMR = window.BOOMR || {};

BOOMR.xhr_excludes = {
  "www.soasta.com":  true,
  "c.go-mpulse.net": true,
  "/api/v1/foobar":  true,
  "https://mpulse.soasta.com/dashboard/": true
};

In the above example, Boomerang will skip instrumentation for:

  • All URLs under www.soasta.com and c.go-mpulse.net
  • All URLs that exactly match the path /api/v1/foobar (regardless of the hostname or query string parameters)
  • The exact URL https://mpulse.soasta.com/dashboard/

Note that all of the above are exact matches (you cannot include wildcards).

Errors

The Boomerang Errors plugin automatically captures JavaScript and other errors from your web application.

Sources of Errors

When the Errors plugin is enabled, the following sources of errors are captured:

All of these options can be configured.

Supported Browsers

The Errors plugin can be enabled for all browsers, though some older browsers may not be able to capture the full breadth of sources of errors.

Notable browsers:

  • Internet Explorer <= 8: Does not support capturing XMLHttpRequest errors.

Manually Sending Errors

Besides automatically capturing errors from onerror, XMLHttpRequest, console.error or event handlers such as setTimeout, you can also manually send errors.

There are three ways of doing this as follows:

Dealing with Script Error

When looking at JavaScript errors, you will likely come across the generic error message: Script error.

Script Error. is the message that browsers send to the window.onerror global exception handler when the error was triggered by a script loaded from a different (cross) origin. window.onerror is used by Boomerang so that it gets notified of all unhandled exceptions.

The Script Error. string is given instead of the real error message and does not contain any useful information about what caused the error. In addition, there is no stack associated with the message, so it’s impossible to know where or why the error occurred.

Browsers mask the real error message for cross-origin scripts due to security and privacy concerns - they don’t want to leak sensitive information in the message or stack. The only thing that window.onerror knows for cross-origin scripts is that an error occurred, not where or why.

Example

For an example of where you’d see Script Error., consider the following code that lives on website.com:

<html>
    <head>
        <title>website.com</title>
    </head>
    <body>
        <script>
            window.onerror = function(message, url, line, column, error) {
                console.log("window.onerror: " + message);
                console.log((error && error.stack) ? error.stack : "(no stack)");
            };
        </script>
        <script src="my-script.js"></script>
        <script src="https://anothersite.com/my-script.js"></script>
    </body>
</html>

Assume my-script.js is the same file being served from both website.com and anothersite.com:

function runCode() {
    a = b + 1;
}

runCode();

When my-script.js is loaded from website.com, it will be executed twice:

  1. First on the same-origin, where we’ll see the full error message followed by the stack:

    window.onerror: Uncaught ReferenceError: b is not defined
    
    ReferenceError: b is not defined
        at runCode (my-script.js:2)
        at my-script.js:5
    
  2. Then, it will be loaded from https://anothersite.com/my-script.js, which will be considered cross-origin and only Script Error. will be logged:

    window.onerror: Script error.
    
    (no stack)
    

As you can see, browser shares the full details of the exception when it’s served from the same origin as the website, but if it’s served from any other origin, it will be considered cross-origin and no details will be shared.

Note that while the browser only shares Script Error. to window.onerror for cross-origin scripts, if you have browser developer tools open, the browser will show you the full error message in the Console. This is because there aren’t any security or privacy concerns for a developer looking at their own machine’s information.

The screenshot below shows what the Chrome Developer tools look like for the above code:

  1. The first (same-origin) error message is written to the console.log() (in black) followed by the browser developer tools logging the same error (in red).

  2. The second (cross-origin) error only shows Script error. in the console.log() (in black) with no stack, but the browser developer tools show the full message and stack (in red):

When You’ll See Script Error

Unfortunately Script Error. will be shown in many legitimate use-cases, such as:

  1. When serving your website’s JavaScript from a CDN (since it will be coming from a different origin)

  2. When loading a library such as jQuery or Angular from their CDN, i.e. Google’s Hosted Libraries or cdnjs

  3. When a third-party script loads from another domain

The good news is that in many of these cases, there are changes you can make to ensure the full error message and stack are shared with window.onerror.

Fixing Script Error

To ensure a cross-origin script shares full error details with window.onerror, you’ll need to do two things:

  1. Add crossorigin="anonymous" to the <script> tag

    The crossorigin="anonymous" attribute tells the browser that the script should be fetched without sending any cookies or HTTP authentication

  2. Add the Access-Control-Allow-Origin (ACAO) header to the JavaScript file’s response.

    The Access-Control-Allow-Origin header is part of the Cross Origin Resource Sharing (CORS) standard.

    The ACAO header must be set in the JavaScript’s HTTP response headers.

    An example header that sets ACAO for all calling origins would be:

    Access-Control-Allow-Origin: *

If both conditions are true, cross-origin JavaScript files will report errors to window.onerror with the correct error message and full stack.

The biggest challenge to getting this working is that (1) is within the site’s control while (2) can only be configured by the owner of the JavaScript. If you’re loading JavaScript from a third-party, you will need to encourage them to add the ACAO header if it’s not already set. The good news is that many CDNs and third-parties set the ACAO header already.

Workarounds for Third Parties that aren’t sending ACAO

One way to help monitor for errors coming from third-party scripts that aren’t setting ACAO (and aren’t within your control) is by manually wrapping calls to any of the third-party script’s functions in a try {} catch {}.

try {
    // calls a cross-origin script that doesn't have ACAO
    runThirdPartyCode();
} catch (e) {
    // report on error with e.message and e.stack
}

If runThirdPartyCode() causes any errors, the catch {} handler will get the full details of the exception.

Unfortunately this won’t work for functions that are executed in the third-party script as a result of browser events or callbacks (since you’re not wrapping them).

When using Boomerang to monitor JavaScript errors, Boomerang automatically wraps some of the built-in browser APIs such as setTimeout, setInterval and addEventListener with a minimal-overhead wrapper. It does this to help ensure as many cross-origin exceptions as possible have full stack details, but there may be compatibility issues when doing so. This behavior is controlled by the monitorEvents and monitorTimeout options for the plugin. They are enabled by default in Boomerang versions up to 1.700.0, but disabled by default in 1.710.0 and later. You may also do this wrapping manually via BOOMR.plugin.Errors.wrap(function).

Why is Boomerang in my Error Stack?

When looking at error reports, you may find errors that have a function in boomerang.js (or /boomerang/) on the stack. Why is that? Is Boomerang causing errors on your site?

One of the ways that Boomerang is able to monitor and measure your site’s performance is by wrapping itself around some of the core browser APIs. Boomerang only does this in a few places, if absolutely necessary – namely, when the browser doesn’t provide a native “monitoring” interface for something that needs to be tracked.

One example is for XMLHttpRequests, as there are no browser APIs to monitor when XHRs load. To monitor XHRs, Boomerang swaps in its own window.XMLHttpRequest object, wrapping around the native methods. When an XHR is created (via .open()), the lightweight Boomerang wrapper is executed first so it can log a start timestamp. When the XHR finishes (via a readyState change), Boomerang can log the end timestamp and report on the XHR’s performance.

Examples of Boomerang wrapping native methods include:

  • XMLHttpRequest if the XHR instrumentation is turned on
  • setTimeout and setInterval if error tracking is turned on
  • console.error if error tracking is turned on
  • addEventListener and removeEventListener if error tracking is turned on

All of these wrapped functions come into play when you see an error stack with a boomerang.js function in it.

Often, the boomerang.js function will be at the bottom of the stack (the first function called). This does not mean Boomerang caused the error, merely that the monitoring code was running before the error occurred. The actual error happens towards the top of the stack – the function that ran and threw the exception.

Let’s look at some examples:

Cannot read property 'foo' of undefined at thirdPartyTwo (https://thirdparty.com/core.js:1:100)
at thirdPartyOne (https://thirdparty.com/core.js:1:101)
at runThirdParty (https://thirdparty.com/core.js:1:102)
at xhrCallback (http://website.com/site.js:2:200)
at XMLHttpRequest.send (https://c.go-mpulse.net/boomerang/XXXXX-XXXXX-XXXXX-XXXXX-XXXXX:3:300)

In the above example, Boomerang is monitoring XMLHttpRequests. An XHR was loaded on the site, and during the XHR callback, an exception was thrown. Even though /boomerang/ is listed here, the error was caused by code in the XHR callback (xhrCallback eventually calling thirdPartyTwo).

Here’s a second example:

Reference error: a is not defined at setTimeout (http://website.com/site.js:1:200)
at BOOMR_plugins_errors_wrap (http://c.go-mpulse.net/boomerang/XXXXX-XXXXX-XXXXX-XXXXX-XXXXX:3:300)
at onclick (http://website.com/site.js:1:100)

In the above example, JavaScript Error Reporting is enabled and an exception was thrown in a setTimeout() on the website. You can see the BOOMR_plugins_errors_wrap function is near the top of the stack, but this is merely the error tracking code. All it did was wrap setTimeout to help ensure that cross-origin exceptions are caught. It was not the actual cause of the site’s error.

Here’s a third example:

Error: missing argument 1 at BOOMR.window.console.error (https://c.go-mpulse.net/boomerang/XXXXX-XXXXX-XXXXX-XXXXX-XXXXX:3:300)
at u/< (https://website.com/site.js:1:100)
at tp/this.$get</< (https://website.com/site.js:1:200)
at $digest (https://website.com/site.js:1:300)
at $apply (https://website.com/site.js:1:400)
at ut (https://website.com/site.js:1:500)
at it (https://website.com/site.js:1:600)
at vp/</k.onload (https://website.com/site.js:1:700)

In the above example, JavaScript Error Reporting is enabled and has wrapped console.error. The minified function u/< must be logging a console.error, which executes the Boomerang wrapper code, reporting the error.

In summary, if you see Boomerang functions in error stacks similar to any of the ones listed below, it’s probable that you’re just seeing a side-effect of the monitoring code:

  • BOOMR_addError
  • BOOMR_plugins_errors_onerror
  • BOOMR_plugins_errors_onxhrerror
  • BOOMR_plugins_errors_console_error
  • BOOMR_plugins_errors_wrap
  • BOOMR.window.console.error

Configuration Options

Enabling

Check the Collect Javascript Errors checkbox in the mPulse Configure Web App dialog box on the Beacons tab.

Enabling with Config Overrides

The Errors plugin is disabled by default, but can be enabled via Config Overrides:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.Errors = {
   enabled: true,
   monitorTimeout: false,
   monitorEvents: false
};

Sources

Each of the sources of errors can be turned off manually via the following monitor* options:

For example:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.Errors = {
    monitorGlobal: true,  // onerror
    monitorNetwork: true, // XHRs
    monitorConsole: true, // window.console.error
    monitorEvents: true,  // addEventListener
    monitorTimeout: true, // setTimeout, setInterval
};

Error callback

You can specify an onError function that the Errors plugin will call any time an error is captured on the page.

If your onError function returns true, the error will be captured. If your onError function does not return true, the error will be ignored.

For example:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.Errors = {
    onError: function(err) {
        if (err.message && err.message.indexOf("internally handled")) {
            return false;
        }
        return true;
    }
};

When to Send Errors

By default, errors captured during the page load will be sent along with the page load beacon. Errors that happen after the page load will not be captured or sent.

To enable this feature, check the Send Error Beacon if JavaScript Errors happen after the Page Load checkbox under the Collect Javascript Errors feature in the mPulse Configure Web App dialog box on the Beacons tab. The Send Interval (in milliseconds) text box controls the interval that errors occurring after the page load are sent on a new beacon.

Alternatively, to enable capturing of errors after page load via Config Overrides, set sendAfterOnload to true. If set, errors that happen after the page load will be sent at most once every sendInterval (which defaults to 1000 milliseconds) on a new beacon.

For example:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.Errors = {
    sendAfterOnload: true,
    sendInterval: 5000
};

How Many Errors to Capture

The Errors plugin will only capture up to maxErrors (defaults to 10) distinct errors on the page.

Please note that duplicate errors (those with the same function name, stack, and so on) are tracked as single distinct error, with a count of how many times it was seen.

Enter the desired value in the Maximum Number of Unique Errors to Track per Page text box under the Collect Javascript Errors feature in the mPulse Configure Web App dialog box on the Beacons tab.

Alternatively, maxErrors can be increased (or decreased) via Config Overrides. For example:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.Errors = {
    maxErrors: 2
};

Third Party Analytics (Big Beacon)

The Boomerang TPAnalytics plugin automatically captures third party analytics campaign information and optionally Client IDs from your web application.

See Data Collection from Third Party Analytics for more details.

Third party analytics vendors currently supported:

  • Google Analytics

  • Adobe Analytics (formerly Omniture Sitecatalyst)

  • IBM Digital Analytics (formerly Coremetrics)

Configuration Options

Enabling

Check the Collect Third-Party Analytics IDs checkbox in the mPulse Configure Web App dialog box on the Beacons tab. Optionally check the Collect Client IDs checkbox to capture third party Client IDs.

Enabling with Config Overrides

The TPAnalytics plugin is disabled by default, but can be enabled via Config Overrides. Capturing third party Client IDs is optional, and can be set with the clientids boolean. For example:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.TPAnalytics = {
     enabled: true,
     clientids: true
};

Early Beacon

Early beacons are beacons that are sent from Boomerang before the page’s onload event. Their purpose is to capture page views, performance and conversion metrics that are available before onload.

Boomerang has traditionally waited until the page has fully loaded before sending a beacon in order to capture the performance metrics of the load event. In certain cases, the user might close the page, manually cancel loading or navigate away before that happens. If this occurs, no beacon is sent and data about that navigation is lost. However, if Early Beacon is enabled for a page, the browser will send two beacons to mPulse: One Early beacon which is sent as soon as possible, and one regular Page Load beacon that contains all of the page’s performance information. If the Page Load beacon is sent then the Early beacon is discarded, if not, the metrics, dimensions and timers contained in the Early beacon are retained and are available in mPulse real-time dashboards.

mPulse customers will only be charged for a single beacon even if both the Early and regular Page Load beacon are sent.

Early beacons are sent after DOMContentLoaded to give the page enough time to set up the DOM and JavaScript variables that could be queried by custom metrics or dimensions.

In order to reduce overhead, Early beacons do not include resource timing or JavaScript error data.

In mPulse real-time dashboards, the default value for the Timer filter is Page Load. Since Early beacons do not include Page Load time, selecting a timer that is calculated before onload (eg. Back-End time) is required to view these beacons.

eg.

Boomerang requires application configuration from a mPulse server before sending a beacon. In order for Early beacons to be sent as soon as possible, configuration can be cached in the browser’s localStorage. Most conversion pages will not be the first page in a session and should have a cached config available.

Configuration Options

Enabling with Config Overrides

Enabling site wide

The Early plugin and Boomerang config caching are disabled by default, but can be enabled via Config Overrides. To enable Early beacons and browser caching of Boomerang config, add the following snippet to your pages:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.LOGN = {
    storeConfig: true
};
BOOMR_config.Early = {
    enabled: true
};

Alternatively, for Akamai CDN customers using mPulse Edge injection, this JSON Config Override configuration can be used in the mPulse behavior settings:

{
    "LOGN": {
        "storeConfig": true
    },
    "Early": {
        "enabled": true
    }
}

Enabling on specific pages

If required, Early Beacon can be enabled only on specifc pages (eg. checkout confirmation page). However, caching of Boomerand config should be enabled on all pages that are navigated to prior to those pages.

Add this Config Override to all pages to enable Boomerang config caching on the whole site:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.LOGN = {
    storeConfig: true
};

Add this Config Override to specific pages to enable Early Beacon only on those pages:

window.BOOMR_config = window.BOOMR_config || {};
BOOMR_config.LOGN = {
    storeConfig: true
};
BOOMR_config.Early = {
    enabled: true
};

Cookies

mPulse Session information

When an end-user browses to a site that’s instrumented with mPulse, Boomerang generates an RT cookie. It contains various pieces of information about the user’s session, as viewed by Boomerang. Here is an example:

nu=https%3A%2F%2Fwww.website.com%2Fus%2Fen%2Fweb-and-mobile-performance.jsp&dm=website.com&si=fe68c9ef-c89b-4918-b18d-b7faebd22524&ss=1500590776086&sl=1&tt=1353&obo=0&sh=1500590778761%3D1%3A0%3A1353&cl=1500590808877&bcn=%2F%2F36f10833.akstat.io%2F&r=https%3A%2F%2Fwww.website.com%2F&ul=1500590809249&hd=1500590809568

The individual subfields are as follows:

Field Description
bcn The URL that beacons will be sent to.
cl The timestamp of the most recent click event (epoch millis).
dm The mPulse-instrumented domain.
hd The timestamp of the previous page’s pagehide event (epoch millis).
nu The URL of a link on the current page that the user clicked on/submitted a form to in order to leave this page.
obo The number of pages visited in this session where Boomerang could not measure the page load time.
r The URL of the previous page visited in this session.
rl Rate limited flag. 1 if rate limited.
se Session expiry length (in seconds).
sh Session debugging information for the last 5 viewed pages [no longer used].
si The unique ID for this session.
sl The number of pages visited in the session (prior to the current page).
srst Details of the session prior to it being reset for expiry.
ss The session start time (epoch millis).
tt The sum of all page load times within this session.
ul The timestamp of the previous page’s unload event (epoch millis).

The RT cookie is never sent to mPulse servers, but is instead assigned to the domain of the site being instrumented (e.g. website.com). It’s used exclusively on the client side, by Boomerang.

The cookie is persistent, not a session cookie, and expires after 7 days of inactivity. This is because we want sessions to continue even if the end-user closes their browser and then returns within 30 minutes.

If the mPulse customer disables session tracking for their site, then Boomerang will not generate the RT cookie.

mPulse bandwidth testing information

When an end-user browses to a site that’s instrumented with mPulse and has bandwidth testing enabled, Boomerang generates a BA cookie. The cookie looks like this:

BA="ba=nnnnnnn&be=nnn.nn&l=nnnn&le=nn.nn&ip=iiiiii&t=sssssss"

The individual subfields are as follows:

Field Description
ba The user’s calculated network throughput in bytes per second
be The statistical standard error at the 95% confidence interval in calculating the user’s network throughput.
l The HTTP latency between the user’s computer and your server in milliseconds.
le The statistical standard error at the 95% confidence interval in calculating the user’s network latency.
ip Whatever was passed in as the user_ip configuration parameter to boomerang, used to rerun the test if the user’s network changes.
t The timestamp in seconds since the epoch when the bandwidth test was last run. Used to rerun the test if it was run more than 7 days ago.

When the Consent Inline Plugin is enabled we provide the option to an end-user to opt-in to or opt-out of mPulse. We use a first-party BOOMR_CONSENT cookie in order to remember an end-user’s choice. BOOMR_CONSENT is persistent, not a session cookie, and expires after 1 year of inactivity.

BOOMR_CONSENT cookie has 2 values: * opted-out - indicates that an end-user has opted-out. * opted-in - indicates that an end-user has opted-in.

Local Storage

For mPulse customers, in some instances Boomerang will persist data in Browser’s Local Storage. In these instances a Local Storage is used for performance optimization and reduction of network round trips.

List of local storage keys used by Boomerang:

Key Plugin Description
_boomr_LOGN LOGN Persists Boomerang JSON configuration. Helps for faster Boomerang initialization. Doesn’t contain personal information.
_boomr_akamaiXhrRetry Akamai Persists a flag that instructs the Akamai plugin when to perform requests. Doesn’t contain personal information.

How-Tos - Knowledge Base

Managing the ResourceTiming Buffer

ResourceTiming is a browser performance API that gathers accurate performance metrics about all of the resources fetched during the page load, such as images, CSS and JavaScript. Boomerang can capture this data automatically. The resources can then be visualized in the mPulse Waterfall dashboards.

By default, the Resource Timing API only tracks the first 150 resources on a page. While this limit can be manipulated by the developer in order to track more resources via window.performance.setResourceTimingBufferSize(), there are performance trade-offs (additional memory consumption) when doing this, so Boomerang doesn’t make these changes automatically.

If you are using one of the Boomerang SPA plugins, the browser might hit the 150 limit quickly, as the browser will not clear the resources for SPA navigations. Therefore, you may want to increase the buffer size or clear the resources every time a beacon is sent.

The following code examples show how you can increase the limit, or clear the resources after each Boomerang beacon.

Set the Resource Timings Buffer

To increase the ResourceTiming buffer size above the default of 150, you can use window.performance.setResourceTimingBufferSize(n):

(function(w){
    if (!w ||
        !("performance" in w) ||
        !w.performance ||
        !w.performance.setResourceTimingBufferSize) {
        return;
    }

    w.performance.setResourceTimingBufferSize(<size>);
})(window);

Clear the Resource Timings Buffer

To clear the ResourceTimings buffer on each beacon, you can use window.performance.clearResourceTimings():

(function(w){
    if (!w ||
        !("performance" in w) ||
        !w.performance ||
        !w.performance.clearResourceTimings) {
        return;
    }

    document.addEventListener(
        "onBoomerangBeacon",
        w.performance.clearResourceTimings.bind(w.performance));
})(window);

Alternatively, for Akamai CDN customers using mPulse Edge injection, this JSON Config Override configuration can be used in the mPulse behavior settings:

{
    "ResourceTiming": {
        "clearOnBeacon": true
    }
}

Content Security Policy (CSP)

Using the mPulse non-blocking loader snippet to include Boomerang on your site, via Akamai Edge injection or origin injection, requires merging the following CSP rules to your existing set of rules:

script-src https://*.go-mpulse.net; img-src https://*.akstat.io; connect-src https://*.akstat.io https://*.go-mpulse.net;

Explanation of individual rules:

  • script-src https://*.go-mpulse.net: The Boomerang JavaScript file will be downloaded from a host in the go-mpulse.net domain over HTTPS.

  • img-src https://*.akstat.io: Boomerang will send GET requests with beacon data to a host in the akstat.io domain using dynamically created IMG elements over HTTPS.

  • connect-src https://*.akstat.io: Boomerang will send POST requests with beacon data using XHR or the sendBeacon API to a host in the akstat.io domain over HTTPS.

  • connect-src https://*.go-mpulse.net: Boomerang will fetch it’s configuration from *.go-mpulse.net using XHR over HTTPS.

If the app is configured to track sessions across multiple domains then a frame-src CSP rule is required to whitelist the request to the cross domain HTML. Boomerang will request the page using an IFRAME.

frame-src [cross domain session host];

mPulse and Boomerang Blocked as a Tracker

Some browsers and browser extensions are adding new privacy features for their users which may tag certain third-party scripts and domains as “trackers”. In some cases, browsers are blocking these requests automatically on behalf of the user.

mPulse and Boomerang use multiple domains for operation:

  • c.go-mpulse.net / s.go-mpulse.net / s2.go-mpulse.net to load Boomerang
  • c.go-mpulse.net to load config.json
  • *.akstat.io to send the beacon

In many cases, those domains have been added to “trackers” lists that browsers/extensions are using. When any of those domains are blocked, mPulse will not be able to send a beacon.

Here are the currently know browsers and extensions and their blocking status:

  • Blocks mPulse / Boomerang out of the box:
    • Brave browser
    • uBlock Origin (extension)
    • Ghostery (extension)
    • Privacy Badger (extension)
    • Disabling JavaScript
  • Can be configured to block mPulse / Boomerang via opt-ins:
    • Mozilla Firefox (opting in to Strict mode instead of Standard)
    • Microsoft Edge (opting in to Strict mode instead of Balanced)
    • Opera browser (enabling Block Trackers)
    • AdBlock Plus (extension) (configuring EasyPrivacy list)
  • Does not block mPulse / Boomerang but support extensions that may:
    • Google Chrome
    • Apple Safari

We have filed issues with tracker lists to request removal:

The Boomerang Akamai Plugin

The Boomerang Akamai plugin is automatically included as part of Boomerang for mPulse. It was designed to help gather network topology information, which is then used to improve the performance of the Akamai CDN.

The Akamai plugin issues two XMLHttpRequests (XHRs) to two separate Akamai URLs, one supporting only IPv4 and the other supporting IPv4+IPv6. The data Akamai gathers from these XHRs assists the Akamai CDN in routing traffic in the most performant way through the network.

How does this help our customers?

Gathering this data helps improve the overall performance of the Akamai CDN, which should improve the performance of all Akamai customer websites.

Customers can choose to opt-out of this process by disabling the Akamai plugin, which will also disable the XHRs (see below).

What does the plugin do?

The plugin will issue an XHR for each of the following URLs:

  • https://trial-eum-clientnsv4-s.akamaihd.net (IPv4)
  • https://trial-eum-clienttons-s.akamaihd.net (IPv4+IPv6)

Akamai Network-Plugin

Both of these requests may 302 Redirect to another URL.

The browser’s LocalStorage is used to track when these requests were last sent. These XHRs will be sent at most once every 30 minutes per visitor.

Does the plugin affect the performance of my website?

The two XHRs are sent after the page has finished loading, so they should not affect the performance of the page load.

The XHRs contain no payload and the response is empty.

These requests are sent only once per user session on a 30 minute time window.

The plugin should have not any user perceivable effect on your website, but may show up in browser network traces and synthetic page load tests.

How can I disable the plugin?

The Akamai plugin can be disabled by executing the following JavaScript on the page:

window.BOOMR_config = window.BOOMR_config || {};
window.BOOMR_config.Akamai = {"enabled": false};

In the mPulse section of Control Center, a configuration option can be added to disable this data collection:

{ "Akamai": { "enabled": false } }

Boomerang Flavors

From Boomerang version 1.737.0 and onward we provide mPulse customers with an option to pick a specific Boomerang flavor based on the metrics and information they would like to collect. The motivation behind having different flavors is to deliver a version of Boomerang that is optimal in terms of transferred bytes to end-users. Delivering less bytes of Boomerang/JavaScript code means to end-users that Boomerang would be delivered faster, Boomerang code would need less device resources (CPU and memory) for parsing and evaluation and that more device resources (CPU, memory and network) would be free for processing other page assets as CSS, JavaScript, Images and etc.

There are 2 significant changes that are introduced with Boomerang Flavors:

  • Boomerang source code: Introducing 9 new sub-versions for Boomerangs with flavors.
  • mPulse app editor: Adding new UI elements to the mPulse App Editor that allow mPulse customers to pick easily a flavor of their choice or allow the App Editor to automatically pick an optimal flavor.

Boomerang source code

In each Boomerang version that has flavors we have 9 flavors that in case of Boomerang 1.737 are 1.737.0, 1.737.10, 1.737.20, 1.737.30, 1.737.40, 1.737.50, 1.737.60, 1.737.70, 1.737.80 (Reference: Flavors table) . A flavor in this case is a subset of Boomerang plugins that are bundled together (Reference: Plugins in flavors table).

Flavors table

Flavor Name File Size (brotli) Description
1.***.0 full 49 KB
The complete collection of Boomerang plugins allowing for the widest range of data collection features.
1.***.10 minimal 25 KB
Smallest bundle containing only the minimally required plugins to send a beacon.
1.***.20 default 29 KB
Standard web performance metrics. Excluding advanced features such as JavaScript error collection, Perceived Performance Metrics and and SPA monitoring.
1.***.30 default-errors 33 KB
Standard web performance metrics including JavaScript error collection. Excluding advanced features such as Perceived Performance Metrics and SPA monitoring.
1.***.40 default-spa 35 KB
Standard web performance metrics including support SPA performance monitoring. Excluding advanced features such as JavaScript error collection and Perceived Performance Metrics.
1.***.50 default-spa-errors 39 KB
Standard web performance metrics including SPA monitoring support and JavaScript error collection. Excluding advanced features such as Perceived Performance Metrics.
1.***.60 cutting-edge 34 KB
Standard web performance metrics including Perceived Performance Metrics support. Excluding advanced features such as JavaScript error collection and SPA monitoring.
1.***.70 cutting-edge-errors 38 KB
Standard web performance metrics including Perceived Performance Metrics and JavaScript error collection. Excluding advanced features such as SPA monitoring.
1.***.80 cutting-edge-spa 40 KB
Standard web performance metrics including Perceived Performance Metrics and SPA monitoring. Excluding advanced features such as JavaScript error collection.

Plugins in flavors table

Plugin Description 1.***.0 1.***.10 1.***.20 1.***.30 1.***.40 1.***.50 1.***.60 1.***.70 1.***.80
rt
Standard web performance metrics
page-params
Page Groups, custom timers, dimensions and metrics
config-override
navtiming
Navigation Timing API monitoring
eventtiming
Event Timing API monitoring
painttiming
Paint Timing and LCP monitoring
akamai
mq
Method queue
mobile
Network Information API monitoring
memory
Browser and page metrics
restiming
Resource Timing API monitoring
compression
Compression utility lib
cross-domain
Session tracking accross several domains
bw
Bandwith test
iframe-delay
Iframe Delay plugin
early
usertiming
User Timing API monitoring
third-party-analytics
cache-reload
Reload Boomerang
errors
auto-xhr
XHR and Fetch API monitoring
spa
history
History API helper for SPA plugin
continuity
Perceived Performance Metrics
1.***.0 1.***.10 1.***.20 1.***.30 1.***.40 1.***.50 1.***.60 1.***.70 1.***.80

Boomerang flavors in mPulse app editor

Flavor override mode

Not all Boomerang plugins can be configured from the App Editor. For example the iframe-delay plugin exists only in the 1.***.0 / full Boomerang flavor and can’t be activated from the App Editor. In such case the auto-select mode may choose a flavor that is not 1.***.0 / full but the Override mode will allow us to choose the 1.***.0 / full Boomerang flavor.

Flavor auto-select mode

In the following example “Collect JavaScript Errors” is selected and “Collect Perceived Performance Metrics” is not selected. This means that the Errors plugin is required but the Continuity plugin is not required. The optimal flavor in this case is 1.***.30 / default-errors which is 33 KB with brotli compression.

The App Editor will automatically pick 1.***.30 / default-errors if the Override checkbox is not ticked.

Troubleshooting

The following guides help you to troubleshoot Boomerang issues.

Browser Developer Tools

Many Boomerang issues will need to be debugged using Browser Developer Tools.

DevToolsSecrets.com has guides for how to use all of the common developer tools.

Generally, they can be opened via F12 or Ctrl-Shift-I in Windows, or Cmd-Option-I on the Mac.

Running Boomerang in a Development Environment

By default, mPulse will disable itself it is run on any of the following host names:

  • Any IP address
  • localhost
  • *.mhtml files
  • file:// URLs

mPulse disables itself so development environments (and saved pages) don’t mix in to production performance data.

If you are using a local development environment and would still like to send beacons, you have two options:

  1. Add window.BOOMR_LOGN_always = true to the page
  2. Run on an aliased hostname

Using BOOMR_LOGN_always

If you want to ensure mPulse runs in your development environment, you can make a small modification to your mPulse Loader Snippet.

Add this line before the rest of the snippet:

<script>
// add this line:
window.BOOMR_LOGN_always = true;

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

We do not recommend including this line in production code.

Using an Aliased Hostname

While mPulse will not run on an IP address or http://localhost, you can avoid this limitation by setting up a local DNS hostname alias that points at your local machine or any other IP address.

The easiest way to do this is to edit your hosts file. In the hosts file, you could add an alias for mymachine.domain.com 127.0.0.1 and it will look to the browser (and mPulse) like it is running on a real server.

On Unix, Linux and Mac OSX, you’ll want to edit /etc/hosts:

sudo nano /etc/hosts

On recent versions of Windows, you’ll want to edit %SystemRoot%\System32\drivers\etc\hosts. To do this, launch Notepad with Run As Administrator, and navigate to e.g. C:\Windows\System32\drivers\etc\hosts.

Once you have the file open in an editor, you’ll want to add a single line for your local machine (127.0.0.1) or the local IP address you’re using:

# Existing lines:
127.0.0.1    localhost
# ...

# Add this line:
127.0.0.1    mymachine.domain.com

Problems

Beacons Not Being Sent on Page Load

Boomerang sends beacons on page load to HTTP(s) endpoints with the pattern of *.mpstat.us or *.akstat.io.

To validate whether everything is working correctly:

  1. Validate whether the standard mPulse Loader Snippet is on the page.

    The loader snippet is required to load boomerang.js. By viewing the page’s source code, you should see the loader snippet JavaScript.

    If the loader snippet is not there, you will need to add it.

  2. Validate whether boomerang.js is loading via the browser developer tools.

    In the Networking tab, you should see a request to [c|s].go-mpulse.net/boomerang/[API-KEY].

    In the Source tab, you should see the minified boomerang.js source code.

    If you do not see boomerang.js in the Networking tab, check that the loader snippet is on the page.

  3. Validate whether config.js[on] is loading via the browser developer tools.

    config.js[on] contains app configuration and security tokens that are required for sending beacons.

    In the Networking tab, you should see a request to [c|s].go-mpulse.net/boomerang/config.js?key=[API-KEY].... or [c|s].go-mpulse.net/api/config.json?key=[API-KEY]....

    If you do not see config.js[on] in the Networking tab, check that boomerang.js has loaded, and validate there are no JavaScript errors from it in the Developer Tools Console.

  4. Validate whether beacons are being sent via the browser developer tools.

    In the Networking tab, you should see beacons being sent to a URL matching *.mpstat.us or *.akstat.io.

If you do not see beacons being sent, please review the following troubleshooting steps:

  1. Validate whether the Boomerang <IFRAME> in the <HEAD>.

    After the loader snippet executes, it will create an <IFRAME> in the <HEAD> of the HTML document. This <IFRAME> is used to load boomerang.js and config.js[on].

    This <IFRAME> must remain in the page for Boomerang to work.

    It will have a src of javascript:false, and a style of width: 0px; height: 0px; border: 0px; display: none.

    Within the <IFRAME>, it will have a <body onload="document._l()"> tag.

    Here is an example of a correct <IFRAME>:

    If the <IFRAME> is later removed, it will stop working, and it will not send beacons.

    Here is an example of what a removed <IFRAME> tag might look like. Note that the <body> was removed, even though the <IFRAME> is still there.

    If this has happened, there may be code on the website that is removing the <IFRAME> or modifying its contents.

API

General API documentation for Boomerang can be found at docs.soasta.com/boomerang-api/.

mPulse-specific documentation is below:

BOOMR.sendMetric(name, value)

The sendMetric() API sends a Custom Metric to mPulse.

The Custom Metric must already be defined in the mPulse app dialog.

For currencies, if sent a JavaScript number the value will be interpreted as cents (divided by 100). If sent a JavaScript string with a decimal, it will be interpreted as-is.

Parameters

  • name - String: Custom Metric name (not the JavaScript definition)
  • value - Number: Metric value (such as 1 or 10)

Example

// send an single metric
BOOMR.sendMetric("MyMetric", 2);
BOOMR.sendMetric("Currency1", 100); // $1.00
BOOMR.sendMetric("Currency2", "100.00"); // $100.00

BOOMR.sendMetrics(metrics)

The sendMetrics() API sends multiple Custom Metrics to mPulse.

The Custom Metrics must already be defined in the mPulse app dialog.

For currencies, if sent a JavaScript number the value will be interpreted as cents (divided by 100). If sent a JavaScript string with a decimal, it will be interpreted as-is.

Parameters

  • metrics - Object: A map of Custom Metric names to values

Example

// send multiple metrics at once
BOOMR.sendMetrics({
    "MyMetric": 2,
    "MyOtherMetric": 1,
    "Currency1": 100, // $1.00
    "Currency2": "100.00" // $100.00
});

BOOMR.sendTimer(name, value)

The sendTimer() API sends a Custom Timer to mPulse.

The Custom Timer must already be defined in the mPulse app dialog.

Parameters

  • name - String: Custom Timer name (not the JavaScript definition)
  • value - Number: Timer value (such as 10 or 1000) in milliseconds

Example

// send a single timer
BOOMR.sendTimer("MyTime", 200);

BOOMR.sendTimers(timers)

The sendTimers() API sends multiple Custom Timers to mPulse.

The Custom Timers must already be defined in the mPulse app dialog.

Parameters

  • timers - Object: A map of Custom Timer names to values

Example

// send multiple timers at once
BOOMR.sendTimers({
    "MyTime": 200,
    "MyOtherTime": 1000
});

BOOMR.sendAll(data)

The sendAll() API sends multiple Custom Metrics, Timers, Dimensions and other data to mPulse.

The Custom Metrics, Timers and Dimensions must already be defined in the mPulse app dialog.

Parameters

  • data.metrics - Object: A map of Custom Metric names to values (optional)
  • data.timers - Object: A map of Custom Timer names to values (optional)
  • data.vars - Object: A map of additional beacon values (optional)
  • data.when - number: Timestamp for the beacon (optional)

Example

BOOMR.sendAll({
    metrics: {
        MyMetric: 2,
        MyOtherMetric: 1,
        Currency1: 100, // $1.00
        Currency2: "100.00" // $100.00
    },
    timers: {
        MyTime: 200,
        MyOtherTime: 1000
    },
    vars: {
        "cdim.LoggedIn": true, // Custom Dimension named "LoggedIn"
        var2: 2
    },
    when: Date.now()
});