Tame your analytics libraries with Analytical - FeeFighters

Tame your analytics libraries with Analytical

We recently integrated KISSMetrics tracking into our website (more on that in a future post!)… and I was once again faced with the annoying task of carefully updating the mess of javascript that was cluttering up our page in various places.  We’re data & analytics tracking freaks at TransFS.com… so we have a bunch of different analytics packages in place on our site. Managing all of these packages and keeping the tracking javascript clean & simple had finally become a real pain point for me.

At various times, we’ve had Google Analytics, Clicky, MixPanel, and our own internal FunnelCake tracking code all monitoring our visitor traffic.  Each library requires specific javascript code to be added to the page; some insisting that the code be added to the top of the <body> element, while others suggesting that it be before the closing </body> tag.  To further complicate matters, we want to be able to trigger a manual track() function to track a specific event.  However, it isn’t always convenient to declare these tracking calls at the bottom of the page, or in a controller, or in any single location.  What if we want to track an action in a view?  How can we be sure that the corresponding library has been initialized at the time when the javascript code is inserted?  What if we want to declare a tracking event in a controller?  How can we easily send the same tracking event to all of the different analytics packages we have installed?

So, in a fury of frustration, I banged out a new rails gem for helping with this exact problem.  I’d like to introduce you to Analytical.  This gem is designed to be an all-purpose analytics front-end.  By providing a simple API to a variety of analytics libraries, it allows you to clean up your views and easily track events in your app without worrying about the details of the underlying analytics apis.  Even better, it gracefully deals with queuing up tracking commands for services, so that the tracking commands are always inserted after the initialization scripts have been added to your page.

So, how does it work?  You start off by adding a single line to your application controller:

    analytical :modules=>[:google, :clicky]

This tells analytical which packages you intend to use. You can define the api keys in config/analytical.yml, like so:

     key: UA-5555555-5
     key: 55555

Then, in your layout file, you need to add a few hooks so that Analytical can insert any initialization code for your modules:

    <!DOCTYPE html>
        <%= stylesheet_link_tag :all %>
        <%= javascript_include_tag :defaults %>
        <%= csrf_meta_tag %>
        <% analytical.identify current_user.id, :email=>current_user.email if current_user %>
        <%= raw analytical.head_javascript %>
        <%= raw analytical.body_prepend_javascript %>
        <%= yield %>
        <%= raw analytical.body_append_javascript %>

As you can see, I’ve also added a simple identify call to the template, so that we can tell our analytics modules about the current user (if they support per-user identification, like Clicky/KISSMetrics).

From there, using analytical to track events is dead simple. Track a url with:

    analytical.track '/a/really/nice/url'

And an event with:

    analytical.event 'Some Awesome Event', :with=>:data

… and these can be used anyplace in your app: views, controllers, templates, whatever. Since views are processed before templates, your commands will queued up and then inserted immediately after the corresponding analytics library has been initialized. This produces javascript code on your page that might look something like:

    <!-- Analytical Init: KissMetrics --> 
    <script type="text/javascript"> 
        var .... initialization javascript for KISSMetrics ...
    <script type='text/javascript'> 
        _kmq.push(["record", "Visited Tour", {}]);

In this example, analytical.event 'Visited Tour' was called in the view… and the event was queued up so it could be inserted immediately after the KISSMetrics library was initialized.

But what about triggering a specific command that is not one of the standard calls that Analytical knows about (track, event, identify)? No problem… you can call any custom method on a module like so:

   analytical.clicky.special_tracking_method :that_only=>:clicky_supports

If you need to output javascript immediately without queuing it up for later insertion (to use in a javascript callback, for instance)… you can do this using the .now accessor:

   <%= analytical.now.track '/some/url' %>



In our app, we wrap this into a convenience javascript function in our that looks like:

	var analytical_track = function(page){
		<%= analytical.now.track('page').gsub(/"page"/,'page') %>
	var analytical_event = function(event, data){
		if (!data) { data = {}; }
		<%= analytical.now.event('event', {}).gsub(/"event"/,'event').gsub(/\"?\{\}\"?/,'data') %>

This allows us to call


from our javascript, anywhere in the page, and it’ll hit every module that we have installed. (Note: we do have to be sure that if we use this javascript helper, that we only call it in ajax situations where the page is certain to be fully baked and all analytics libraries are initialized.)

That’s about it. We’ve had the gem in production for a while now, and it has really cleaned up our tracking code. However, I’d love to get some feedback on how it could be improved!

As of now, I have implemented support for Google Analytics, Clicky, and KISSMetrics… but the library is extremely easy to extend, so I’m hopeful that the community will add support for other services that people would like to use. You can find the code here: http://github.com/jkrall/analytical, so fork away!

Lastly, I’d like to call out the cool Snogmetrics library for providing a lot of the inspiration for Analytical. I stole some great ideas from that project, and adapted it for our broader needs. Thanks Theo!

About the Author