Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Support routine for adding W3C user timing events to a site. Includes some basic polyfill support for browsers that don't support user timing or navigation timing (though the start time for non-navigation timing support could be improved with IE < 9 to use IE's custom start event).
// Support routines for automatically reporting user timing for common analytics platforms
// Currently supports Google Analytics, Boomerang and SOASTA mPulse
// In the case of boomerang, you will need to map the event names you want reported
// to timer names (for mPulse these need to be custom0, custom1, etc) using a global variable:
// rumMapping = {'aft': 'custom0'};
(function() {
var wtt = function(n, t, b) {
t = Math.round(t);
if (t >= 0 && t < 3600000) {
// Google Analytics
if (!b && window['_gaq'])
_gaq.push(['_trackTiming', 'UserTimings', n, t]);
// Boomerang/mPulse
if (b && window['rumMapping'] && window.rumMapping[n])
BOOMR.plugins.RT.setTimer(window.rumMapping[n], t);
}
};
utReportRUM = function(b){
var m = window.performance.getEntriesByType("mark");
var lm={};
for (i = 0; i < m.length; i++) {
g = 'usertiming';
if (lm[g] == undefined || m[i].startTime > lm[g])
lm[g] = m[i].startTime;
p = m[i].name.match(/([^\.]+)\.([^\.]*)/);
if (p && p.length > 2 &&
(lm[p[1]] == undefined ||
m[i].startTime > lm[p[1]]))
lm[p[1]] = m[i].startTime;
}
for (g in lm)
wtt(g, lm[g], b);
};
utOnLoad = function() {utReportRUM(false);};
if (window['addEventListener'])
window.addEventListener('load', utOnLoad, false);
else if (window['attachEvent'])
window.attachEvent('onload', utOnLoad);
// Boomerang/mPulse support
utSent = false;
BOOMR = window.BOOMR || {};
BOOMR.plugins = BOOMR.plugins || {};
BOOMR.plugins.UserTiming = {
init: function(config) {BOOMR.subscribe('page_ready', function(){
if (!utSent) {
utReportRUM(true);
utSent=true;
BOOMR.sendBeacon();
}
});},
is_complete: function() {return utSent;}
};
})();
/*
Strategically place:
markUserTime('some event');
Through your code to get measurements for when various activities complete. It
will also generate timeline events so you can see them in Chrome's dev tools.
A good use case is to add them inline to sections of your site that are
above-the fold (right after the menu, right after the main story, etc) and also
in the onload handler for any critical above-the-fold images.
*/
;(function () {
var w = typeof window != 'undefined' ? window : exports,
marks = [];
w.performance || (w.performance = {});
w.performance.now || (
w.performance.now = performance.now || performance.webkitNow ||
performance.msNow || performance.mozNow);
if (!w.performance.now){
var s = Date.now ? Date.now() : +(new Date());
if (performance.timing && performance.timing)
s = performance.timing.navigationStart
w.performance.now = (function(){
var n = Date.now ? Date.now() : +(new Date());
return n-s;
});
}
w.performance.mark || (
w.performance.mark =
w.performance.webkitMark ? w.performance.webkitMark :
(function (l) {
marks.push({'name':l,'entryType':'mark','startTime':w.performance.now(),'duration':0});
}));
w.performance.getEntriesByType || (
w.performance.getEntriesByType =
w.performance.webkitGetEntriesByType ? w.performance.webkitGetEntriesByType :
(function (t) {
return t == 'mark' ? marks : undefined;
}));
}());
window.markUserTime = function(l) {
var raf = window['requestAnimationFrame'] ||
(function(callback){setTimeout(callback, 0);});
raf(function(){
window.performance.mark(l);
if (window['console'] && console['timeStamp'])
console.timeStamp(l);
});
};
@pmeenan

This comment has been minimized.

Show comment
Hide comment
@pmeenan

pmeenan Jul 1, 2013

(coming soon) WebPagetest will report on any user timing events that were recorded
and also expose a high-level metric for when the last user timing event fired.

With any luck we can also get RUM solutions to start reporting user timing events
and we can significantly loosen our dependency on the (very broken) document
onload times.

Owner

pmeenan commented Jul 1, 2013

(coming soon) WebPagetest will report on any user timing events that were recorded
and also expose a high-level metric for when the last user timing event fired.

With any luck we can also get RUM solutions to start reporting user timing events
and we can significantly loosen our dependency on the (very broken) document
onload times.

@constantx

This comment has been minimized.

Show comment
Hide comment
@constantx

constantx Aug 12, 2013

