Tracking Offline Transactions With Universal Analytics

March 4, 2014
Painting of girl

"We don’t do commerce, we just have a lead generation form."

Google Analytics last fall shot some video talking about Universal Analytics that featured Dan Wilkerson and me. At one part of the video, I talk briefly about Georges Seurat’s painting ‘Sunday Afternoon on the Island of La Grande Jatte’.

I’m gonna be honest, the inspiration for that analogy was from Ferris Bueller’s Day Off. At one point the characters go to the Art Institute of Chicago, and one character in particular, Cameron, stares at the painting as it steps further and further into the painting. If for some reason you’re culturally illiterate, here’s what I’m talking about:

My point was sort of the reverse. The picture of the little girl above, focused in, is a small part of the story, but in the past, that was all we had to go on. As analytics have proceeded over the years we’ve got bigger and bigger pictures as we step further back from the painting.

picture of girl

The picture of a girl becomes a girl and her mother walking amongst a wide variety of people, and is that water over there?


The more we see, the bigger a story we can tell.

So how does this relate to websites?

Universal Analytics Goes Offline

The majority of commercial websites out there don’t actually process a transaction on your visit to their website. Sometimes it’s a lead generation website, where the primary goal is to get someone to submit a contact form, and then later, maybe days, weeks, or even months, a transaction occurs somewhere else. It’s easy to tie your attribution to the form submission, but much more difficult to tie it to hard revenue numbers.

Marketers and third-party tools have approached this in several different ways in the past. One common thing to do is to feed attribution information into the form submission, and then carry that along to the final transaction. This has the benefit of being able to assign some revenue numbers to specific campaigns but loses the depth of that visitor's experience. Let me give an example.

Here’s what most systems might show you when considering attribution:

Branded Campaign Visit => $100

Here’s what actually happened:

A visitor does an organic search on Google for "Widgets."  He finds your website and reads several of the great blog articles your team has written. He clicks on your Facebook page link, and follows you on Facebook. A week later he sees one of your promoted posts on Facebook, and clicks the link, changing his referral to being from your social media campaign. When he arrives he is given variation B of your new content experiment. He likes the new look and it’s encouraged him to convert, but he has to go do something and puts it off. The next day he does a branded search for your company, and sees one of your branded Google Ads campaigns, clicks on that, again changing his referral information. He sees and clicks on a specific image banner on the home page to get to the form submission page, where he finally submits his information. Two weeks later he actually processes a transaction offline with you for your Widgets for $100.

What Was Lost?

Multi-channel attribution is non-existent. Our visitor might be better described as:

Organic (Not Provided) =>

Social Media Campaign (Facebook) =>

Branded Campaign =>


But did that content experiment sway his conversion? What was the value of that? What about the banner he clicked on? Shouldn’t it be also:

Organic (Not Provided) / Content A / Did Not View Banner =>

Social Media Campaign (Facebook) / Content B / Did Not View Banner =>

Branded Campaign / Content B / Did Not View Banner =>


How are you supposed to accurately judge all your campaigns if all you’re doing is Last Non-Direct Click Attribution? How are you supposed to accurately judge your content experiments if all you are measuring are form submissions, rather than the revenue generated which can be two wildly different metrics?

The answer is to use the Universal Analytics Measurement Protocol and track your users’ eventual conversions offline, tying the revenue to their visits.

How To Track Offline Conversions In Five Easy Steps

Step One: Get Universal

The Measurement Protocol requires Universal Analytics so if you’re still using Google Analytics Classic, or Traditional Google Analytics, you’ll need  to upgrade. Check out Alex’s post on upgrading here if you need to do that.

Step Two: Set Up Custom Dimensions

You’ll need to go into the Google Analytics interface and set up at least one, if not two custom dimensions for your property. UID and CID.

UID will be our hold for a User ID. The full User ID functionality for Universal Analytics is coming soon hopefully, so you might as well get this rigged up and ready to go. It’s not absolutely required in this case, however, our examples will be using it.

CID is the Client ID. This is the number that Google Analytics uses to identify a particular user/device/browser instance. On the web, it’s normally stored in a first-party cookie, or for a mobile app, it’s generated randomly on the install. This one is key to having this whole thing work.

Step Three: Grab the Data

Once we have our Custom Dimensions defined, it’s time to go onto our website and actually grab the data. For the UID this can be anything. I often will use a uniqid() PHP function to generate a unique ID, but you can do it however you like. Just keep in mind it can’t be personally identifiable information. So no emails or social security numbers, please. Create this UID on first page load, store it in a cookie and in your session, so that you can pass the UID into GA as a Visitor level custom Dimension:

ga(‘create’, ‘UA-XXXXX-X, ‘’);
ga(‘set’, ‘dimension1’, ‘PUT THE UNIQUE ID HERE’ );
ga(‘send’, ‘pageview’);

The CID is a little more complicated. We need to grab that from the tracker or the cookie. This JavaScript works nicely.

ga(function(tracker) {
clientId = tracker.get(‘clientId’);

This will only pull the CID value for the visitor AFTER the page has been tracked and Universal Analytics exists on the page, so you should put it after your UA tracking code. You can easily put its value into a hidden input field in a form this way and pass it into your back end system for storage with the user information:

ga(function(tracker) {
clientId = tracker.get(‘clientId’);
document.forms[0].cid.value = clientId
<input type=”hidden” id=”cid” name=”cid”>

Step Four: Measurement Protocol Hit

So now, hopefully, in your system you’ve collected the CID and passed it along with the user ID and other information about the user that your marketing software might care about.

Eventually, some of these users will complete transactions, and when that happens you’ll make a measurement protocol hit. You can automate it in your systems, or you could do it manually if you don’t have a tremendous number of transactions. (But automating it would be probably better). I’ll leave it up to you how you want to automate it into your system.

For a transaction, you’d make at least two http requests. One for the transaction, and another for the actual item. If you have multiple items, you’d have multiple item hits. They’d look something like this:……

Here’s how those break down

Transaction Hit

v=1  //v always equals 1 for now.

&tid=UA-XXXXXX-X  //insert the correct property id here

&cid=YYYYYYYYYYY//the CID you captured from the user on form completion goes where Y goes

&t=transaction  //it’s a transaction

&ti=ZZZZZZZZZZZZ   //this is a transaction ID we generated dynamically. As long as this is unique, you can even create this at the time this measurement hit is generated. If you have specific transaction IDs in your system you could pass them here, or set it to be a random ID like uniqid() above. Something like: 52ea5aab1f0c2

&tr=1100 //the purchase value of the transaction

&cd1=23bc5c58a4a4b //this is the custom dimension for slot 1, with our userID

Item Hit:

v=1 //always 1 again

&tid=UA-XXXXXXX-X //again modify for your property id

&cid=YYYYYYYYYYY //same CID as the transaction, and the initial user

&t=item //it’s an item hit

&ti=ZZZZZZZZZZZZ //the same transaction id as passed in the transaction hit

&in=Widget //the product name

&ip=1100 //product price

&iq=1 //product quantity

&ic=IF5739 //SKU, whatever yours is. If you don’t have a SKU you could make one, or you could use this area for additional product information. Just remember that the SKU needs to be unique per transaction. If you send the same SKU for multiple items in a transaction, only the last one will get recorded. So if you use it for concatenating something like product color etc, just be sure that it remains unique as well. If you want to use it for more generic product category stuff that is used for multiple products, you can concatenate on some sort of unique hash at the end which you can strip off later in reports.

&cd1=23bc5c58a4a4b //and the user ID again for the custom dimension

With pretend numbers in place these hits might look like this:……. 509493873&t=item&ti=52ea5aab1f0c2&in=Widget&ip=1100&iq=1&ic=IF5739&cd1=52ea5a8bc6a4a

You can also send a virtual page hit, but it’s not necessary. I’ve done it both ways, and I’ve yet to determine which way I like better. We tested these by sending a page hit for some transactions, and not for others. The page hit we sent on half the later transactions were sent prior to the transaction and item hit:

v=1 //always 1

&tid=UA-XXXXXX-X //again the property ID

&cid=YYYYYYYYYYYYYYYYY // again the CID of the initial user

&t=pageview // this one is a virtual pageview

&dp=/offline/conversion //this is the page

&dt=offlineconversion //this is the title

&cd1=23bc5c58a4a4b //the userID again for the custom dimension

This does not appear necessary, but I am mentioning it so the results make sense.

Results in the Reports

Here’s how it looks in the standard reports. After some initial visits and form submissions, the data looks like the below screenshots. Visits and goal completions, but not page value, no transaction information, and no revenue.

Traffic report chart example


Traffic reports generated show visits but no revenue or conversions.

Acquisition-all-traffic-goal-2-before image


We see goal completions for forms though and a 25 percent conversion rate on the inquiry form! Not bad. I guess those are good source/mediums.

Conversions-ecommerce-overview-before image


No commerce of course. At least until the next day when we sent the measurement protocol hits.

Acquisition-all-traffic-ecommerce-after image


Now not only do we see the visits, and their form completions, but we see who actually eventually converted, and for how much. We had a 40 percent conversion rate from bing/referral but not a single transaction from those guys. though is looking pretty good, particularly for average order value.

Conversions-ecommerce-overview-after image


And now our commerce report is full of lovely yeast and beef extract products for our fake Marmite store.


If you process revenue in some way offline and haven’t tied it back into your Google Analytics data yet, what’s stopping you? With Universal Analytics it’s easy to pull back from the painting and view a bigger picture than just the little girl with the white hat. Get better insights into your site today by using offline conversions and the measurement protocol.