Hotjar User ID tracking in Google Analytics with Google Tag Manager

Hotjar Recordings Dashboard

Updated 14th of May 2019.

This is the 3rd time I write about tracking Hotjar User ID in Google Analytics using Google Tag Manager. Hotjar have had a history of changing how to access the User ID, and that is why this is the 3rd time I write about the subject.

The advantage of tracking the Hotjar User ID in Google Analytics, is that you now can use Google Analytics to identify behavior that Hotjar can help you answer.

The first thing you should do if you haven’t done it yet is to head over to Hotjar, and create an account.

Google Analytics setup

Head over to Google Analytics and create a Custom Dimension with Scope set to Session. The S: as I use in the Dimension name, simply means that this is a Dimension with the Scope set to Session.

Google Analytics Hotjar Dimension

Google Tag Manager Setup

We are going to create X Variables, Y Tags and W Triggers.

We are also going to store the Hotjar User ID in a Session Cookie. I’m using the Cookie Setting method from Simo, so you need to create that setup in addition to what I describe in this post.

Google Tag Manager Variables

NoVariable NameVariable TypeBuilt in / Custom
1Container IDContainer IDBuilt in
3Hotjar - timerEventNumberData Layer VariableCustom
4Hotjar - timerLimitCustom JavascriptCustom
5Hotjar - UserIdCustom JavascriptCustom
6Hotjar - UserId - Cookie1st Party CookieCustom

We need to activate the Container ID and HTML ID variable, and create 4 different GTM Variables.

Container ID and HTML ID Variables

Built-In Utilities Variables - Google Tag ManagerThe method we are going to use to trigger these tags are somewhat special, we are going to use Tag Sequencing with a Custom HTML Tag, and because of that you need to activate the Container ID variable and the HTML ID variable.

If you aren’t familiar with Tag Sequencing, I recommend that you read Understanding Tag Sequencing In Google Tag Manager by Simo Ahava.

Variable 1: Getting the Hotjar userId from Hotjar

The Hotjar userId contains a value similar to this: 41d7c48b-8689-42dd-9a79-83690993f2ee. Create a Custom Javascript Variable, and add the code below. This code will grab the first part of the Hotjar userId (41d7c48b), which is the User ID you find in Hotjar. We will later save this ID to a Session Cookie.

Name the Variable Hotjar UserId.

This code have been changed several times. I credit Alex Asigno (see comment field) for this version.

Variable 2: Getting the Hotjar User ID from the Session Cookie

Create a 1st Party Cookie Variable, and add hotjarId as the Cookie Name. This variable will grab our modified Hotjar User ID that we have stored as a Session Cookie.

Name the Variable Hotjar UserId – Cookie.

Hotjar UserId Cookie GTM Variable

Variable 3: Hotjar – timerEventNumber

This is a “nice to know” variable for our tracking. We are going to use a Timer trigger for our Hotjar User ID tracking, and the timerEventNumber will tell us how many times the Timer has to “ping” Hotjar before we get the Hotjar userId.

Create a Data Layer Variable, name the Variable for timerEventNumber. In the field Data Layer Variable Name, add gtm.timerEventNumber as the value.

Hotjar - GTM - timerEventNumber Variable

Variable 4: Hotjar – timerLimit

A Timer Trigger can be limited. We are going to “ping” for the Hotjar ID up to 6 times. However, if the Hotjar UserId already exists in the hotjarId cookie, we will not run the trigger. This is done by setting the timerLimit to 0.

Create a Custom Javascript Variable, and add the code below, and call the variable for Hotjar – timerLimit.

Variable 5: Page Hostname – Strip www LowerCase

I use this variable for setting the cookie on the domain.

Page Hostname - Strip www Lowercase - GTM Variable

Google Tag Manager Trigger

We need to create a Timer Trigger for our tracking. This Trigger will check if the Hotjar userId is avilable, it will store the modified Hotjar UserId from the variable Hotjar UserId to a Session Cookie, and then the ID will be tracked in Google Analytics.

Name the Trigger Hotjar – Timer.

Hotjar - GTM Timer Trigger

Interval setting

This is the number of milliseconds between firing events. I have set the timer to check for the Hotjar userId every 2 seconds (2000 milliseconds).

Limit setting

This is the maximum number of times to fire the event. Insert the Hotjar – timerLimit Variable here.

Enable This trigger setting

This setting tells the Timer when it should be triggered. The condition checks if our modified Hotjar UserId is stored in the Session Cookie. If it exist, the Trigger will NOT be enabled.

Fire On setting

The setting is the same as above. If the Hotjar UserId is found in the Session Cookie, the Timer will not fire.

Google Tag Manager Tags

We need to create 2 different GTM Tags.

  1. 1 Custom HTML Tag for storing the Hotjar User ID to a Session Cookie.
  2. 1 Google Analytics Tag for tracking the ID from the Session Cookie.

Tag 1: Google Analytics Event tracking of Hotjar User ID

This is the Tag that is going to track the Hotjar UserId to Google Analytics. Create a Google Analytics Event Tag with the Non-Interaction Hit set to True.

Hotjar Google Analytics Event Tag

In the Label field, add the Variable {{Hotjar UserId – Cookie}}.

In the Value field, add the Variable {{Hotjar – timerEventNumber}}.

You should also add the Variable {{Hotjar UserId – Cookie}} as a Dimension to your Google Analytics Settings Variable. I have only added the dimension directly to this tag for demonstration purposes. Note that I also use a Variable for the Dimension Index Number.

Do NOT add any Triggers to the Tag. Our tag “Hotjar – Store UserId to Cookie” will trigger this tag as a Cleanup Tag. The screenshot below only shows how things will look when we are finished with our setup.

Hotjar Google Analytics Event Tag Trigger Setting

Tag 2: Hotjar – Store UserId to Cookie

Create a Custom HTML Tag and name it Hotjar – Store UserId to Cookie. The code is using the Cookie Setting method from Simo. He has also described the method in another blog post as well.

Hotjar - Store UserId to Cookie - Advanced Setting - GTM TagThe image shows settings for this Tag. As you can see we are using Tag Sequencing, and the Trigger is the previous made Hotjar – Timer Trigger. Here is the explanation of what’s going on:

  • The Timer Trigger will every 2 seconds check if the variable Hotjar User ID contains a Hotjar userId, unless our modified User ID is already stored in a Session Cookie.
    • If Hotjar User ID is undefined, this tag fails and further sequences are aborted. Then new attempts will be done every 2 second until it has a userId, or 6 attempts have been done.
  • If it’s not undefined, our modified Hotjar User ID is stored to a Session Cookie.
    • In addition, this will trigger our GA – Event – Hotjar tag as a Cleanup Tag.
    • The GA – Event – Hotjar tag will track our modified Hotjar User ID from the Session Cookie.

If you haven’t done it already, head over to Hotjar, create an account, set up the tracking described in this blog post, and use Google Analytics to identify behavior that Hotjar can help you answer.

Some final words

The content of this blog post was updated 14th of May 2019, so if you have visited this blog post before, some of the content and solutions are different. For example, I used to save the Hotjar ID to Local Storage instead of saving it to a Session Cookie.

I have deleted some comments that are no longer relevant.