Include both scripts?

Include both scripts?

@pmeenan

This comment has been minimized.

Show comment
Hide comment
@pmeenan

pmeenan Aug 30, 2013

Depends on what you want to do. The 2nd one is a polyfill and support routine for user timing. The first one is a bridge that will report user timing to Google Analytics and Boomerang (or SOASTA).

You can see it live on webpagetest.org if you want to see an example.

Owner

pmeenan commented Aug 30, 2013

Depends on what you want to do. The 2nd one is a polyfill and support routine for user timing. The first one is a bridge that will report user timing to Google Analytics and Boomerang (or SOASTA).

You can see it live on webpagetest.org if you want to see an example.

@pmeenan

This comment has been minimized.

Show comment
Hide comment
@pmeenan

pmeenan Aug 30, 2013

btw, if you haven't seen it yet, this blog post has a bunch more detail: http://blog.patrickmeenan.com/2013/07/measuring-performance-of-user-experience.html

Owner

pmeenan commented Aug 30, 2013

btw, if you haven't seen it yet, this blog post has a bunch more detail: http://blog.patrickmeenan.com/2013/07/measuring-performance-of-user-experience.html

@bluesmoon

This comment has been minimized.

Show comment
Hide comment
@bluesmoon

bluesmoon Nov 22, 2013

better to use setImmediate than setTimeout(0)

better to use setImmediate than setTimeout(0)

@bluesmoon

This comment has been minimized.

Show comment
Hide comment
@bluesmoon

bluesmoon Jan 29, 2014

The new mPulse has RT and UT built in. Used your script as a basis for mine.

The new mPulse has RT and UT built in. Used your script as a basis for mine.

@jamischarles

This comment has been minimized.

Show comment
Hide comment
@jamischarles

jamischarles Feb 6, 2014

@bluesmoon Any chance that's open source? Or does Soasta maintain a private fork of boomerang?

@bluesmoon Any chance that's open source? Or does Soasta maintain a private fork of boomerang?

@jamischarles

This comment has been minimized.

Show comment
Hide comment
@jamischarles

jamischarles Feb 6, 2014

@bluesmoon Also, which repo is considered stable? Your fork, or lognormal, or another?

@bluesmoon Also, which repo is considered stable? Your fork, or lognormal, or another?

@jamischarles

This comment has been minimized.

Show comment
Hide comment
@jamischarles

jamischarles Feb 14, 2014

@pmeenan Out of curiosity, why is this step necessary?

if (t >= 0 && t < 3600000) {

https://gist.github.com/pmeenan/5902672#file-user-timing-rum-js-L9

Curiously enough, I left this step out, and am getting lots of IE9 responses that appear to be a timestamp, instead of the delta.

@pmeenan Out of curiosity, why is this step necessary?

if (t >= 0 && t < 3600000) {

https://gist.github.com/pmeenan/5902672#file-user-timing-rum-js-L9

Curiously enough, I left this step out, and am getting lots of IE9 responses that appear to be a timestamp, instead of the delta.

@edmund-huber

This comment has been minimized.

Show comment
Hide comment
@edmund-huber

edmund-huber Sep 8, 2014

The spec says http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbytype that getEntriesByType should always return a sequence. It seems like it would be more correct if the polyfill returned [] instead of undefined when the type is not 'mark'. https://gist.github.com/edmund-huber/d3acd4d510d895cf860a#file-user-timing-js-L39

The spec says http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbytype that getEntriesByType should always return a sequence. It seems like it would be more correct if the polyfill returned [] instead of undefined when the type is not 'mark'. https://gist.github.com/edmund-huber/d3acd4d510d895cf860a#file-user-timing-js-L39

@micmro

This comment has been minimized.

Show comment
Hide comment
@micmro

micmro Oct 23, 2014

There is a bug in line 22:

if (performance.timing && performance.timing)

should probably be

if (w.performance.timing && w.performance.timing.navigationStart)

micmro commented Oct 23, 2014

There is a bug in line 22:

if (performance.timing && performance.timing)

should probably be

if (w.performance.timing && w.performance.timing.navigationStart)
@bluesmoon

This comment has been minimized.

Show comment
Hide comment
@bluesmoon

bluesmoon Nov 13, 2015

@jamischarles, the lognormal one is stable. RT plugin is opensource. UT isn't so much a plugin, nothing really to opensource, though I'm thinking of merging it into RT.

@jamischarles, the lognormal one is stable. RT plugin is opensource. UT isn't so much a plugin, nothing really to opensource, though I'm thinking of merging it into RT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment