Offline transactions with Google Analytics

The trouble with web analytics is the possibility of it telling you lots about your website but nothing about your business. A browser is not the same thing as a customer, and yet we forget this in the data that we use to optimize our marketing efforts. Using Google Analytics, part of the solution to this problem is User ID, which allows us to track users as they move between multiple browsers, as long as they log in along the way. However, a lot of the most important interactions in a customer’s journey might not take place in a browser at all – instead they’ll take place in a shop, or over the phone, at an event, or in the customer’s inbox. In these cases, it might be that you can draw together these interactions with your existing Google Analytics data using Measurement Protocol.

Introduced with Universal Analytics, Measurement Protocol is an alternative way of sending data to Google Analytics that gives you far more control than traditional on-page code – allowing you to send custom hits associated with specific users, even if no web pages were involved.

In this guide, I’ll look to explain what can and cannot be done with Measurement Protocol and how to deploy it in practice. Primarily this will be focused on the use case of lead tracking, but the lessons here apply to any application of Measurement Protocol. I’ll also offer some tips and caveats from our experiences deploying Measurement Protocol solutions with our clients.

If you’re not already confident with Google Analytics, you might want to check out Google’s own Digital Analytics Fundamentals before you read further, or at least this guide to how sessions are calculated.

The importance of offline steps

Measurement Protocol stays within Google Analytics’ paradigm of hits, sessions, and users – it’s another way of sending a hit besides the more traditional JavaScript snippet approach.

Looking at our attribution reports in Google Analytics with a purely on-site implementation, we might get the impression that a user:

  • Discovered us when our great content was shared on social media
  • Came back via organic and decided to get in touch
  • Later signed up to attend one of our meetups

If this is a lead generation site, we’d probably be very pleased to see a journey like this, but there are two problems with it. Firstly, it doesn’t actually tell us whether this turned out to be a good lead or a bad lead – should we invest more in content, or does this content just bring in leads that turn up to an event then go dead? Secondly, we risk seriously misunderstanding what it is that turns a website visitor into a likely customer – simply by failing to record steps in the process that might not have taken place on the website.

The journey above might actually look more like this, with offline interactions shown in blue:

  • Discovered us when our great content was shared on social media
  • Came back via organic and decided to get in touch
  • Was called by the sales team, who brought up the topic of relevant upcoming events
  • Later signed up to attend one of our meetups
  • Spoke with the team at the event
  • Arranged a contract over phone and email

Adding in these offline interactions, we have a far fuller view of what this customer’s path to conversion actually looked like, and we can confirm that this was a “good” lead of the sort that we might want to attract more of – rather than just ending the funnel at lead generation.

Use cases

The example above is probably the most common use-case – lead generation. However, we can actually use Measurement Protocol in any situation that meets the following criteria:

  • Users making themselves uniquely identifiable to CRM, e.g.:
    • Customer number
    • Email address
    • Username
  • Non-website interactions that happen after this fact but where the CRM could be referenced, e.g.:
    • Phone call
    • Email
    • Live chat
    • In person (store / showroom / branch / event)

More broadly, you could use Measurement Protocol for any of the following:

  • Conversions that occur away from your website
  • Steps toward conversion that occur away from your website
  • Engagement with your brand that occurs away from your website

In each of these cases, what you’d want to send to Google Analytics is a little different. For example, if you want to record steps towards conversion, you probably want to give them a medium, whereas if you want to record the conversion itself, you want to attribute that to the medium of a previous session. Which brings us neatly to the setup process.

Attribution using measurement protocol

Measurement Protocol sends data to Google Analytics using a GET or POST request to a given URL. The parameters added to this URL are the data itself. There has to be a hit of some sort (such as a pageview, event or transaction), and the time of that hit cannot be overridden – for instance, you cannot place an additional hit into the middle of a session that occurred yesterday. Nonetheless, this facilitates accurate attribution of offline interactions, due to an oft-maligned quirk of Google Analytics – that it uses “last non-direct click” for everything, including the sources and mediums of sessions themselves. As Measurement Protocol hits are by default “direct”, “last non-direct click” attribution causes them to inherit attribution data from previous sessions.

So, for example, if we sent a hit to Google Analytics with no source (i.e. a direct hit) when we spoke to the customer at the event on the 12th of December in the above table, this session would be attributed by Google Analytics to “email”, the last known non-direct source for that Client Id. The only exceptions are if more than 90 days have passed since the last session with a non-direct source, or if you override attribution data in your Measurement Protocol hit.

The last missing component here is matching the customer at the event to his last known session. Typically, the way this works in practice is that wherever on the site a user can be added to the CRM, their clientId is added as an invisible field. Then if we want to send offline interactions recorded in our CRM back into analytics, or send website visits recorded in our analytics into our CRM, we have a unique value that we can use to match browsers to people.


Setup part 1: Prerequisites

Measurement Protocol requires a Google Analytics account that has been upgraded to Universal Analytics. While it’s been a long time since we’ve seen one that hasn’t been upgraded, you can check yours to be sure by going to the Admin menus and checking for Universal Analytics features like the “Referral Exclusion List”.

Google Analytics Referral Exclusion List

This guide is also written under the assumption that you’ll use analytics.js tracking code (or, equivalently, a Universal Analytics Google Tag Manager tag).

Setup part 2: Collecting client ID

Client ID is used by Google Analytics to uniquely identify browsers, and it’s a required parameter for Measurement Protocol hits.

It’s worth noting here that if you have multiple tracking IDs per page, users will generally have the same Client ID across all of them, so you don’t need to worry about getting the right one. You can confirm this yourself by looking at the query parameters of individual Google Analytics hits on your site:

google analytics client id

There are multiple ways to collect a user’s Client ID, in order to send it back with your Measurement Protocol hits. I’m going to cover two here. The first is built into Google Analytics itself:

setup code

This works if you have regular on-page tracking code, and we’d recommend it if you do. Obviously in your case you’re going to want to do something more than just log the Client ID to the console, but we’ll get onto that later.

The second method involves extracting the Client ID from the Google Analytics cookie. I’ve stolen it from Simo Ahava’s post here (number 6 in his list). The good thing about this method is that it’s robust to both Google Tag Manager and on-page Google Analytics code implementations. You’ll need a series of Google Tag Manager Variables. First is a 1st Party Cookie Variable, using the Cookie Name “_ga”:

cookie variable

Next up is a custom JavaScript variable to extract the Client ID from the first variable:

client id from cookie

Once you have this, you can reference the second variable (in my case above, {{ClientID from Cookie}}) when you need it for your CRM. Which brings us neatly to:

Setup part 3: Bringing client ID into your CRM

I’ll offer very little detail here, because it’s going to vary so much from one CRM to the next. In all cases, however, you need to add an additional invisible field to all forms where a user can enter your CRM. You might also want to expand when this is – for example, by ensuring that all email collection on your site is integrated with your CRM. Using this invisible field, submit your Client ID collected from the previous step to your CRM, so that it is always attached to that person.

If someone ever accesses your site again with a new browser and identifies herself or himself (for example by signing in), you’ll want to update this Client ID so that it’s always set to the browser (and thus channel, landing page, device etc.) from which they most recently accessed the site.

Setup part 4: Recording interactions

You send data back to Google Analytics by making POST or GET requests to, for example by making requests with PHP cURL – if you’re unsure on this, it might be worth speaking to your dev team. The parameters of the URL you request are then filled with the data you wish to send. You can do so over HTTP or HTTPS.

In some trickier cases, such as email, you could consider doing this by having a single-pixel image with a source that is set to the Google Analytics URL you wish to request.

Google has a handy tool here to help you build up the URLs that you wish to request, but I’ve outlined the ones you really need to know here:



Explanation Example
v Required Protocol Version v=1
tid Required Tracking ID tid=UA-123456-1
cid Required (or use UserID instead) Client ID cid=213725098.1449428391
t Required Hit Type – typically pageview, event or transaction. t=event
dl Required for “pageview” hit type Document Location – if your hit is a pageview, this is where you set the URL for that page. Must be encoded as a URL (see example).
ec Required for “event” hit type Event Category – if your hit is an event, this is where you set the category, just like you would with a regular Google Analytics event. ec=MyEventCategory
ea Required for “event” hit type Event Action – if your hit is an event, this is where you set the action, just like you would with a regular Google Analytics event. ea=MyEventAction
sc Optional Session Control – set to “start” if you’re worried about continuing a user’s previous session within your session timeout window (default of 30 minutes). Set to “end” if you’re worried about a user continuing the session you’ve started within your session timeout window (recommended). sc=end
aip Optional Anonymize IP – set this to 1 if the IP (i.e. office) from which you’re sending requests is filtered out of your reporting view (recommended). aip=1
sr Optional Screen Resolution – necessary if you’re filtering out screen resolution (not set) traffic to reduce Measurement Protocol spam. sr=1024×768
dh Optional Document Host Name – necessary if you have a hostname filter to reduce Measurement Protocol spam. Not necessary if you’re using dr (below).
dr Optional Document Referrer – useful if you want to manually set the full source of your hit (as opposed to just hostname). Without this, Measurement Protocol hits are “direct”, meaning that they’ll inherit the source of the user’s previous session (which is often what you want). Must be URL encoded (see example).
cd<dimensionIndex> Optional Custom Dimension – this requires a little bit of interface setup, but it’s useful for debugging to have a hit-level custom dimension to flag up which hits are sent by Measurement Protocol. cd1=MeasurementProtocol
ni Optional Non-Interaction flag – useful for ensuring that Measurement Protocol events do not inflate your session count, or affect engagement metrics. This is only applicable to “event” hits. ni=1

There’s also a whole bunch of other parameters, which can be used to set anything you’d normally set with an on-page hit, and more besides. You can see the full documentation here.

For example, if we wanted to send an event with:

  • Category: “Lead”
  • Action: “Qualified”
  • Screen Resolution: “MeasurementProtocol” (to avoid one of the spam filters)
  • Hostname: (to avoid another spam filter)
  • Custom Dimension 1: “MeasurementProtocol” (for easy segmenting)
  • IP address: (to avoid an office IP filter)
  • Session Control: Start (to force this hit to be treated separately from a user’s previous session if we happen to deal with the lead super quickly)

We’d request the following URL:[InsertClientIdHere]&ec=Lead&sr=MeasurementProtocol&ea=Qualified&uip=

Note that this example sends a single hit to a “/collect” URL. To send multiple hits, you can either use multiple URLs like this one, or use the “batch” method, which is documented here. The validator linked above will allow you to build a hit containing both an event and a pageview, but that would be multiple hits, and does not work.

Setup Part 5: Google Analytics interface

Depending on what you’re doing, you may not have to set anything up here. However, in most cases, you’ll be sending conversions of some sort, in which case the usual goal configuration setup applies. If you’re sending transactions, then as well as the additional required parameters, you will need to enable eCommerce tracking within the interface – just as you would if you were sending transactions via on-page code.

Measurement Protocol with User ID

If you really want a thorough view of customer journeys on your site, then it needs to be multi-device. Unfortunately, Google Analytics doesn’t currently have the ability to tie browsers together until they sign in, and as for many sites phone visits are typically informational and as such do not involve sign-in, this adds limited value. Nonetheless, if you’re interested in UserID, check out our guide here – essentially the only complication for Measurement Protocol is that you’ll need to use the User ID parameter (uid=****) as well as or instead of the Client ID parameter (cid=****).

Reporting caveat

In the lead generation example, one problem with using Measurement Protocol is that it will artificially inflate your session count. This is because it works by attributing additional converting sessions to existing users, rather than by adding additional conversions to existing sessions. In fact, one major limitation is the inability to set the time of a hit – the time will always be recorded as whenever you sent it, thus preventing you from slotting a conversion onto the end of an existing session.

You can avoid this session inflation by having a separate view or segment that filters out some unique attribute that you can add to your Measurement Protocol hits (perhaps a fictional URL or a hit-level custom dimension). This is fine as long as you don’t need the correct number of sessions and goals in the same report, you’ll be able to use the interface, otherwise you’ll need to set-up some custom reporting – the Google Analytics add-on for Google Spreadsheets being a good place to start. Alternatively, if you’re only using the Measurement Protocol to send “event” hits, you can use the non-interaction flag to avoid any inflation of your session count.



Useful Tools & Guides: