Upcoming LunaMetrics Seminars
Washington DC, Sep 22-26 Boston, Oct 6-10 Chicago, Oct 20-24 Seattle, Nov 3-7

Tracking Offline Transactions with Universal Analytics

girl-1

“We don’t do ecommerce, we just have a lead generation form.”

Google Analytics last fall shot some video talking about Universal Analytics that featured Dan Wilkerson and myself here at LunaMetrics. 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.

girl-2

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

girl-3

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 visitors 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 AdWords 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 =>

$100

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 =>

$100

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 Let’s Say 5 Easy Steps

Step 1: 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 2: 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 3:

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, ‘yourdomain.com’);
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.

<script>
ga(function(tracker) {
clientId = tracker.get(‘clientId’);
});
</script>

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:

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

Step 4:

So now, hopefully, in your system you’ve collected the cid and pass 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:

http://www.google-analytics.com/collect?v=1&tid=UA-XXXXXX-X&cid=YYYYYYYYYYYYYYYY&t=transaction&ti=52ea5aab1f0c2&tr=1100&cd1=23bc5c58a4a4b

http://www.google-analytics.com/collect?v=1&tid=UA-XXXXXX-X&cid=YYYYYYYYYYYYYYYY&t=item&ti=52ea5aab1f0c2&in=Widget&ip=1100&iq=1&ic=IF5739&cd1=23bc5c58a4a4b

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 transactions id’s 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:

http://www.google-analytics.com/collect?v=1&tid=UA-123456789-1&cid=75839030.509493873&t=transaction&ti=52ea5aab1f0c2&tr=1100&cd1=52ea5a8bc6a4a

http://www.google-analytics.com/collect?v=1&tid=UA-123456789-1&cid=75839030. 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 like in the standard reports. After some initial visits and form submissions, the data looks like the following screenshots. Visits, goal completions, but not page value, no transaction information, no revenue.

Acquisition - all traffic - ecommerce - before

Traffic reports generated show visits but no revenue or conversions…

Acquisition - all traffic - goal 2 - before

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

Conversions - ecommerce - overview - before

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

Acquisition - all traffic - ecommerce - after

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% conversion rate from bing/referral but not a single transaction from those guys. clowncollege.com though is looking pretty good, particularly for average order value…

Conversions - ecommerce - overview - after

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

Conclusions

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.

Sayf Sharif

About Sayf Sharif

Sayf Sharif is a Web Analyst, and expert in Usability and UX, who has worked with businesses large and small to maximize their online presence since the beginning of the Web, winning numerous awards along the way. Sayf has studied human tool use from the stone age (he went to graduate school for Archaeology) to the information age (he started programing on his father’s TRS-80), and is always interested in what goals people wish to accomplish using their tools, and how successful that experience was.

http://www.lunametrics.com/blog/2014/03/04/tracking-offline-transactions-universal-analytics/

24 Responses to “Tracking Offline Transactions with Universal Analytics”

James says:

So if I understand correctly:

Assign USER ID to random visitor, they fill out form with their name attached. You save this to your systems.

Guy walks in offline store and buys the widget, you get his name and add it to the system.

You (or automate) match that offline name, to the name recieved from the form which has a USER ID attached.

Then send that mapping to GA to assign that conversion to the original source.

??

Pawel says:

Sayf,

great article – thanks for sharing. I just wanted to clarify one thing — CID contains visitor level identifier, right? If so then if a user visits our website once from google organic on january 31st and submits a form, we will have reported: 1 visit (google / organic), 1 goal conversion (100% CR), 0 ecommerce transactions (0% ecommerce CR). Lets assume now, that then this user purchases a product on February 2nd and we send transaction hits to Google Analytics. Then if we report data for February 2nd we will have 1 visit (google / organic), 0 goal conversions (0% CR), 1 ecommerce transaction (100% ecommerce CR). The data for the full range (January 31st-February 2nd) will look like this: 2 visits (google / organic), 1 goal conversion (50% CR), 1 ecommerce transaction (50% ecommerce CR). Am I right?

Sayf Sharif Sayf Sharif says:

