'It was you!' moment. Tracking GA users' ID

Someone on behalf of the Google Analytics team
asked me to add this warning message.

Using the technique described below might result in your GA account cancelled.

Said that, if you want to know the reasons and why I think it’s nonsense, here you have the whole story.

No doubt we are lately moving from a 'pageviews' kind of measurement towards a user centric one and that makes sense especially when we have the ability to track users across devices and also offline.

For example, you are trying to answer questions like 'how much it costs to get a user to download your game' and 'how much each user spends on your game'.

The trick is to use the user ID from our CRM or such to tag user activity in our websites so we can close the loop later in the phase where we merge data for customer life-cycle analysis. In some cases there are more than two worlds that we want to combine:

  • Web data
  • CRM data
  • In-game telemetry / in-app / software-usage, or just 'data from product or service usage'

For the web part of that equation, it requires the visitor to be logged in so we can tag all his/her activity with our internal user ID but what happens with all the data from the very first visit till that person decides to register and log in for the first time? We have the “we don't know you', and the 'we know you now' but we were lacking the 'it was you!' moment. That's the gap in the stream.

With the new Universal Analytics Google came with a way to overwrite their randomly generated user ID with the ID from your database what has many benefits, here you have detailed explanation on how to do it but it does not close the gap we mentioned before.

Also because users could delete their cookies, use different browsers in the same machine or in different computers (at work, at home), or different devices (desktop, tablet, smartphone, game console) this gap is bigger than we think but we still want to trace all their activity no matter where it happens.

The solution is simple, it just requires a few lines of code and the possibilities that enables are many and awesome.

Capturing the Google Analytics User ID

Both, classic or the new Universal Analytics, generate a User ID to relate all the information from several sessions in the same browser. We don't need to reinvent the wheel creating more IDs, we just need to capture it in a custom variable or dimension to make it available as GA does not make theirs visible in any report or extraction via API.

Before getting hands down with the code and because I don't want to be firing custom variables at every single pageview, I'll be using browser's localStorage. Don't know what it is? Take a look at this article to get started, as a solutions analytics architect you are going to love it. Even more, if you use Google Tag Manager don't miss Simo Ahava's article Persist dataLayer In Google Tag Manager.

This is the logic I want to apply then you code it the way you want although JavaScript code is offered below too.

Collect visitor ID in Google Analytics

Where that user ID lives and what it looks like

GA stores the user ID in cookies and both, classic and Universal, are a set of two numbers

  • First set is a randomly generated user ID
  • Second set is a timestamp of the first time the cookie was set for that user

Classic Google Analytics:

  • cookie '__utma'
  • value '20048935.207219877.1408047971.1412353137.1412637565.14'

New Universal Analytics

  • cookie '_ga',
  • value 'GA1.2.2110272052.1412637630'

The reason for that second set of numbers, as David Vallejo (he is shy and humble enough to say so but one of the best technical GA specialists worldwide) explained to me: having just the first set of numbers increases chances for collisisons or coincidences, more in particular for sites with a high volume of traffic. By adding the second set, the timestamp, it increases the uniqueness of the user ID, something crucial as you can imagine under the scope of visitor analysis.

Not only that, he taught me a 'trick' that demonstrates what GA considers user ID by opening the console (F12) in your browser showing any page having Universal implemented. Type:


and hit enter. Voilà, there you have it!

Technical solution, JS code

We need to read cookies so we have two options:

  • Write a generic function to retrieve any cookie value even if they are not GA related
  • Write an specific one to retrieve only GA user ID. That could support classic,  Universal or both

First one is handier when you do more cookie related work in your analytics implementation.

The code itself

1st. Generic function to read cookies.

