Note: Google recently replacing their “ga.js” analytics script with the new “analytics.js” and changed the syntax of how event tracking works. While the code examples on this post won’t work with the new analytics script, you can read how to update your code to the new syntax and the same conceptual principles apply. — Eric (2016-04-18)
In a previous post by Kelly Sattler and Joel Richard, we explored using web analytics to measure a website’s success. That post provides a clear high-level picture of how to create an analytics strategy by evaluating our users, web content, and goals. This post will explore a single topic in-depth; how to set up event tracking in Google Analytics.
Why Do We Need Event Tracking?
Finding solid figures to demonstrate a library’s value and make strategic decisions is a topic of increasing importance. It can be tough to stitch together the right information from a hodgepodge of third-party services; we rely on our ILSs to report circulation totals, our databases to report usage like full-text downloads, and our web analytics software to show visitor totals. But are pageviews and bounce rates the only meaningful measure of website success? Luckily, Google Analytics provides a way to track arbitrary events which occur on web pages. Event tracking lets us define what is important. Do we want to monitor how many people hover over a carousel of book covers, but only in the first second after the page has loaded? How about how many people first hover over the carousel, then the search box, but end up clicking a link in the footer? As long as we can imagine it and JavaScript has an event for it, we can track it.
How It Works
Many people are probably familiar with Google Analytics as a snippet of JavaScript pasted into their web pages. But Analytics also exposes some of its inner workings to manipulation. We can use the _gaq.push
method to execute a “_trackEvent” method which sends information about our event back to Analytics. The basic structure of a call to _trackEvent
is:
_gaq.push( [ '_trackEvent', 'the category of the event', 'the action performed', 'an optional label for the event', 'an optional integer value that quantifies something about the event' ] );
Looking at the array parameter of _gaq.push
is telling: we should have an idea of what our event categories, actions, labels, and quantitative details will be before we go crazy adding tracking code to all our web pages. Once events are recorded, they cannot be deleted from Analytics. Developing a firm plan helps us to avoid the danger of switching the definition of our fields after we start collecting data.
We can be a bit creative with these fields. “Action” and “label” are just Google’s way of describing them; in reality, we can set up anything we like, using category->action->label as a triple-tiered hierarchy or as three independent variables.
Example: A List of Databases
Almost every library has a web page listing third-party databases, be they subscription or open access. This is a prime opportunity for event tracking because of the numerous external links. Default metrics can be misleading on this type of page. Bounce rate—the proportion of visitors who start on one of our pages and then immediately leave without viewing another page—is typically considered a negative metric; if a page has a high bounce rate, then visitors are not engaged with its content. But the purpose of a databases page is to get visitors to their research destinations as quickly as possible; bounce rate is a positive figure. Similarly, time spent on page is typically considered a positive sign of engagement, but on a databases page it’s more likely to indicate confusion or difficulty browsing. With event tracking, we can not only track which links were clicked but we can make it so database links don’t count towards bounce rate, giving us a more realistic picture of the page’s success.
One way of structuring “database” events is:
- The top-level Category is “database”
- The Action is the topical category, e.g. “Social Sciences”
- The Label is the name of the database itself, e.g. “Academic Search Premier”
The final, quantitative piece could be the position of the database in the list or the number of seconds after page load it took the user to click its link. We could report some boolean value, such as whether the database is open access or highlighted in some way.
To implement this, we set up a JavaScript function which will be called every time one of our events occur. We will store some contextual information in variables, push that information to Google Analytics, and then delay the page’s navigation so the event has a chance to be recorded. Let’s walk through the code piece by piece:
function databaseTracking ( event ) { var destination = $( this )[ 0 ].href, resource = $( this ).text(), // move up from <a> to parent element, then find the nearest preceding <h2> section header section = $( this ).parent().prevAll( 'h2' )[ 0 ].innerText, highlighted = $( this ).hasClass( 'highlighted' ) ? 1 : 0; _gaq.push( [ '_trackEvent', 'database', resource, section, highlighted ] );
The top of our function just grabs information from the page. We’re using jQuery to make our lives easier, so all the $( this )
pieces of our code refer to the element that initiated the event. In our case, that’s the link pointing to an external database which the user just clicked. So we set destination
to the link’s href
attribute, resource
to its text (e.g. the database’s name), section
to the text inside the h2
element that labels a topical set of databases, and highlighted
is a boolean value equal to 1 if the element has a class of “highlighted.” Next, this data is pushed into the _gaq
array which is a queue of functions and their parameters that Analytics fires asynchronously. In this instance, we’re telling Analytics to run the _trackEvent
function with the parameters that follow. Analytics will then record an event of type “database” with an action of [database name], a label of [section header], and a boolean representing whether it was highlighted or not.
setTimeout( function () { window.location = destination; }, 200 ); event.preventDefault(); }
Next comes perhaps the least obvious piece: we prevent the default browser behavior from occurring, which in the case of a link is navigating away from our page, but then send the user to destination
200 milliseconds later anyways. The _trackEvent
function now has a chance to fire; if we let the user follow the link right away it might not complete and our event would not be recorded.1
$( document ).ready( // target all anchors in list of databases $( '#databases-list a' ).on( 'click', databaseTracking ) );
There’s one last step; merely defining the databaseTracking
function won’t cause it to execute when we want it to. JavaScript uses event handlers to execute certain functions based on various user actions, such as mousing over or clicking an element. Here, we add click event handlers to all <a>
elements in the list of databases. Now whenever a user clicks a link in the databases list (which has a container with id “databases-list”), databaseTracking
will run and send data to Google Analytics.
There is a demo on JSFiddle which uses the code above with some sample HTML. Every time you click a link, a pop-up shows you what the _gaq.push
array looks like.
Though we used jQuery in our example, any JavaScript library can be used with event tracking.2 The procedure is always the same: write a function that gathers data to send back to Google Analytics and then add that function as a handler to an appropriate event, such as click or mouseover, on an element.
For another example, complete with code samples, see the article “Discovering Digital Library User Behavior with Google Analytics” in Code4Lib Journal. In it, Kirk Hess of the University of Illinois Urbana-Champaign details how to use event tracking to see how often external links are clicked or files are downloaded. While these events are particularly meaningful to digital libraries, most libraries offer PDFs or other documents online.
Some Ideas
The true power of Event Tracking is that it does not have to be limited to the mere clicking of hyperlinks; any interaction which JavaScript knows about can be recorded and categorized. Google’s own Event Tracking Guide uses the example of a video player, recording when control buttons like play, pause, and fast forward are activated. Here are some more obvious use cases for event tracking:
- Track video plays on particular pages; we may already know how many views a video gets, but how many come from particular embedded instances of the video?
- Clicking to external content, such as a vendor’s database or another library’s study materials.
- If there is a print or “download to PDF” button on our site, we can track each time it’s clicked. Unfortunately, only Internet Explorer and Firefox (versions >= 6.0) have an
onbeforeprint
event in JavaScript which could be used to detect when a user hits the browser’s native print command. - Web applications are particularly suited to event tracking. Many modern web apps have a single page architecture, so while the user is constantly clicking and interacting within the app they rarely generate typical interaction statistics like pageviews or exits.
Notes
- There is a discussion on the best way to delay outbound links enough to record them as events. A Google Analytics support page condones the
setTimeout
approach. For other methods, there are threads on StackOverflow and various blog posts around the web. Alternatively, we could use theonmousedown
event which fires slightly earlier thanonclick
but also might record false positives due to click-and-drag scrolling. - Below is an attempt at rewriting the jQuery tracking code in pure JavaScript. It will only work in modern browsers because of use of
querySelectorAll
,parentElement
, andpreviousElementSibling
. Versions of Internet Explorer prior to 9 also use a uniqueattachEvent
syntax for event handlers. Yes, there’s a reason people use libraries to do anything the least bit sophisticated with JavaScript.
function databaseTracking ( event ) { var destination = event.target.href, resource = event.target.innerHTML, section = "none", highlighted = event.target.className.match( /highlighted/ ) ? 1: 0; // getting a parent element's nearest <h2> sibling is non-trivial without a library var currentSibling = event.target.parentElement; while ( currentSibling !== null ) { if ( currentSibling.tagName !== "H2" ) { currentSibling = currentSibling.previousElementSibling; } else { section = currentSibling.innerHTML; currentSibling = null; } } _gaq.push( [ '_trackEvent', 'database', resource, section, highlighted ] ); // delay navigation to ensure event is recorded setTimeout( function () { window.location = destination; }, 200 ); event.preventDefault(); } document.addEventListener( 'DOMContentLoaded', function () { var dbLinks = document.querySelectorAll( '#databases-list a' ), len = dbLinks.length; for ( i = 0; i < len; i++ ) { dbLinks[ i ].addEventListener( 'click', databaseTracking, false ); } }, false );