This snippet sends Time to First Paint, Connection type and Speed to first network hop if they are supported by browser JS API. The script sends the data to GA custom dimension that is set with Session scope. It also tries to guess if the customer visits the website for first time by setting a cookie for 8 hours. In specific case the cookie lifetime could be changed and also the dimension numbers should be changed depending on GA dimension IDs.
(function() {
function createCheckCacheCookie() {
var expireHours = 8;
var date = new Date();
date.setTime(date.getTime() + (expireHours*60*60*1000));
document.cookie = "assumedColdCache=true" + "; expires=" + date.toUTCString() + "; path=/";
}
function cacheCookieExists()
{
return document.cookie.indexOf('assumedColdCache=') !== -1;
}
function getTimeToFirstPaint() {
// Use Chrome's loadTimes or IE 9+'s msFirstPaint to record the time to render in milliseconds:
var firstPaintTime, timingSource;
if ('chrome' in window && typeof window.chrome.loadTimes == 'function') {
var loadTimes = window.chrome.loadTimes();
// A small percentage of traffic from Chrome in the wild returns impossibly large values – 2+
// days! – which need to be filtered out:
firstPaintTime = loadTimes.firstPaintTime - loadTimes.startLoadTime;
if (firstPaintTime > 3600) {
//Raven.captureMessage('chrome.loadTimes() reported impossible values',
// {extra: {loadTimes: loadTimes}});
return 'N/A';
}
// Convert from seconds to milliseconds:
firstPaintTime = Math.round(firstPaintTime * 1000);
} else if ('performance' in window) {
var navTiming = window.performance.timing;
if (navTiming.navigationStart === 0) {
return 'N/A'; // IE9 bug - see below
}
// See http://msdn.microsoft.com/ff974719
firstPaintTime = navTiming.msFirstPaint - navTiming.navigationStart;
}
if (typeof firstPaintTime == 'number' && firstPaintTime > 0) {
return firstPaintTime;
}
return 'N/A';
}
function getConnectionType()
{
if ('connection' in navigator) {
return navigator.connection.type;
}
return 'N/A';
}
function getFirstNetworkHopSpeed()
{
if ('connection' in navigator) {
return navigator.connection.downlinkMax;
}
return 'N/A';
}
function sendData() {
var timeForFirstPaint = getTimeToFirstPaint();
if ('N/A' !== timeForFirstPaint) {
var quotient = Math.floor(timeForFirstPaint/50);
timeForFirstPaint = (quotient * 50) + ' - ' + ((quotient + 1) * 50);
}
ga('send', 'event', 'Performance', 'Frontend', 'User Timings', 1, {
'dimension1': timeForFirstPaint,
'dimension2': getConnectionType(),
'dimension3': getFirstNetworkHopSpeed(),
nonInteraction : 1
});
}
if (false === cacheCookieExists()) {
createCheckCacheCookie();
// Defer collecting data until after the load event has finished to avoid an IE9
// bug where navigationStart will be 0 until after the browser updates the
// performance.timing data structure:
window.addEventListener('load', function() {
setTimeout(sendData, 50);
});
}
})();