Note: This post originally appeared on the blog of my since-shuttered analytics firm: Axiomatic. That said, if you need some analytics work, get in touch

WARNING: This entry's going to get a good bit nerdy. Useful, but nerdy.

Say your website has files available to download. If they come through your website to download, there are fairly easy ways to track those downloads in Google Analytics1.

But what if downloaders don't come through your website at all? What if links to the file get posted on message boards, or downloaded via cURL. How do you track those so you can know what's eating up your bandwidth - or how widespread your notoriety might actually be - without slogging through server logs to find the culprit?

The first thing you need to realize is that Google Analytics is really just a series of GET requests. Seriously, open up your Developer Tools' network tab (Chrome's is below) and watch the traffic. You should see something like the below2:

Ga dev tools

Of note, I'm using the newer Universal Analytics. I you're on the older analytics infrastructure, this should also work for you, but I make no guarantees.

If you explore a bit further, you'll see what GA is doing under the hood is a fairly simple GET request to the following URL:

That's what GA requests by default, but we can pare that down to the bare essentials with a URL like this:

That URL represent only the bare minimum needed to trigger GA event tracking and can be done through either a GET or POST request.

The required attributes:

  • v: The version of GA API. Right now, that value should always be "1"
  • t: The type of tracking. In this case (and recommended for file downloads), it's an event. If you wanted to trigger a page view instead, the value would be "pageview," and that comes with different required parameters.
  • ec: Event Category.
  • ea: Event Action.
  • el: Event Label.
  • tid: Your Google Analytics Tracking/Property ID.
  • cid: An anonymous Client ID. Of note: GA's expecting a random UUID for this one.

Some optional, but recommended, parameters:

  • dr: Document referrer - as in, where this request came from.
  • uip: This is an IP override. Left out, GA will record the event or pageview as coming from your proxy server IP (we'll talk more about the proxy server in a moment).
  • ua: User Agent Override. This is another recommended passthrough for your proxy server to make it easier to spot abuse later.
  • dl: Document location URL. In this case, I'd recommend using the URL of the file to be downloaded.
  • dt: Document title. Also useful for determining which file was downloaded.
  • uid: The specific User ID in your application. If you have this download as part of an authenticated API, feel free to plug this in.

So, how do we send this data to GA when a user downloads a file directly?

That's where our proxy server comes in.

Essentially, instead of linking directly to the files, you should link instead to an application or server that will first ping GA and then send the file - whether through a redirect or by sending the file directly.

Just as an example3, here's how you'd do it in Rails4:

One side note for this technique: The same idea can be applied to other things. For example, you could fairly easily rig this same idea up to track API usage.

If you implement something like the above,let me know how it goes. And if you run into trouble, definitely let me know.

  1. Custom events, a topic for a later series of posts, are one of two ways the GA docs outline for you. But, again, that's only going to help if the downloads originated from your site directly. 
  2. This one in particular is fired on a click of the newsletter form "Submit" button in the footer of this and every page. Feel free to fill that form out to give it a whirl ... 
  3. Special thanks to Joel Meador for a quickie (but thorough) code review on this example. Any mistakes contained therein are my fault, not his. 
  4. This example's in Ruby/Rails because that's what I'm most familiar with. On a different platform? The procedure is probably similar. Just send this post to your dev team and have them take a crack at it. And if they give you any gruff, let me know