James, that’s correct, you could do that. As long as you can identify them on the site, and pass their CID and/or User ID to your system, and then can later identify them on your POS in the real world brick and mortar store, you can match that revenue in GA to that user.

Sayf Sharif Sayf Sharif says:

Pawel, If I understand you correctly then yes that’s how it should appear.

Matt Bulow says:

Hi Sayf,

Thanks very much for this, it really helped me understand how Universal Analytics can now be used to track the entire customer journey.

Matt

Maggie says:

Thanks for this great article, Sayf. I have one question: if UA is in Google Tag Manager, how can I make sure the CID is pulled after the page is tracked?

Daniel says:

How are you able to match an offline visitor and sale to a specific, anonymous website visit?

If we had a way to collect personal info, and all online visitors provided their personal info before making an offline purchase, I can see how you could match transactions to unique visitors, but GA prohibits the collection of personal info and only a small percentage of people ever submit their personal info normally.

So how can we match an offline transaction to an online GA UID or CID, assuming the above limitations are true?

How were you able to match your transactions to the UID/CID in your example?

And finally, how were you able to use the measurement protocol to send the correct, required transaction data and ensure that it was properly attributed to the correct online user profiles in the correct GA Property? Meaning what app(s), script(s) or platform(s) were actually used to send the right transaction data to the right place in GA?

One more question actually, if the cost data upload occurs later than the actual transactions took place, is it possible to define the correct time and date of the transaction in GA?

Thanks.

Sayf Sharif Sayf Sharif says:

Daniel,
We can assign a User ID to anyone, the hard part is tying it to other devices for instance. For that we’d need to have some sort of identifying login. However the CID is the id of the cookie, and that is something that identifies the visit in GA. As I showed above, we can take the CID from an otherwise anonymous visit, and pass that with a form submission. Then we can associate all offline transactions with that CID.

The subject of personally identifiable information (PII) within Google Analytics is an ongoing one, but the key part is “identifiable to Google”. A hashed value, or just an ID number that you associate in your database, are completely allowed. So we keep their otherwise personal information offline in our own database, but we can still use and assign a userid or use the cid.

So to answer the third question and reiterate, we can capture the CID from a user, and then alter use that CID to pass the transaction. The system matches the transaction automatically via the CID.

As far as sending the correct transaction data, that’s really up to you to create your measurement protocol hit with the correct revenue information, etc, but as far as the property, you’ll notice that one of the parameters of the hit is the property ID. You can use various means to send this data, it could be done automatically within an offline system, in a Google Doc, built manually by hand, it just needs to make that http request to Google, from wherever it makes it.

the transaction comes in as when the hit takes place. You can’t redefine that unfortunately. The best you can do is automate the system so that the offline transaction hit occurs at the same time, or roughly the same time, as the offline transaction itself.

Sayf Sharif Sayf Sharif says:

Maggie,

Well, to not require luck, you’d have to force tag order. There are a variety of ways to do this. It’s a little easier if you’re using a custom html tag for your google analytics, rather than the inbuilt tag. You can just add a datalayer.push event to the end of that code and then have another tag that fires on that new event, which grabs the CID code, and pushes it also into the datalayer, and then you’d grab the CID as a macro value and can use that after that based on an additional chained event, etc.

chaining events like that in tag manager really is it’s own blog post I think.

Phil Caines says:

Great post Sayf,

I will try and use this strategy for a client who is using Zoho for tracking. Do you know of any successful implementations of offline sales conversions with Zoho?

Cheers,
Phil

Sayf Sharif Sayf Sharif says:

I do not believe I know anyone using Zoho in this way. Good luck!

Mark H says:

Phil,

I am about to do that. Via auto-tagging, I will pass GCLID into landing pages and form submits will go into Zoho and carry on the GCLID. Using offline conversions, I will attach the actual conversion to the GCLID giving me a full picture. But the next thing…

Sayf,

So, I’m guessing this is not for Adwords, and so is a full holistic coverage across all web properties. Right?

Basically, what you’ve outlined functions like gclid but independent of Adwords.

If your answer is yes, is there a way without needing to code to generate the unique IDs and be able to do all this by just using tag manager?

