I am constantly fielding questions from our clients that ask:

  • How can I tell if our customer experience needs improvement?

  • Where are the friction points that cause our current or potential customers to leave or drop off?

  • What is the most common path to conversion?

These questions are near impossible to answer with out-of-the-box Google Analytics tracking. That is why analysts, like myself, go to great lengths to enhance the data collected in Google Analytics. One of the best ways to start answering these questions is by establishing a strong foundation of row-level data about your users. Imagine viewing a second-by-second log of interactions that someone took on your website leading up to a drop-off or a conversion. That kind of data is invaluable and the tutorial below can get you started in the right direction.

This tutorial is intended for a mid-level analyst. If you would like help from a professional, please consider reaching out to us at info@compassred.com.

Step 1: Create Custom Dimensions for Client ID, Session ID, and Hit ID in Google Analytics

The first step in our process is creating Custom Dimension placeholders in Google Analytics for Client ID, Session ID, and Hit ID. This is a pretty straightforward process, but you will need Edit access at the Property level in Google Analytics before you can get started. If you have the correct permissions, complete the following in order:

Open Google Analytics and navigate to the Admin panel of the Property you would like to send Client ID, Session ID, and Hit ID

Under the Property Settings, click on Custom Dimensions

Click +New Custom Dimension and add your first Custom Dimension for Client ID. The scope can be either User or Session. There are some limits on how User Custom Dimensions can be used, so I recommend setting scope to Session instead.

Complete the same process for Session ID and Hit ID; pay attention to the scopes. Session ID should be scoped to Session and Hit ID should be scoped to Hit.

Check to make sure that your Custom Dimensions look similar to mine. Your Index (column 2) might be different depending on how many Custom Dimensions you already have setup. If it is different, be sure to note it somewhere — you will need to make a change to the code in Step 2. Speaking of which, Step 1 is done and onto Step 2.

Step 2: Create a Custom Task to Capture Client ID, Session ID, and Hit ID in Google Tag Manager

Now that we have Custom Dimensions setup in GA, it’s time to populate those dimensions with actual data. For this step, we are going to use a somewhat hidden feature inside Google Tag Manager called Custom Task. What Custom Task allows you to do is append a function to your Google Analytics tags that executes at the same time as your tag. It doesn’t sound all that impressive at first, but it makes setting up Client ID, Session ID, and Hit ID so much easier and less prone to errors. If you’d like to learn more about Custom Task, Simo Ahava has a great post on his blog that I used as the inspiration for this post.

This step will require Publish access to the Google Tag Manager container that aligns with the data being sent to your Google Analytics Property. If you have the correct permissions, complete the following in order:

Create a New Custom Javascript Variable and copy/paste the code belowinside the code shell. Take some time to read through the script to understand what it’s doing. I erred on the side of human-readability when writing it.

