Tracking downloads using URI redirects [tutorial]

A common requirement on the web is to track downloads. In this guide, we’ll cover two approaches to tracking downloads:

  1. Tracking downloads using Javascript event listeners on the link click (common approach)
  2. Tracking downloads using the collector URI redirect (more robust / reliable approach)

1. Tracking downloads using Javascript event listeners (common approach)

Downloads are generally triggered when a user clicks a particular link.

A common approach, then, to tracking downloads, is simply to use Javascript and add an event listener on the link / button that needs to be clicked to trigger a download, such that when that link or button is clicked, a Snowplow event is fired. Assuming it is a standard link click that triggers the download, you can for example simply enableLinkClickTracking on initializing your Snowplow JS tracker and make sure the href has an unambiguous id so that you can easily spot the link clicks that trigger downloads. These will then be tracked in Snowplow automatically.

The problem with this approach is that if the download causes the user to leave the website (e.g. in order to load a PDF in the browser) there’s no guarentee that the link click event will fire before the user leaves the website.

A more robust approach, using the collector URI redirect, is detailed below.

2. Tracking downloads using the collector URI redirect (more robust / reliable approach)

Both the Snowplow Clojure and Scala RT collectors support URI redirects. This means they can be used for any type of click tracking. This works as follows:

First, you take the link to the asset that will be downloaded e.g.

<a href="">Download here</a>

You replace the URI in the link link with a Snowplow collector URI, but add /r/tp2 to the URI. This will forward anyone who clicks the link to the Snowplow collector itself. The /r/tp2 tells the Snowplow collector to redirect the user to another URI:

<a href="http://my-snowplow-collector/">Download here</a>

Now add the URI that you want the user redirected to (i.e. URI that the asset to be downloaded is located on) to the querystring as the value for the u parameter. As this is a querystring parameter, we’ll need to URL-encode the URI. So in this, we want to direct the user to:

Let’s URL encode it e.g. using this URL encoder:

Then add it to as the u parameter:

<a href="http://my-snowplow-collector/">Download here</a>

This will successfully redirect, and record the event as a uri_redirect event. If we’d prefer to record it as a different event (e.g. a custom structured event) we can simply add the e parameter to the querystring and set it’s value to any of the values allowed in the Snowplow Tracker Protocol. So if, for example, we want to record this as a custom structured event with category = download and action = downloaded-my-excellend-pdf, we’d add the following name value pairs to the querystring, based on the Tracker Protocol:

  • e=se (event = structured event)
  • se_ca=download (category = download)
  • se_ac=downloaded-my-excellend-pdf (action = downloaded my excellent PDF)

Putting this all together our link becomes:

<a href="http://my-snowplow-collector/`">Download here</a>
1 Like

Hey Yali, thank you for this tutorial.
The events generated by the URI redirect approach do not have a domain_userid, at least in our case. Is there a way to have it filled?
Asking because more and more browsers block 3rd party cookies so the network_userid is often reset, which makes it difficult to associate the click event with other events tracked by the Javascript tracker.

Hi @Boris

If you want a reliable user_id, it’s a good idea to get your collector running on the same domain (well, a subdomain of) your website, then your cookies won’t be third party but will be first. network_userid is very liable when used with a first party Snowplow collector.

You can however add a parameter to your URL when tracking if you want to track the domain_userid manually, just add ?duid=.... to your URL as the query string (or extend the existing query string with &duid=....). In fact, I think you can use any property from the Snowplow Tracker Protocol.

You can read the cookie values out of the JS tracker like so:

1 Like

Hi Paul, thanks a lot for your answer,

If we put the collector in the same domain, is that correct that domain_userid and network_userid would become equivalent (not the same value obviously, but let’s say redundant) for events tracked with the Javascript tracker?

We own multiple websites we’d like to track our users across. These days with more browsers blocking 3rd party cookies, is the recommended approach to enable cross domain tracking as documented in

The don’t quite become equal. In Safari (which has the strictest rules of the popular browsers) the domain_userid will always be limited to a 7 day lifespan but it is always first party. network_userid can have a lifespan of up to 2 years but only if set from a “first party” collector. explains the differences between the browsers.

Cross domain tracking is a good approach for stitching users across websites where it is common for users to click a link that takes them from one site to another. A “third party” cookie used to be useful for stitching across sites and can be useful in Chrome still but this is becoming a far less viable option now (and I wouldn’t recommend setting up anything with a third party cookie these days as its usefulness is very limited and likely won’t have much longevity).

1 Like