Thursday, January 5, 2012

Chrome, Prerender and Site Stats

As Chrome keeps inching towards market dominance, it is definitely helping to move the web forward and speeding it up along the way. One of the interesting ways they have helped speed up the web (as of Chrome 13) is through the use of "prerendering". Basically, prerendering will begin to download a page that is linked from the current page via link declarations on the current page like so:
<link rel="prerender" href="/someOtherAwesomeness.html">
<link rel="prerender" href="http://anotherAwesome.website.com">
These pages will now be downloaded in the background while the user is currently on the page theses are linked from. When/if the user follows a link to one of those pages, it will feel nearly instantaneous to the user since the page is already loaded.

Pretty interesting trick on Google's part to make Chrome feel faster. As one can imagine, to avoid unnecessary overhead to websites linked from one page, discretion should be practiced in selecting what if any pages should be prerendered from the current page being viewed. Easy candidates are next-type pages and other links that have a high click through rate.

How does this impact site stats? It depends on whether you can truly count a page view if a page was prerendered but then never seen? If you just care about inflated numbers, then this is probably a welcome exploit to increasing views across a larger number of pages even though a person truly only viewed one page. But, if you do care about them for being able to understand user interaction with your content, this could skew your numbers in a horrible way. These false views will increase the denominator in your analytics formulas without a chance of increase to the numerator, thus making your impact for user actions on those pages seem less effective.

The good news is that individual sites will have to enable this in their code for now and hence adoption will be slow. But with Google search results pages utilizing this feature already and the Chrome Beta released today enabling it from the omnibox, these false views will quickly start to accumulate.

So how do you prevent that from happening? Depends on how you determine page views.

If you use Google Analytics, you are already covered with the 2011-07 release (July 26, 2011) as it uses the Page Visibility API (but only with the webkit prefix, hopefully they keep up with other vendor releases as well).

If not, you can roll your own by using the Page Visibility API yourself. Continuing on form the example from my previous post, we can build a simple check for determining whether or not a page has been prerendered:
var visibilityAPI = ( typeof document.hidden != 'undefined' && { 'visibilitystate': 'visibilitystate', 'visibilitychange': 'visibilitychange' } ) || ( typeof document.webkitHidden != 'undefined' && { 'visibilitystate': 'webkitvisibilitystate', 'visibilitychange': 'webkitvisibilitychange' } ) || ( typeof document.mozHidden != 'undefined' && { 'visibilitystate': 'mozvisibilitystate', 'visibilitychange': 'mozvisibilitychange' } ) || ( typeof document.msHidden != 'undefined' && { 'hidden': 'msHidden', 'visibilitystate': 'msvisibilitystate', 'visibilitychange': 'msvisibilitychange' } );

(function pageVisibilityChanged() {
    if ( document[ visibilityAPI.visibilitystate ] === "prerender" ) {
        // Application has been prerendered
        // Add listener to fire when page is no longer in prerender state
        document.addEventListener( visibilityAPI.visibilitychange, pageVisibilityChanged, false );
    }
    else {
        // Page is no longer in presender state
        // A page view can be counted now
        document.removeEventListener( visibilityAPI.visibilitychange, pageVisibilityChanged, false );
    }
})();
There is still one problem with this example: the person could still never see your site though even after the follow one of the links. For example, they could open the page in a new tab behind their current one and then close it before they view it. Yes, this is probably an edge case, but you could easily expand the previous example to only count when the page is truly viewed.
var visibilityAPI = ( typeof document.hidden != 'undefined' && { 'hidden': 'hidden', 'visibilitystate': 'visibilitystate', 'visibilitychange': 'visibilitychange' } ) || ( typeof document.webkitHidden != 'undefined' && { 'hidden': 'webkitHidden', 'visibilitystate': 'webkitvisibilitystate', 'visibilitychange': 'webkitvisibilitychange' } ) || ( typeof document.mozHidden != 'undefined' && { 'hidden': 'mozHidden', 'visibilitystate': 'mozvisibilitystate', 'visibilitychange': 'mozvisibilitychange' } ) || ( typeof document.msHidden != 'undefined' && { 'hidden': 'msHidden', 'visibilitystate': 'msvisibilitystate', 'visibilitychange': 'msvisibilitychange' } );

(function pageVisibilityChanged() {
    if ( document[ visibilityAPI.visibilitystate ] === "prerender" ) {
        // Application has been prerendered
        // Add listener to fire when page is no longer in prerender state
        document.addEventListener( visibilityAPI.visibilitychange, pageVisibilityChanged, false );
    }
    else if ( !document[ visibilityAPI.hidden ] ) {
        // Page is no longer in presender state or hidden
        // A true page view can be counted now
        document.removeEventListener( visibilityAPI.visibilitychange, pageVisibilityChanged, false );
    }
})();
Now you are one small step closer to more accurate reporting!