Bringing Web Analytics for your Desktop App

Web analytics desktopOften you’ll need to know how many active users  you have and what functionalities of your app that they use the most. If you’re writing an iOS or Android app, there’s plenty of services to do this. But on the Mac choices are a bit slim.

I needed some kind of application usage analytics service that I can use for our upcoming Mac OS X application. I’ve been using Flurry Analytics for my iOS apps but it looks like they don’t provide an Mac OS X counterpart to their service. Similarly Google Mobile Analytics also doesn’t have a desktop counterpart.

Luckily I found doo’s GAJavaScript tracker from a StackOverflow answer. The framework wraps Google Analytics‘ JavaScript tracker so that you can call it from an OS X application. It works by having a local copy of the JavaScript library and run it from a local HTML file loaded through an invisible WebView.

Then I’ve integrated this framework into my app and distributed the app to just over a hundred beta users. Strangely Google Analytics’ reports for that “app” remained zero hits. That can’t be right since I’ve been receiving feedback from a number of users (meaning that at least some people are using the app, even if only for a short while).  I’ve also debug the app with analytics turned on –  even if nobody else uses the app, the reports should show my own usage of the app. I’ve fiddled with it for a while, trying out various type of tracking codes (e.g. site tracking vs mobile tracking), debug the library and immediately checking the result but it simply doesn’t work: there isn’t any “hit” registered in any of the Real-Time Reports.

What puzzles me is that the answerer claims that this library works perfectly fine. I’m not sure whether there’s some hidden tricks to use doo’s library that I didn’t know about or that this answer was simply lying:

GAJavaScriptTracker Answer

I was using the latest version of GAJavaScriptTracker which is already quite old, the commit date was 7 September 2012. Suspecting that Google Analytics library have changed in the mean time, I’ve downloaded the latest version of ga.js and try it out. Unfortunately it didn’t work.

Being weary for this and having a real need for a desktop analytics library, I decided to roll out my own solution: BSWebTracker. It’s still roughly inspired from doo’s work but completely written from scratch with an entirely different approach. It’s not tightly coupled to Google Analytics and you can easily swap in another analytics provider (Adobe’s SiteCatalyst is one contender – previously Omniture). But it does require you to have a web server as part of the setup.

How it works 

Instead of having a copy of Google Analytics’ JavaScript module inside the app, the library mimics a web browser hitting a predetermined web page. In turn the web “site” is simply an empty web page containing Google Analytics’ tracking code, which then does the heavy work of recording your application’s usage.  BSWebTracker is designed only to load a single URL for the entire app and differentiates various tracking actions by varying Analytics’ utm_xxx parameters. These are the exact same parameters that you can construct using the URL Builder.

Since it uses a WebView and not directly talking to Google Analytics, it was not as straightforward as requesting a URL for every single tracking requests. Requests are serialized so that Google Analytics’ JavaScripts are executed properly even when there is a rapid fire of tracking requests from the app. That is, if the “page” is being loaded or a JavaScript is being executed, the WebView should be left alone and not asked to load another requests, otherwise it’ll just drop whatever it’s doing right now and serves the new request. Thus the library maintains an internal queue of tracking requests and dispatch them one by one.

This imply that you shouldn’t send hundreds of tracking requests in a tight loop – otherwise it may take a very long time for all requests to complete and the user may quit your application long before all tracking requests are sent. Instead send on the completion of a user action like, for example, opening a document or completed a workflow. 

Furthermore BSWebTracker also manages its WebView instance diligently. It’ll discard the instance whenever there are no more tracking requests to send. You wouldn’t want to keep an unused WebView instance around, would you? It’s a heavyweight object – being a full-fledged web browser after all. So even though you shouldn’t burst a lot of requests, you’ll still want to keep them near (time-wise) to each other. In other words, maintain locality of reference. Try to group tracking requests in one lifecycle of your app – for example at startup – instead of sending far-flung requests. If you send requests only once in a while, there might be thrashing of WebView instance creation / destruction as the class creates a WebView instance to solely serve one request and then immediately deallocates it afterwards.

The sequence diagram below illustrates the typical flow of messages between your application, BSWebTracker, and how your tracking data finally ends up in Google.

BSWebTracker sequence diagram


As you can see from the diagram above, each time your application sends a tracking request, the class will just queue it for later. At the next run loop, it’ll pick up one request and send them over to the WebView. In turn the WebView will load the request and eventually Google Analytics gets to see your tracking request. After the WebView have completed a request, BSWebTracker will pickup another URL from the queue and send them over. This will continue until the last tracking request is completed. Should BSWebTracker tries to dequeue and see that the queue is empty, it’ll discards the WebView instance. 

One last note: currently BSWebTracker doesn’t do much error handling. If your website is down or otherwise cannot be reached, it’ll simply discard tracking requests and not saves them for later retry. It also doesn’t try to store the exact time when the tracking request occur and forward it to the analytics reports (e.g. backdates tracking action) and other fancy stuff. So probably the library will only be useful for online-type apps (like web browsers or instant messaging clients) and will need some adaptation to be used offline.

Get It Now

You can find BSWebTracker in Github, under the very liberal BSD open-source license. Please let me know if you find it useful and use it in your own app.

PS: I’ll always welcome a complementary license of your app ;-)

That’s all for now. Take care!


Avoid App Review rules by distributing outside the Mac App Store!

Get my FREE cheat sheets to help you distribute real macOS applications directly to power users.

* indicates required

When you subscribe you’ll also get programming tips, business advices, and career rants from the trenches about twice a month. I respect your e-mail privacy.

Avoid Delays and Rejections when Submitting Your App to The Store!

Follow my FREE cheat sheets to design, develop, or even amend your app to deserve its virtual shelf space in the App Store.

* indicates required

When you subscribe you’ll also get programming tips, business advices, and career rants from the trenches about twice a month. I respect your e-mail privacy.

0 thoughts on “Bringing Web Analytics for your Desktop App

Leave a Reply