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


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.

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

(function() {
    // Boomerang Loader Snippet version 12
    if (window.BOOMR && (window.BOOMR.version || window.BOOMR.snippetExecuted)) {

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

    // NOTE: Set mPulse API Key
    window.BOOMR.url = "//" +
        "[API KEY GOES HERE]";

    var // document.currentScript is supported in all browsers other than IE
        where = document.currentScript || document.getElementsByTagName("script")[0],
        // 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) {

        var script = document.createElement("script"); = "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;


        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");
   = scriptId || "boomr-if-as";
            script.src = window.BOOMR.url;

            BOOMR_lstart = new Date().getTime();

            parent = parent || doc.body;

        // 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(where.parentNode, "boomr-async");

        // 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

        // Try to get the iframe's document object
        try {
            win = iframe.contentWindow;
            doc =;
        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.domain='" + dom + "';void(0);";
            win = iframe.contentWindow;

            doc =;

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

            // 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() {

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

        // Finish the document

    // 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";   = "script";

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

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

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

        // Append our link tag
    else {
        // No Preload support, use iframe loader

    // 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);

Configuration Overrides

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

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

    // ...
    // loader snippet above
    // ...

Single Page Apps


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.


  • 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


BOOMR = window.BOOMR || {};

BOOMR.xhr_excludes = {
  "":  true,
  "": true,
  "/api/v1/foobar":  true,
  "": true

In the above example, Boomerang will skip instrumentation for:

  • All URLs under and
  • All URLs that exactly match the path /api/v1/foobar (regardless of the hostname or query string parameters)
  • The exact URL

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


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:

These are all enabled by default, and can be manually turned off.

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.


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

            window.onerror = function(message, url, line, column, error) {
                console.log("window.onerror: " + message);
                console.log((error && error.stack) ? error.stack : "(no stack)");
        <script src="my-script.js"></script>
        <script src=""></script>

Assume my-script.js is the same file being served from both and

function runCode() {
    a = b + 1;


When my-script.js is loaded from, 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, 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
} 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. You may also do this 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 (
at thirdPartyOne (
at runThirdParty (
at xhrCallback (
at XMLHttpRequest.send (

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 (
at BOOMR_plugins_errors_wrap (
at onclick (

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 (
at u/< (
at tp/this.$get</< (
at $digest (
at $apply (
at ut (
at it (
at vp/</k.onload (

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


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

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


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 capturing of errors after page load, you need to set sendAfterOnload to true. If set, errors that happen after the page load will be sent at most once every sendInterval (which defaults to 1 second) 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.

You can increase (or decrease) maxErrors. 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 Session IDs and campaign information from your web application.

Third party analytics vendors currently supported:

  • Google Analytics

  • Adobe Analytics (formerly Omniture Sitecatalyst)

  • IBM Digital Analytics (formerly Coremetrics)

Configuration Options


The TPAnalytics plugin is disabled by default, but can be enabled via BOOMR_config:

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


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):

    if (!w ||
        !("performance" in w) ||
        !w.performance ||
        !w.performance.setResourceTimingBufferSize) {


Clear the Resource Timings Buffer

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

    if (!w ||
        !("performance" in w) ||
        !w.performance ||
        !w.performance.clearResourceTimings) {


From the Akamai Property Manager (Luna), under your mPulse settings, you can also use this Config Override instead:

    "ResourceTiming": {
        "clearOnBeacon": true


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:

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. 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:


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.


The following guides help you to troubleshoot Boomerang issues.

Browser Developer Tools

Many Boomerang issues will need to be debugged using Browser Developer Tools. 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:

// add this line:
window.BOOMR_LOGN_always = true;

    // ...
    // loader snippet above
    // ...

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 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 ( or the local IP address you’re using:

# Existing lines:    localhost
# ...

# Add this line:


Beacons Not Being Sent on Page Load

Boomerang sends beacons on page load to HTTP(s) endpoints with the pattern of * or *

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][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][API-KEY].... or [c|s][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 * or *

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.


General API documentation for Boomerang can be found at

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.


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


// send an single metric
BOOMR.sendMetric("MyMetric", 2);


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

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


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


// send multiple metrics at once
    "MyMetric": 2,
    "MyOtherMetric": 1

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.


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


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


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

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


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


// send multiple timers at once
    "MyTime": 200,
    "MyOtherTime": 1000

Content Security Policy (CSP)

mPulse Non-Blocking Loader Snippet

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://*; img-src https://*; connect-src https://*;

Explanation of individual rules:

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

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

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

  • connect-src Boomerang will fetch it’s configuration from 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];