Skip to content

Instantly share code, notes, and snippets.

Last active January 18, 2024 23:46
Show Gist options
  • Save pmeenan/5902672 to your computer and use it in GitHub Desktop.
Save pmeenan/5902672 to your computer and use it in GitHub Desktop.
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) {
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 = {}); || ( = || performance.webkitNow ||
performance.msNow || performance.mozNow);
if (!{
var s = ? : +(new Date());
if (performance.timing && performance.timing)
s = performance.timing.navigationStart = (function(){
var n = ? : +(new Date());
return n-s;
w.performance.mark || (
w.performance.mark =
w.performance.webkitMark ? w.performance.webkitMark :
(function (l) {
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);});
if (window['console'] && console['timeStamp'])
Copy link

pmeenan commented Aug 30, 2013

btw, if you haven't seen it yet, this blog post has a bunch more detail:

Copy link

better to use setImmediate than setTimeout(0)

Copy link

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

Copy link

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

Copy link

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

Copy link

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

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

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

Copy link

The spec says 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'.

Copy link

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)

Copy link

@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