function() {  // customTask function wrapper  return  function (model) {    //function for declaring Client ID, Session ID and Hit ID and sending to Cookies / Custom Dimensions
function setClientSessionAndHitId () {            var gaClientIdCookie = '_gaclientid';          var gaSessionIdCookie = '_gasessionid';          var gaHitIdCookie = '_gahitid';          var domainPath = (function () {                var hostname = window.location.hostname;          var myDomain = 'domain=' + hostname + ';path=/';                   return myDomain;                }) ();          var clientId = model.get('clientId');          var newSessionId = (function () {          var currentDate = (function () {           var today = new Date();       var dd = today.getDate().toString();       var mm = (today.getMonth()+1).toString(); //January is 0!       var yyyy = today.getFullYear().toString();                  if (dd.length<2) {             dd = '0' + dd;         }          if (mm.length<2) {             mm = '0' + mm;         }          return yyyy + mm + dd;          }) ();        var randomNumberString = Math.floor((Math.random() * 10000000) + 1).toString();        var randomEightDigitNumber = (function () { if (randomNumberString.length === 8) {            return randomNumberString;           } else {                                   while (randomNumberString.length < 8) {                                    randomNumberString = '0' + randomNumberString;                                  } return randomNumberString;                                }                               }) ();       return currentDate + '|' + randomEightDigitNumber;       }) ();     var newHitId = (function () {        var currentTime = (function () {                          var today = new Date();                          var hh = today.getHours();                          var mm = today.getMinutes();                          var ss = today.getSeconds();                                                     if (hh<10) {                              hh = '0' + hh;                            }                           if (mm<10) {                              mm = '0' + mm;                            }                           if (ss<10) {                              ss = '0' + ss;                            }                          return hh + ":" + mm + ":" + ss;                        }) ();       return currentTime;       }) ();   //function for setting 30 minute cookie (mimic GA session)   function set30MinuteCookie(cname, cvalue) {      var d = new Date();      d.setTime(d.getTime() + (30 * 60 * 1000));      var expires = "expires="+ d.toUTCString();      document.cookie = cname + "=" + cvalue + ";" + expires + ";" + domainPath; }
//function for setting 10 year cookie (until user clears cookies or it's reset)
function set10YearCookie(cname, cvalue) {      var d = new Date();      d.setTime(d.getTime() + (10 * 365 * 24 * 60 * 60 * 1000));      var expires = "expires="+ d.toUTCString();      document.cookie = cname + "=" + cvalue + ";" + expires + ";" + domainPath; }
//function for getting cookies
function getCookie(cname) {        var name = cname + "=";        var decodedCookie = decodeURIComponent(document.cookie);        var ca = decodedCookie.split(';');        for(var i = 0; i <ca.length; i++) {            var c = ca[i];            while (c.charAt(0) == ' ') {                c = c.substring(1);            }            if (c.indexOf(name) == 0) {                return c.substring(name.length, c.length);            }        }        return "";    }
//function for setting Client ID
function setClientId() {      set30MinuteCookie(gaClientIdCookie, clientId);            model.set('dimension' + 1, clientId);    }            //function for setting Session ID      function setSessionId() {      var sessionId = getCookie(gaSessionIdCookie);            if (sessionId === "") {        sessionId = newSessionId;     } else {        sessionId = sessionId;     }            set30MinuteCookie(gaSessionIdCookie, sessionId);            model.set('dimension' + 2, sessionId);    }      //function for setting Hit ID
function setHitId() {      set30MinuteCookie(gaHitIdCookie, newHitId);            model.set('dimension' + 3, newHitId);    }
//final execution
setClientId();          setSessionId();          setHitId();
}        setClientSessionAndHitId();     }}

If your Custom Dimensions were different from mine, you will want to alter the code below to reflect the appropriate index. This line appears a total of three times within the code (once for Client ID, once for Session ID, and once for Hit ID). Be sure to update the number (e.g. 1 below) to reflect the appropriate Custom Dimension index you have setup in GA (e.g. if your Custom Dimension index for Client ID is 13, then change the 1 in my code to 13).

model.set('dimension' + 1

Save your variable as ‘JS Custom Task’ or something similar.

Add your JS Custom Task variable to an existing GA Settings variable. If you do not have an existing GA Settings Variable then create one following this guide. Once you have your GA Settings variable opened up, navigate to Fields to Set and add a field called ‘customTask’. Assign the value to your JS Custom Task variable you just created. Refer to the screenshot below for what it should look like:

Save and QA your changes using preview mode. You should be able to see your dimensions being sent in your network calls and your cookies should show up in the Chrome debugger as well.

Once you are satisfied with your setup, Publish your changes live.


Once all of your changes in Google Tag Manager are published, data for Client ID, Session ID, and Hit ID should start flowing into your Google Analytics Property. You can start reporting almost immediately by pulling data into Google Data Studio (example report below). This method works best with strong Event tracking, which, if you need a place to get started, check out my blog post on How to Setup Click Heatmap Tracking.

I hope you found this tutorial helpful. Consider following Patrick Strickler and CompassRed Data Labs to stay up to date on when we publish new content.

Source: https://medium.com/compassred-data-blog/ho...
AuthorPatrick Callahan