Thanks!

Sayf Sharif Sayf Sharif says:

Mark,

So we’re not really generating Unique ID’s so much as grabbing the ID of the user’s cookie itself in this case. It’s unique, we’re just not generating it, GA is.

The scripts above could be used in GTM as a custom javascript macro to grab it, and do something with it in GTM. The key is to make sure you have that CID of that user, not the GCLID. The CID identifies their device/browser cookie, and will let you reference them again in the future.

However you’d need the code at least in GTM to grab the CID, and then you’d need to do something with it to capture it in some way, so you could reference their offline behavior later.

Joe says:

Hi

Sorry if I have missed this but what scope are we setting on the custom dimensions?

ALso is the user ID supposed to be session based? I Just wondered how this equates if the user starts using different browsers during the process.

Thanks

Joe

Sayf Sharif Sayf Sharif says:

Scope should be User level.

If you’re using the new User ID feature, and your user is logging in, then you can use that, and track the pattern across browsers.

Sofia Agboatwalla says:

Hi Sayf,
I am using the Measurement Protocol to pass the client id along with events. I am able to view the events when I log in to Google Analytics. Where can I see any data based on Client Ids? I have created a custom dimension called CID as per the article above:
‘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.’
I have also set up a custom report with Metric Group: Event/Session With Events and Dimension Drilldown->Custom Dimensions->CID but am unable to view any data based on CID. Please advise.
Thanks

Sayf Sharif Sayf Sharif says:

Sofia,

Are you passing that CID as a custom dimension value as well? Sending the CID with the hit, will record it as that CID in GA, but it won’t automatically pass into a custom dimension named CID. You’d need to also pass it as a custom dimension value (like cd1 in the measurement protocol hit) for it to be seen in GA within that dimension.

If you ARE passing it as a dimension, and the dimension is set up correctly within GA, then I am not sure, you might have some sort of syntax error in your hit.

Mark H says:

Thanks Sayf! That clarifies the part about not needing to generate. Would this apply to cross-domain tracking as well?

Sayf Sharif Sayf Sharif says:

It should, you just need to send the right information with the measurement protocol. When you send an offline hit, there’s no cookie to base it off of, so it’s sending the hit to GA, which then based on the hit determines the visit, etc.

The problem with cross domain tracking stems from having multiple cookies, so the lack of a cookie in this case generally will solve the problem.

Imagine if you had 2 website domains, and an offline hit.

User hits a.com and gets a CID of 123
User hits b.com and gets a CID of 456 and then submits a form.
That form submits the CID (456) which later is used by:
Another Server sends an offline hit with CID 456

So in that case you’d have 2 users.

If you do cross domain on a.com and b.com what happens is this:

User hits a.com and gets CID 123
User hits b.com which is linked by a.com through cross domain tracking and is ALSO assigned CID 123.
User submits form with CID 123 attached.
Server sends measurement protocol hit with CID 123

One user, across 2 domains, and an offline hit.

Hope that helps.

Chris says:

Hi Sayf,

Brilliant article, thanks.

Would I need to remove my standard e-commerce tracking code for this to work?

I’m looking to implement this on a site where payments are taken off-site, so e-commerce tracking is sketchy at best!

Thanks, Chris

Sayf Sharif Sayf Sharif says:

Chris,

It works independently, so if you want to replace sketchy online tracking, with more accurate offline tracking, then yes I”d remove the online stuff if it’s not accurate, and replace it with more accurate offline measurement.

Onofrio says:

Hi Sayf,
I haven’t a free custom dimension for storing the cid.
Is there a possibility to obtain it with “Core Reporting API” in java? I’m looking for all 230 pre-defined google dimensions, but it seems that cid doesn’t exist. Can you help me? Thank you for all. Onofrio

Sayf Sharif Sayf Sharif says:

It’s not in the Core Reporting API. You’ll need to use a custom dimension for it unfortunately. Are there any of your used custom dimensions that you can spare?

Onofrio says:

Hi Sayf,
thank you very much for your response.
If this is the only way, I will use a custom dimension.
Thank you. Regards. Onofrio

Leave a Reply