Implementation
Once you've signed up for a mPulse account, you will be given an API key.
To integrate mPulse into your site, you will need to include the mPulse Loader Snippet, which loads Boomerang in a performant way.
mPulse Non-Blocking Loader Snippet
Paste the following code snippet into every page of your site at the top of the HEAD, but after sensitive META tags.
See the mPulse non-blocking loader snippet tutorial for more information.
A minified version of this snippet is provided below. You should use the minified version in a production environment.
Replace [API KEY GOES HERE]
with your mPulse API key.
<script>
(function() {
// Boomerang Loader Snippet version 14
if (window.BOOMR && (window.BOOMR.version || window.BOOMR.snippetExecuted)) {
return;
}
window.BOOMR = window.BOOMR || {};
window.BOOMR.snippetStart = new Date().getTime();
window.BOOMR.snippetExecuted = true;
window.BOOMR.snippetVersion = 14;
// NOTE: Set mPulse API Key
window.BOOMR.url = "//c.go-mpulse.net/boomerang/" +
"[API KEY GOES HERE]";
var // document.currentScript is supported in all browsers other than IE
where = document.currentScript || document.getElementsByTagName("script")[0],
// Parent element of the script we inject
parentNode = where.parentNode,
// Whether or not Preload method has worked
promoted = false,
// How long to wait for Preload to work before falling back to iframe method
LOADER_TIMEOUT = 3000;
// Tells the browser to execute the Preloaded script by adding it to the DOM
function promote() {
if (promoted) {
return;
}
var script = document.createElement("script");
script.id = "boomr-scr-as";
script.src = window.BOOMR.url;
// Not really needed since dynamic scripts are async by default and the script is already in cache at this point,
// but some naive parsers will see a missing async attribute and think we're not async
script.async = true;
parentNode.appendChild(script);
promoted = true;
}
// Non-blocking iframe loader (fallback for non-Preload scenarios) for all recent browsers.
// For IE 6/7, falls back to dynamic script node.
function iframeLoader(wasFallback) {
promoted = true;
var dom, doc = document, bootstrap, iframe, iframeStyle, win = window;
window.BOOMR.snippetMethod = wasFallback ? "if" : "i";
// Adds Boomerang within the iframe
bootstrap = function(parent, scriptId) {
var script = doc.createElement("script");
script.id = scriptId || "boomr-if-as";
script.src = window.BOOMR.url;
BOOMR_lstart = new Date().getTime();
parent = parent || doc.body;
parent.appendChild(script);
};
// For IE 6/7, we'll just load the script in the current frame, as those browsers don't support 'about:blank'
// for an iframe src (it triggers warnings on secure sites). This means loading on IE 6/7 may cause SPoF.
if (!window.addEventListener && window.attachEvent && navigator.userAgent.match(/MSIE [67]\./)) {
window.BOOMR.snippetMethod = "s";
bootstrap(parentNode, "boomr-async");
return;
}
// The rest of this function is IE8+ and other browsers that don't support Preload hints but will work with CSP & iframes
iframe = document.createElement("IFRAME");
// An empty frame
iframe.src = "about:blank";
// We set title and role appropriately to play nicely with screen readers and other assistive technologies
iframe.title = "";
iframe.role = "presentation";
// Ensure we're not loaded lazily
iframe.loading = "eager";
// Hide the iframe
iframeStyle = (iframe.frameElement || iframe).style;
iframeStyle.width = 0;
iframeStyle.height = 0;
iframeStyle.border = 0;
iframeStyle.display = "none";
// Append to the end of the current block
parentNode.appendChild(iframe);
// Try to get the iframe's document object
try {
win = iframe.contentWindow;
doc = win.document.open();
}
catch (e) {
// document.domain has been changed and we're on an old version of IE, so we got an access denied.
// Note: the only browsers that have this problem also do not have CSP support.
// Get document.domain of the parent window
dom = document.domain;
// Set the src of the iframe to a JavaScript URL that will immediately set its document.domain to match the parent.
// This lets us access the iframe document long enough to inject our script.
// Our script may need to do more domain massaging later.
iframe.src = "javascript:var d=document.open();d.domain='" + dom + "';void 0;";
win = iframe.contentWindow;
doc = win.document.open();
}
if (dom) {
// Unsafe version for IE8 compatibility. If document.domain has changed, we can't use win, but we can use doc.
doc._boomrl = function() {
this.domain = dom;
bootstrap();
};
// Run our function at load.
// Split the string so HTML code injectors don't get confused and add code here.
doc.write("<bo" + "dy onload='document._boomrl();'>");
}
else {
// document.domain hasn't changed, regular method should be OK
win._boomrl = function() {
bootstrap();
};
if (win.addEventListener) {
win.addEventListener("load", win._boomrl, false);
}
else if (win.attachEvent) {
win.attachEvent("onload", win._boomrl);
}
}
// Finish the document
doc.close();
}
// See if Preload is supported or not
var link = document.createElement("link");
if (link.relList &&
typeof link.relList.supports === "function" &&
link.relList.supports("preload") &&
("as" in link)) {
window.BOOMR.snippetMethod = "p";
// Set attributes to trigger a Preload
link.href = window.BOOMR.url;
link.rel = "preload";
link.as = "script";
// Add our script tag if successful, fallback to iframe if not
link.addEventListener("load", promote);
link.addEventListener("error", function() {
iframeLoader(true);
});
// Have a fallback in case Preload does nothing or is slow
setTimeout(function() {
if (!promoted) {
iframeLoader(true);
}
}, LOADER_TIMEOUT);
// Note the timestamp we started trying to Preload
BOOMR_lstart = new Date().getTime();
// Append our link tag
parentNode.appendChild(link);
}
else {
// No Preload support, use iframe loader
iframeLoader(false);
}
// Save when the onload event happened, in case this is a non-NavigationTiming browser
function boomerangSaveLoadTime(e) {
window.BOOMR_onload = (e && e.timeStamp) || new Date().getTime();
}
if (window.addEventListener) {
window.addEventListener("load", boomerangSaveLoadTime, false);
}
else if (window.attachEvent) {
window.attachEvent("onload", boomerangSaveLoadTime);
}
})();
</script>
Minified
Replace [API KEY GOES HERE]
with your mPulse API key.
<script>
(function(){if(window.BOOMR&&(window.BOOMR.version||window.BOOMR.snippetExecuted)){return}window.BOOMR=window.BOOMR||{};window.BOOMR.snippetStart=(new Date).getTime();window.BOOMR.snippetExecuted=true;window.BOOMR.snippetVersion=14;window.BOOMR.url="//c.go-mpulse.net/boomerang/[API KEY GOES HERE]";var e=document.currentScript||document.getElementsByTagName("script")[0],a=e.parentNode,s=false,t=3e3;function n(){if(s){return}var e=document.createElement("script");e.id="boomr-scr-as";e.src=window.BOOMR.url;e.async=true;a.appendChild(e);s=true}function o(e){s=true;var t,o=document,n,i,d,r=window;window.BOOMR.snippetMethod=e?"if":"i";n=function(e,t){var n=o.createElement("script");n.id=t||"boomr-if-as";n.src=window.BOOMR.url;BOOMR_lstart=(new Date).getTime();e=e||o.body;e.appendChild(n)};if(!window.addEventListener&&window.attachEvent&&navigator.userAgent.match(/MSIE [67]\./)){window.BOOMR.snippetMethod="s";n(a,"boomr-async");return}i=document.createElement("IFRAME");i.src="about:blank";i.title="";i.role="presentation";i.loading="eager";d=(i.frameElement||i).style;d.width=0;d.height=0;d.border=0;d.display="none";a.appendChild(i);try{r=i.contentWindow;o=r.document.open()}catch(e){t=document.domain;i.src="javascript:var d=document.open();d.domain='"+t+"';void 0;";r=i.contentWindow;o=r.document.open()}if(t){o._boomrl=function(){this.domain=t;n()};o.write("<bo"+"dy onload='document._boomrl();'>")}else{r._boomrl=function(){n()};if(r.addEventListener){r.addEventListener("load",r._boomrl,false)}else if(r.attachEvent){r.attachEvent("onload",r._boomrl)}}o.close()}var i=document.createElement("link");if(i.relList&&typeof i.relList.supports==="function"&&i.relList.supports("preload")&&"as"in i){window.BOOMR.snippetMethod="p";i.href=window.BOOMR.url;i.rel="preload";i.as="script";i.addEventListener("load",n);i.addEventListener("error",function(){o(true)});setTimeout(function(){if(!s){o(true)}},t);BOOMR_lstart=(new Date).getTime();a.appendChild(i)}else{o(false)}function d(e){window.BOOMR_onload=e&&e.timeStamp||(new Date).getTime()}if(window.addEventListener){window.addEventListener("load",d,false)}else if(window.attachEvent){window.attachEvent("onload",d)}})();
</script>
IFRAME-less Loader Snippet v12+
The mPulse Loader Snippet is continually being improved to make it more performant, reliable and compatible. Using the mPulse Loader Snippet (instead of an inline <script src="...">
tag) ensures Boomerang loads asynchronously and non-blocking, so it won’t affect the page’s performance.
Versions 1 through 10 (v1 - v10) of this snippet utilized an IFRAME to host Boomerang, which got it out of the critical path, to ensure Boomerang was able to load asynchronously and non-blocking.
The latest versions of the mPulse Loader Snippet (v12+) have a significant change, to utilize Preload on modern browsers (instead of an IFRAME) to load Boomerang asynchronously.
The IFRAME-less mPulse Loader Snippet (v12+) has multiple benefits versus older versions (<= v10), as long as the browser supports Preload:
- Boomerang executes in the main page instead of an IFRAME.
- No IFRAME is created in the
<head>
of the document (improves Search Engine Optimization issues in some cases). - Avoids the performance cost of creating an IFRAME (20-40ms).
- Avoids using document.write() (which is being deprecated).
- Content-Security-Policy (CSP) compliant.
Please note that browsers which don’t support Preload (such as Internet Explorer and Firefox) will still use the IFRAME fallback.
If upgrading from an older version of the snippet (<= v10) to an IFRAME-less snippet (>= v12), please make sure to test the changes to make sure there are no compatibility issues.
Boomerang 1.629.0 or later should be used with the IFRAME-less snippet to avoid compatibility issues.
Loader Snippet Known Issues
- IFRAME-less (version 12 or newer)
- Websites using Google Tag Manager (GTM) to inject the Loader Snippet may not see beacons from Firefox 74 or older.
- These versions of Firefox do not support Preload, so fallback to using the IFRAME loader.
- boomerang.js is not fetched due to a Firefox bug with setting the
iframe.src = "about:blank"
, which is done for Content Security Policies (CSP) compatibility. - Websites that are not using Content Security Policies can change:
// An empty frame iframe.src = "about:blank"
; to// An empty frame iframe.src = "javascript:void(0)";
. - Websites that are using Content Security Policies should use a
<script async src="//c.go-mpulse.net/boomerang/[API KEY GOES HERE]">
tag to load boomerang.js instead of the Loader Snippet.
Loader Snippet Version History
Version 10: December 18, 2017
- Escape
<body
tag injection to avoid server-side parsers that incorrectly string replace<body
with something else. - Added a version comment to the beginning of the snippet.
Version 11: June 6, 2018
<link rel="preload">
support- IFRAME-less
- Removes document.write entirely
- Removes IE 6 / 7 support
- Adds the
<link>
/<iframe>
/<script>
as the last sibling of 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 in Content Security Policy (CSP). - Adds support for IE 6 / 7 back in via sync
<script>
tag. - Adds support for IE 8 with
document.domain
set viadocument.write
. - Keeps track of the
BOOMR.snippetVersion
andBOOMR.snippetMethod
. - Removes dependency on the tag if
.currentScript
doesn’t work. - Fixes an issue where if Preload times out at 3 seconds, but still later succeeds, the promotion (
<script>
tag) would still happen even if the IFRAME method had started. - Ensures we track
BOOMR_lstart
for Preload method. - Adds
loading="eager"
to the IFRAME to avoid lazy loading. - Removed
BOOMR_mq postMessage()
listener for XSS security concerns.
Version 14: January, 2020
- Keeps a reference to the
parentNode
during startup in case the first<script>
tag is later removed - Changes IFRAME
src
syntax fromvoid(0)
tovoid 0
. - Comment spelling fix
Version 15: July, 2021
- Removes
document.write
logic for IE 8 in favor of sync code was flagging developer warnings in modern browsers even though it wasn’t being run. - IE 8 is approx 0.001% of traffic in 2021 (according to mPulse).
Configuration Overrides
When a configuration override is required, the window.BOOMR_config
object should be defined above the mPulse loader snippet:
<script>
window.BOOMR_config = window.BOOMR_config || {};
// set global options
window.BOOMR_config.autorun = false;
// set a plugin's options
window.BOOMR_config.History = {
enabled: true,
auto: true
};
(function(){
// ...
// loader snippet above
// ...
})();
</script>
Alternatively, for Akamai CDN customers using mPulse Edge injection, Config Overrides can be set in the property's configuration.
Note
Config Overrides can be set in Akamai Control Center's Property Manager, under the mPulse behavior settings. Config Overrides set this way must be in JSON format.
Updated almost 3 years ago