window.getCookie = function (cname) {
  if (document.cookie.length > 0) {
    cstart = document.cookie.indexOf(cname + "=");
    if (cstart != -1) {
      cstart = cstart + cname.length + 1;
      cend = document.cookie.indexOf(";", cstart);
      if (cend == -1) {
        cend = document.cookie.length;
      return unescape(document.cookie.substring(cstart, cend));
  return '';

var GAuserID = getCookie('__utma'); // for classic GA
var GAuserID = getCookie('_ga');    // for Universal

Specific function to read user ID while using Universal Analytics (written by David Vallejo).

window.get_ga_UID = function () {
  try {
    var cookie = document.cookie.match(new RegExp('_ga=([^;]+)'))[1].split('.');
    return cookie[2]+'.'+cookie[3];
  } catch (e) {
    return '';

var userID = get_ga_UID();

If you are one of those who wants to be dressed for all occasions supporting classic (legacy), and Universal here you have it as David puts it:

window.get_ga_UID = function (ga) {
  if (ga == 'legacy') {
    try {
      var cookie = document.cookie.match(new RegExp('__utma=([^;]+)'))[1].split('.');
      return cookie[1] + '.' + cookie[2];
    } catch (e) {
      return '';
  } else {
    try {
      var cookie = document.cookie.match(new RegExp('_ga=([^;]+)'))[1].split('.');
      return cookie[2] + '.' + cookie[3];
    } catch (e) {
      return '';

var userID = get_ga_UID('legacy'); // for classic or legacy 
var userID = get_ga_UID(); // for Universal

2nd. Code sending GA User ID to Custom Variable.
This is where the logic described before materializes into code. I'll assume at this point that 'dimension5' is the one you have previously created, scoped to 'User' (important), to collect user ID.

var utma = getCookie('_ga').split('.');
var userID_CK = utma[2] + '.' + utma[3];
var userID_LS = localStorage.getItem('userID_LS');

if (!userID_LS){
    ga('set', 'dimension5', userID_CK);
} else {
  if (userID_CK && (userID_LS != userID_CK)){
    ga('set', 'dimension5', userID_CK);

Where to place the code?

Functions to retrieve information from cookies could be added at the beginning of the document before the GA JavaScript stuff. Place the code to make that work right before ga('send', 'pageview'); as we'll use custom dimensions that must be set before the pageview is sent.

How does it look like?

Here you have an screenshot of the GA UID collected side by side with UID from a CRM. Now we have that connection made let's the show of deeper user behaviour analysis begin!

Match CRM and GA visitor IDs

I hope you find it useful. Suggestions are welcome. Even more appreciated if you want to share with us how you make use of it for deeper analysis. That could be a complete new post complementing this one.

Thanks David for your help! Also many thanks to my mate Heather Anderson, fantastic EA's frontend developer, superawesome trumpet player and GA implementation architecht in training, for proofreading.

UPDATE: Righ after I posted this article, while chatting with David about the topic he came with a smart idea to keep Google Analytics clientId value as long as possible. In other words, users delete cookies from time to time but they are not so savvy to clear values in localStorage what makes the trick.

Oct 22, 2014
Written by:
Filed under: Technical Analytics

Nov 05, 2014
Posted by:
David Simpson #1

Once you've got the user ID in a custom dimension, you can display other user information from your CRM using the PII Viewer for Google Analytics is a Google Chrome extension.

It allows you to map the user ID stored in Google Analytics to locally stored personally identifiable information (PII) such as name and email address.

Dec 10, 2014
Posted by:
Charles Meaden #2

Thanks for a very informative post

What would be the position be if we randomly generated an Id using Javascript and then stored this in a cookie for google tag manager to read each time?

Dec 17, 2014
Posted by:
Cornel #3

What if you use a third party ID (Facebook User ID), like I did here ? Is this still against GA TOS?

Dec 17, 2014
Posted by:
Ani Lopez #4

Hi Charles and Cornel,
Apparently it is OK to Google if you collect the User ID in the cookie. The issue here is the use of localStorage. It does not violate privacy in any manner and makes the code more effective by sending the data to the custom dimension ONLY when it changes instead in every single page load.

According to them: ?Using HTTP State Management mechanisms to propagate cookie state is a circumvention of our privacy safeguards? but as I?ve said repeatedly it does not violate privacy at all.

I would not bother creating another randomly generated ID or such. It is safe to collect User ID from GA's cookie.

Jan 27, 2015
Posted by:
Stephen Harris #5

What is the purpose of using localStorage (or any other intermediate storage mechanism, for that matter)? Looking at your flow chart, the UID is stored in localStorage, but it's never used. The value tracked by the custom dimension is always the value retrieved from the GA cookie.

This code would accomplish the same thing ...

  var utma = getCookie('_ga').split('.'); 

var userID_CK = utma '.' utma ;
ga('set', 'dimension5', userID_CK);

... without violating GA TOS.

Jul 25, 2016
Posted by:
Amit kumar #6

How can do same thing in php ???

Have your say
twitter @anilopez

Articles I write for other sites

Analytics Tribulations Of An SEO

The art of measure is never easy but when it comes to SEO it's even worst

Challenges of Spanish Language on Search Marketing @ Multilingual Search

'Standard Spanish' is something that I don’t buy into when it comes to international scenarios. I'll explain to you why and some tips to start facing correctly your Spanish strategy.

Handling Multilingual Sites for Humans & Search Engines @ Bruce Clay Blog

The logic behind the scenes to show all content to bots and the right language to users

Mobile detection issues & Google Instant Previews @ Cardinal Path blog

Mobile web represents the bigger headache ever for those wanting to target the small but growing audience they represent nowadays. check your Instant Previews for possible indexation issues.