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
: (currentlyVersion 14
) Can be updated with enhancements/fixes at any time.Beta
: (currentlyVersion 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 15
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 = 15;
// 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/8, 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/8, we'll just load the script in the current frame:
// * IE 6/7 don't support 'about:blank' for an iframe src (it triggers warnings on secure sites)
// * IE 8 required a doc write call for it to work, which is bad practice
// This means loading on IE 6/7/8 may cause SPoF.
if (!window.addEventListener && window.attachEvent && navigator.userAgent.match(/MSIE [678]\./)) {
window.BOOMR.snippetMethod = "s";
bootstrap(parentNode, "boomr-async");
return;
}
// The rest of this function is for 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();
}
// 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=15;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 i(e){s=true;var t,i=document,n,o,d,r=window;window.BOOMR.snippetMethod=e?"if":"i";n=function(e,t){var n=i.createElement("script");n.id=t||"boomr-if-as";n.src=window.BOOMR.url;BOOMR_lstart=(new Date).getTime();e=e||i.body;e.appendChild(n)};if(!window.addEventListener&&window.attachEvent&&navigator.userAgent.match(/MSIE [678]\./)){window.BOOMR.snippetMethod="s";n(a,"boomr-async");return}o=document.createElement("IFRAME");o.src="about:blank";o.title="";o.role="presentation";o.loading="eager";d=(o.frameElement||o).style;d.width=0;d.height=0;d.border=0;d.display="none";a.appendChild(o);try{r=o.contentWindow;i=r.document.open()}catch(e){t=document.domain;o.src="javascript:var d=document.open();d.domain='"+t+"';void 0;";r=o.contentWindow;i=r.document.open()}r._boomrl=function(){n()};if(r.addEventListener){r.addEventListener("load",r._boomrl,false)}else if(r.attachEvent){r.attachEvent("onload",r._boomrl)}i.close()}var o=document.createElement("link");if(o.relList&&typeof o.relList.supports==="function"&&o.relList.supports("preload")&&"as"in o){window.BOOMR.snippetMethod="p";o.href=window.BOOMR.url;o.rel="preload";o.as="script";o.addEventListener("load",n);o.addEventListener("error",function(){i(true)});setTimeout(function(){if(!s){i(true)}},t);BOOMR_lstart=(new Date).getTime();a.appendChild(o)}else{i(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
- Websites using Google Tag Manager (GTM) to inject the Loader Snippet may not see beacons from Firefox <= 74
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
- Escape
- 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 thedocument.currentScript
instead of before the first<script>
on the page - Depends on the
<script>
tag beingid="boomerang-loader-script"
- Added
BOOMR_mq
postMessage()
listener
- Version 12: January 17, 2019
- CSP-compliant (changes IFRAME
.src
fromjavascript:void(0)
toabout:blank
to avoidunsafe-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 viadocument.write
- Keeps track of the
BOOMR.snippetVersion
andBOOMR.snippetMethod
- Removes dependency on the
<script>
tag beingid="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
- CSP-compliant (changes IFRAME
- 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 fromvoid(0)
tovoid 0
- Comment spelling fix
- Keeps a reference to the
- 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)
- The
- Removes
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:
- Check the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
- Insert the standard mPulse Loader Snippet.
If most of your pages are SPA:
- Check the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
- Insert the standard mPulse Loader Snippet.
- 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:
- Uncheck the Enable Single Page App (SPA) Monitoring checkbox in the mPulse Configure Web App dialog box.
- Insert the standard mPulse Loader Snippet.
- 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:
- A full HREF
- A hostname
- 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
andc.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:
- JavaScript runtime errors captured via the
onerror
global event handler XMLHttpRequest
responses that were not successful- Any calls to
window.console.error
- JavaScript runtime errors that happen during a callback for
addEventListener
- JavaScript runtime errors that happen during a callback for
setTimeout
andsetInterval
- Manually sent errors via
BOOMR.plugin.Errors.send(message|exception)
- Functions that threw an exception that were wrapped via
BOOMR.plugin.Errors.wrap(function)
- Functions that threw an exception that were run via
BOOMR.plugin.Errors.test(function, arg1, arg2)
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:
BOOMR.plugin.Errors.send()
: Immediately sends an error.BOOMR.plugin.Errors.wrap()
: Wraps a function with error trackingBOOMR.plugin.Errors.test()
: Runs the function and captures any errors.
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:
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
Then, it will be loaded from
https://anothersite.com/my-script.js
, which will be considered cross-origin and onlyScript 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:
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).The second (cross-origin) error only shows
Script error.
in theconsole.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:
When serving your website’s JavaScript from a CDN (since it will be coming from a different origin)
When loading a library such as jQuery or Angular from their CDN, i.e. Google’s Hosted Libraries or cdnjs
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:
Add
crossorigin="anonymous"
to the<script>
tagThe
crossorigin="anonymous"
attribute tells the browser that the script should be fetched without sending any cookies or HTTP authenticationAdd 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 onsetTimeout
andsetInterval
if error tracking is turned onconsole.error
if error tracking is turned onaddEventListener
andremoveEventListener
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:
monitorGlobal
enables theonerror
global event handlermonitorNetwork
enables monitoringXMLHttpRequest
responses (Automatically Instrument XHR also needs to be enabled)monitorConsole
enables monitoring calls towindow.console.error
monitorEvents
enables monitoringaddEventListener
callbacksmonitorTimeout
enables monitoringsetTimeout
andsetInterval
callbacks
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. |
mPulse consent information
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 thego-mpulse.net
domain over HTTPS.img-src https://*.akstat.io
: Boomerang will send GET requests with beacon data to a host in theakstat.io
domain using dynamically createdIMG
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 theakstat.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 Boomerangc.go-mpulse.net
to loadconfig.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)
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
filesfile://
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:
- Add
window.BOOMR_LOGN_always = true
to the page - 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:
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.
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.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 thatboomerang.js
has loaded, and validate there are no JavaScript errors from it in the Developer Tools Console.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:
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 loadboomerang.js
andconfig.js[on]
.This
<IFRAME>
must remain in the page for Boomerang to work.It will have a
src
ofjavascript:false
, and a style ofwidth: 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 as1
or10
)
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 as10
or1000
) 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()
});