39 Comments on "Hotjar User ID tracking in Google Analytics with Google Tag Manager"

  1. Very useful, thanks Savio!

    Those copying / pasting names of variable/trigger/container names might run into an issue when previewing the tag in the last step “Tag 2: Store Hotjar User ID to Local Storage” because “{{Hotjar User ID – Get}}” uses a hyphen, while the earlier steps formatted itself to a dash.

  2. Loryn Thompson | June 14, 2016 at 4:33 pm | Reply

    Hey Eivind, thanks so much for putting this together! It’s always best to link your analytics tools together whenever possible 🙂

    I’m curious, though — could I achieve the same (or similar) result by pushing the Hotjar ID to the data layer, setting up a data layer variable, and adding it as a custom dimension on a pageview, making sure that the Hotjar tag fires before the pageview tag? Just wanted to avoid adding an extra event to my setup, if possible, or at least understand why it wouldn’t work for my own edification 🙂

    Also, do you know if the Hotjar ID is set for every user that visits a page with the Hotjar code, or only if the user has data saved to Hotjar (poll, recording, etc.)?

    Thanks for your help!

    • Eivind Savio | June 16, 2016 at 9:18 pm | Reply

      Hi Loryn

      Unfortunately you get access to the Hotjar ID a long time after the pageview tag has fired. You will not be able to grab the ID on DOM Ready, but you may be able to grab the ID on Window Load (and you wouldn’t track pageviews on Window Load).

      You could however use my “timer method” and set the Hotjar ID into Local Storage (or a cookie), and on the next pageview you will be able to grab the ID from Local Storage or the cookie, and send it to a dimension. This method means that you will not be able to track Hotjar ID for “bounces”, only for users with more than 1 pageview.

      Is the Hotjar ID set for every user…?
      I haven’t studied this in detail, but some quick tests indicates that the Hotjar ID is only set when a user has data saved to Hotjar (poll, recording, heatmap).


  3. Hi Eivind,

    first of all, great idea and find!
    I’ve integrated this as a test in Google Analytics and see the first ID’s dripping in.
    The only difference I made is set the custom dimension to ‘Hit’ level as this is an ID tied to a user (due to privacy concerns).
    I understand choosing the ‘session’ level but that might mean you could get stuck on the login/logged-out user (if you only use the hotjar ID for user ID tracking, which I’m doing in this test).

    Do you have any idea what triggers the hotjar ID in particular?
    I’ve been testing the tracked hotjar ID’s and haven’t found them in Hotjar (yet? have you noticed a lag in hotjar?)


    • You will not be able to match all Hotjar ID’s vs. those collected in GA. However, I’m able to match most of them. Your Hotjar plan may also play a role here. I checked this today on a paid Hotjar account. I could find most Hotjar ID’s tracked in GA that I was interested in (and nailed down some checkout issues). 🙂

  4. I have been noodling on this for awhile. You make my day. There is rich information by matching up GA behavior with Hotjar’s recording. It will provide much better analysis for UX and CRO issues. Thank you very much 🙂

  5. Hi, The only thing I found with this is that if the value within {{Hotjar User ID – Local Storage}} already exists, then the GA tag will not trigger.

    You could trigger the GA tag on any event based on {{Hotjar User ID – Local Storage}} ‘does not equal’ ‘undefined’, and have the tag only fire once per page.

    • That’s correct, and I have done that on purpose. Why have the tag to fire on every page, you just need to store the Hotjar User ID once. Reading the Hotjar User ID can be done with your other tags as I mention at the bottom of this post.

  6. Excellent post and a great intro to Google Tag Manager timers!

  7. Not sure if the API (undocumented?) has changed…but get is not a function:‘userId’);
    Uncaught TypeError: is not a function(…)

    This is the case for two separate sites using different HotJar accounts. I can’t find any documentation on how to get the userId.

    The HotJar library loading is:

  8. I implemented this solution and it was working perfectly up till yesterday (15.11.2016), but then GA stopped receiving data. We haven’t done any changes to GTM or GA implementations. I run multiple tests, but I couldn’t get my GA tags to execute as I would expect them to. HotJar reports (e.g. recordings) work fine. Has anyone experienced anything similar? Could it be a change on the Hotjar system side?

  9. Same problem here, Hotjar changed a tracking code.

    It must be implemented via some fingerprinting technique – I tried to submit some questions in browser anonymous mode, all responses had the same user ID.
    Object window.hj has attribute fingerprinter, In requests there is a new field:
    fingerprint : “577611fd618ff89909bb047589a9fapf”

    I don’t know how to decode / encode user ID from this fingerprint.

  10. Thanks for this help Savio, but I’m also at the end of the road on this. I’ll be watching out for ay new on a solution of course

    Meanwhile does anyone know of any good survey/poll tool that does have a working method for populating a GU custom dimension with a UID?

    GA integration?

  11. I contacted Hotjar on this subject and it seems they “[…] recently made some changes to our tracking script and since these changes, the detailed userID extraction is not possible anymore. We are looking into a solution that is more stable for the future.”

    I do not understand why they removed it in the first place, but it is seriously impossible at the moment to link Hotjar session to your own data as they confirmend… Anybody experience with Inspectlet?

    If you guys need this as bad as I do, please vote up this ‘feature-request’:

  12. Rainer Kretzer | December 22, 2016 at 4:59 pm | Reply

    After trial and erroring throug the properties for a while, I have been successful with:‘userId’).

    • Nice find Rainer. Did try it on a couple of sites, and it works.

      Can I credit you somehow when I update this blog post? Ex. do you have a blog or something?


    • Wow, thanks a lot Rainer!

      • Rainer Kretzer | December 23, 2016 at 7:10 pm | Reply

        Hej Eivind,

        the way you mentioned me in your update is absolutely fine. I am grateful for your great tutorial and I am glad I was able to help out with a solution for the issues related to Hotjar’s recent API changes.

        Merry Christmas!

  13. Can anyone who already tried confirm me this also works on mobile devices? I know that, at least some while ago, there were problems when trying to save on the local storage on mobile (especially on iPhones, as far as I remember).

    Thank you,

    PS. Happy holidays and an exciting New Year everyone!

  14. I dont think even‘userId’) is working anymore. I think they are using the term key instead of UseriD

    I used“-“).shift() for this part

    • Rainer Kretzer | January 5, 2017 at 8:54 am | Reply

      I am currently successfully tracking userIDs with‘userId’), which do perfectly match the userIDs listed in Hotjar. “Key” contains a completely different value, which has not had any relation to the userIDs listed in Hotjar in my trials.

      • Followed the guide rigorously using the ‘userID’ method, with no joy.
        Should l be abel to see the UserID as a variable using GTM in preview mode?
        The timer runs for 6 iterations, but i still get undefined. Have increased to 6s intervals but still nothing.
        Bad question in know but can anyone give me any hints on what else to check?

        • Rainer Kretzer | January 6, 2017 at 9:41 pm | Reply

          I have initially encountered the same problem. Reading the first comment to this post I realized, that I did not name my variables consistently regarding declaration and usage in different places in GTM. Please check all your hyphens. I had some inconsistencies with them: some where simple minus-chars, others have been typographically correct hyphens, which are different characters and hence will result in inconsistent variable names.

  15. should clarify i mean using GTM preview mode once i have published the version live.

  16. Hi,

    I don’t understand, Where did you identfy this ” Hotjar UserID – D – Index ” ?


    • Eivind Savio | May 11, 2017 at 6:29 pm | Reply

      This is your Google Analytics Custom Dimension Index number.

      You could write the number directly into the GTM Custom Dimension Index column, but it’s better to use a GTM Variable for this.

  17. Hi there!

    Thank you for your instructions, very helpful 🙂 However, I do have a question – I followed the instructions and I am indeed getting the Hotjar User Ids as a second dimensions. Sometimes I get the User Id but when inserted into the search box in Hotjar, there are no recordings. Am I the only one getting this..?

  18. Hi Eivind,

    Thank you for this great post 🙂 I have been using it successfully but I notice that i still see Hotjar User ID’s coming in, even if I have no recordings/heatmpas whatsoever running. I have exactly did what you’ve written down. Do you have any idea as to why this might be the case?



  19. For new readers – the tracking was down but now it works again because id remains the same after page reload (at least 4 me), so this post is still relevant 🙂
    Altho you might want to check out the above comments where Savio mentioned another method (a better one), using session cookies.

  20. Anyone reading this will need to update the get variable with the following as Hotjar have updated their code.

    function() {
    return hj.globals.get(“userId”).split(“-“).shift();

  21. Hi Alex, interesting last comment, but GTM doesn’t like the script. Any ideas?

  22. What is the JS – setCookie variable?

  23. I’ve made a script based on this article. You can just create new session based custom dimension and paste this script into custom html tag with window load trigger:

    var hjCoockieName=’hotjarid’; //name for cookie mark
    var dimensionNumber=’3′; //prefered custom dimension number
    var gaTrackerName=’myTraker’; //your tracker name

    function setCookie(cname, cvalue, exhours) {
    var d = new Date();
    d.setTime(d.getTime() + (exhours*60*60*1000));
    var expires = “expires=”+ d.toUTCString();
    document.cookie = cname + “=” + cvalue + “;” + expires + “;path=/”;
    function getCookie(cname) {
    var name = cname + “=”;
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(‘;’);
    for(var i = 0; i 0)
    var dimension = ‘dimension’+dimensionNumber;
    ga(gaTrackerName+’send’, ‘event’, ‘setHotjarId’, document.location.pathname, {
    ‘nonInteraction’ : true,
    dimension : hj.globals.get(“userId”).split(“-“)[0]
    setCookie(hjCoockieName, ‘true’, 0.5);

    if (getCookie(hjCoockieName).length==0){
    setTimeout(check, 1000);

    It works perfect for me.
    Don’t forget to set tracker name in your GA settings variable in GTM.

  24. Hi Eivind, Thank you for the great write-up. What would be the end result of this? Would I be able to see Hotjar UserIDs in Google Analytics? Thanks!

  25. Hey
    Great post, but it seems that it is not working for me.
    Did Hotjar changed (again) how they are using their user id and cookie? or do I need to make some changes to make it work?

    Any advice will be appreciated


Leave a comment

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.