Featured Image - The Ultimate Guide to Personalise your Website

The Ultimate Guide on Personalising your Website for Free Using Google Tag Manager [Updated May ’18]

Good Marketing is all about creating a customer experience that’s relevant to a person’s intent. It’s the reason you turn to Amazon for one product, but end up buying 3. It’s why you love browsing your Netflix, and turn to Spotify to discover new tunes.

But you’re probably not working for Netflix, and don’t have a team of data scientists and programmers developing a recommendation engine. So where do you start creating an experience that’s relevant to your visitor’s intent? **Update May ’18 to include my slides about this topic**

Segmentation is standard in email marketing, even paid advertising like Facebook. But what about your website? Tons of data can be leveraged, even right from the first session (referral, campaign, landing page, location, screen size, operating system…).

But isn’t overwhelming? Where do you get started?

If you don’t want to spend over $1000 per month for solutions like Optimizely Pro or Yieldify or just want to test the waters with a free solution – you’re in the right place. I’ll show you exactly how to create a more personal user experience while in turn boosting your conversion rates.

And the best? You’ll be able to do it all for free, 100%! (your boss will love this)

happy boss

And I’ll even show you how you can measure exactly $$$ you’re making because of it (your boss will love this even more).

What I am going to show you in the complete guide, step-by-step, with no coding experience required:

  • How to show a different homepage to returning users based on their intent (Conversion boost for Truly +30%)
  • Change the headline on your landing pages based on the campaign or channel your visitors come from (landing page conversion rate +20-80%)
  • How to create intent-based pop ups on your blog to capture email addresses using Sumo.Me (increased our email captures +200%)

These are just example use cases – after reading this article, you will be able to use the same framework to personalise almost everything on your website.

There are 2 main parts in this guide:

PART 1: Setting up the Infrastructure: Tracking, User IDs & Split Groups
PART 2: Personalising your Website Based on your Visitor’s Intent

Looking for my slides from All Things Data 2018 Tel Aviv / MeasureCamp London? Here you go!

PART 1: Setting up the Infrastructure: Tracking, User IDs & Split Groups


GoogleTagManager (GTM): It’s the most versatile tool and does a lot more than just ‘managing tags’. In order to benefit from this guide, you’ll need to have GTM installed on your website.

Analytics tool: We’ll be using Google Analytics in this guide, but you can also use Mixpanel (my preferred tool to measure A/B tests),

That’s all that’s needed! Even though a little bit of brain might be helpful too 😉

2. THE BASICS – Assigning a unique ID to your visitor, and creating a split testing logic

Let’s get started with this. In order to create unique Unique User ID (UUID) with Google Tag manager, I am using Abhishek Tiwari’s code as a basis, which he published in this great article.

Firstly, we need to assign every visitor to our website a random unique user ID (UUID) and store this ID locally for the user. This will allow us to persist settings across different sessions.

The old way to do this would be to drop a cookie on the visitors computer. Cookies have been around since the inception of the web, and have become limited in terms of their functionality (for a great overview, check Simo Ahavara’s article here).

So let’s save some carbs and use a more modern solution: the Web Storage API.

Note: That means old browsers such as IE 7 & older won’t support this. But I wonder if people using such old browsers would even notice personalisation? I am fine to make this sacrifice (if you’re not, the same article from Simo explains a fallback method).

Assigning a UUID & create SplitGroups in Tag Manager

Firstly, head to Google Tag Manager and create a new Tag (HTML) and call it for example “UUID to DataLayer”.

Then paste in the following code use the following code based on Abhishek’s code:


Here’s how it should look like…

UUID to DataLayer
Create a UUID in Tag Manager and push it to the DataLayer

What does this code do?

  1. If the dataLayer can be accessed, the code will run. If not (e.g. older browsers), it won’t.
  2. Either A) If a user has no ID assigned or B) the user already had a UUID

(A) If a user has no ID assigned (i.e. = null)

  • The script runs & generates a random ID based on some rules
  • It then saves this ID in the localStorage of the Web Storage API under ‘UUID’, in the persistent localStorage.

(B) If the user already had a UUID, the script takes the ID from the localStorage

  1. The UUID and splitGroup will then be pushed into the DataLayer

Next, we need to define a trigger for this code. We want to assign this UUID for every page view – the script will handle the condition whether it’s a new or existing user.

Page View Trigger
Use the Standard ‘Page View’ Trigger to fire this tag


Activate the Preview mode – you should see this:

Head to your website and…

Using Chrome and Firefox, right-click and select ‘Inspect’ (Chrome) or ‘Inspect Element’ (Firefox). Then click on ‘console’.

Enter ‘localStorage.getItem(“UUID”)’ in the console, press enter. You should see your UUID!

Yay! 😄

So what’s next? Well, I promised you we’d be able to measure the success of your personalisation activity easily, which we can do by splitting the traffic. How do you do that?

Firstly, we need to segment our visitors in different randomly assigned groups (e.g. A/B).

Well, we just created a UUID with random numbers, so let’s go ahead and use that. We only need to amend the tag we just created slightly.

We’ll be assigning our users to 10 different segments simply by using the first digit of their UUID, which can be a number between 0 and 9.

This javascript does the trick:

And in order to make it easily accessible, we’ll also push this number to the dataLayer:

And here’s the final code:


Wasn’t so hard right?

In order to make this work, we also need to create the variable ‘splitGroup’ in our dataLayer.

GTM makes it quite easy – just go to “Variables” and add a new DataLayer Variable with the name “splitGroup”:

Let’s try this out: Preview the container and go to the browser of your choice. In the console, type in:

“dataLayer”. Press enter.

You will now see everything that’s in your dataLayer (probably a lot more than I’ve got in this example):

You can see that the splitGroup is set correctly. Given it’s position in the array, you can also get the value directly by typing in:

“2” because it’s the 3rd item in the array (count starts at 0).


Well, it’s not completely done. 😅

Didn’t I promise that you could prove to your boss the impact of all of this?

Yes, and here’s how we do it!

Measuring Results in Google Analytics

In order to measure any personalisation in your Google Analytics, we need to do a few more things. The aim is to have a custom dimension that allows you to look how your customers have performed depending what variation of your site they’ve looked at.

First, we need to create a custom dimension in your Google Analytics.

To do so, log in to your Google Analytics, go to ‘Admin’ and find the ‘Custom Definitions’ section under the property menu.

GA - Custom Dimensions

From there, select ‘Custom Dimensions’ and click to add a new dimension.

Create one Dimension for splitGroup, and (optionally) another one for the UUID of the user.

GA - Custom Dimension - SplitGroup

You should end up with something like this:

GA - Custom Dimension 3

Now the most important thing here are the ‘Index’ IDs for each of your dimensions. Note them down!

Next, we’ll head to Google Tag Manager. Go to your Google Analytics Settings Variable (Note: You’ll only have that if you trigger Google Analytics through Tag Manager, which I strongly recommend).

Edit the variable and scroll down to ‘More Settings’, where you can add the 2 Custom Dimensions we’ve just defined and connect them to the variables we’ve created earlier.

GA - Custom Dimension 4 - GTM Settings

Hit save!

Does it work? Try it out by checking your Google Tag Manager Preview / Debug tool, select the “Window Loaded” Event and then find your Google Analytics settings variable.
You can see below that we’re passing on the two variables for splitGroup & UUID.

GA - Custom Dimension 5 - GTM Settings

And in Google Analytics, you can segment traffic by this dimension:

Now we’re all set with our foundations. Let’s have some fun!

Arnold having fun

PART 2: Personalising your Website

Now that we’ve set up the foundation, let’s bring it to action.

What I am going to show you:

  • How to show a different homepage to returning users based on their initial landing page (boosted my conversion 20%)
  • Change the headline on your landing pages based on the campaign or channel your visitors come from
  • How to create intent-based pop ups on your blog to capture email addresses using Sumo.Me (increased our email captures +200%)

(1) Personalising your Homepage for Visitors based on their Initial Landing Page

Let’s start by personalising our homepage for returning visitors based on their previous intent. I’ll break it down in 3 simple steps:

  1. Create a list of different intent categories, and map these to landing pages
  2. Capture the intent of a visitor based on their landing page and save it in their localStorage
  3. Change the homepage hero image and messaging for the returning visitor

Let’s start by defining what different intents your visitors could have. We’ll be using growth-consultant.com as an example.
Let’s say my visitors are interested in either of the following:

  1. Help with growth strategy
  2. Help with marketing personalisation
  3. Help with their Facebook advertising

For each of these intents, I’ve set up three landing pages which I am sending traffic to from different channels, e.g. Organically, with Facebook Ads and Google Adwords:

  • Growth Strategy: growth-consultant.com/growth-strategy
  • Marketing Personalisation: growth-consultant.com/marketing-personalisation
  • Facebook Ads: growth-consultant.com/Facebook-ads

So far so good.

Now for your website, it might be a little more complicated! You may have hundreds of different pages, and mapping each will be difficult. Thank god, Google just released a new feature in Google Tag Manager which makes this a lot easier – it’s called RegEx tables.

Essentially we can use this to segment all of your pages based on characters the URL contains.

What? 🤓

Back to my initial example, assuming I’ve got the following pages:

  • growth-consultant.com/growth-strategy/overview
  • growth-consultant.com/growth-strategy/my-approach
  • growth-consultant.com/marketing-personalisation
  • growth-consultant.com/blog/ultimate-guide-to-personalise
  • growth-consultant.com/personalisation/case-study
  • growth-consultant.com/Facebook-ads

Now we need to assign the above pages to the intent groups I’ve defined above.

My rules are pretty simple:

  1. If page URL contains ‘strategy’ => intent is ‘growth-strategy’
  2. If page URL contains ‘personalis’ => intent is ‘personalisation’
  3. If page URL contains ‘facebook’ => intent is ‘facebook-ads’

We’ll now need to translate this into RegEx. I won’t go into detail here, but if you want to learn more about RegEx, here’s a great guide by Ryan to help you get started.

Fortunately, in this case it’s really simple 🤗

Let’s put this into tag manager, here’s how it looks like:

RegEx Table in Tag Manager

Important: Switch off the ‘Full Matches Only’ advanced setting AND ‘Enable Capture Groups and Replace Functionality’.

For more information about these settings, consider Simo’s article on the topic, which goes a lot more into detail.

Also, if you can’t find the input variable {{Landingpage}} yet, don’t despair. We’ll work on this next.

But first, we need to create a logic to set the landing page as a variable in the localStorage when the user lands on your website for the first time.

We’ll use a custom script for that. Here’s the code:

(Thanks Ben for simplifying this massively!)

This script sets the landing page path and the date the landing page was set, but only if a) it was not set before or b) it was set longer than 14 days ago. So in other words, we’re keeping the intent locked in for a period of 14 days – this of course can be amended.

Just paste this into Google Tag Manager and save it under something like ‘Landingpage to LocalStorage’.

Landing Page to LocalStorage

We’re getting there, just a little step to make this landing page available in tag manager – we’re just creating a variable called ‘Landing Page’. This is one pretty simple – we just pull this information from the localStorage:

Create this variable as a custom Javascript and we’re good to go:

Javascript Variable for LandingPage


So, does it work? You bet!

In Tag manager, enable the Preview mode for workspace you created the tags & variables in, and head to your website using any of the landing pages you’ve mapped in your table.

You should see the debugger loading with the page. First, check if the necessary tags have been fired, and then head to the ‘variables’ section. Make sure you select ‘Page View’ on the left, as this would be the time when the variables were set:

Google Tag Manager Preview

Check the variables ‘Intent Table’ and ‘Landingpage’. Here’s mine:

Google Tag Manager Preview - Variables
Et voila, my intent was mapped to ‘personalisation’! 😎

Now finally, let’s bring this to use – we need some personalised content! I’ll use a simple example here, but this can be applied practically everything on your website.

In order for this to work, we’ll be using a technology called jQuery, which is a JavaScript library. As the jQuery Foundation puts it: The most basic concept of jQuery is to “select some elements and do something with them.”

In order to use it for our use case, you don’t need to be jQuery pro, but having a little bit of HTML and Javascript knowledge certainly will make your life easier. But if you don’t have that, don’t worry, I’ll explain the basic bits.

(1) Selecting the elements we want to change

The first step is to select the elements on our site we’d like to change in order to personalise them. This could be the main headline of your website for example, or it could be the hero image or anything else, really!

How do we do that?

Let me explain this using an example: Asos.com.

We’d like to change the main headline of the homepage “THIS IS ASOS” to “UNIQUE FASHION FOR HER”, because we’d like to be more relevant to visitors who you know have an intent to buy women’s clothes.

Asos Homepage
Source: Asos.com

How do we select this element?

Right-click on the headline, and click on ‘Inspect’ (Chrome) or ‘Inspect Element’ (Firefox, Safari).

You’ll see the code of this particular element highlighted. Now right-click on that code, go to ‘Copy’ and ’Selector’ (Chrome) / ’CSS Selector’ (Firefox). In Safari, just right-click and click on ‘Copy Selector Path’.

Grab the Element Selector

That’s all we need for now! 👍

(2) Change it to something else

We’ve already decided we want to change this headline to: ASOS – UNIQUE FASHION FOR HER.

So how does the jQuery look like?

The general structure is like that: jQuery(“WHAT WE ARE SELECTING”).WHAT-IS-IT(“WHAT WE’RE CHANGING IT TO”);

So for our ASOS example, this is code:

How can you test it works?

Head to the “console” tab (after you clicked ‘Inspect’ / ‘Inspect Element’).

Type in “jQuery” and hit Enter.

If you get an error like “Uncaught ReferenceError: jQuery is not defined”, just paste the following code into the console (thanks to Naftuli for this nifty code):

Ok, jQuery is now ready for us to inject code. Let’s paste in the line of code from above:



Asos Personalised Homepage Hero


Let’s circle back – here’s what I’d like to do on my blog, and I’ll show you the full code that you can use on your site as well.

I’d like to change my blog sub headline “Digital Marketing & Growth advice. No bs, just useful stuff!” depending on the users’ intent.

Growth Consultant - Subheadline

  • For people with the ‘Facebook’ intent, I want to show them this alternative sub-headline: “Digital Marketing Growth advice, with a focus on Facebook Advertising. No bs, just useful stuff.”
  • Growth Strategy: Digital Marketing Growth advice, with a focus on Growth Strategy. No bs, just useful stuff.
  • Personalisation: Digital Marketing Growth advice, with a focus on Marketing Personalisation. No bs, just useful stuff.

You get the gist! The element selector for this sub headline is: #masthead > div > p.site-description

So my jQuery reads:

And it works..

Growth Consultant - Personalised

Simple, right?

Let’s bring it all together. We need a script (a tag in GTM) to run the right jQuery depending on the user’s intent. We’re already saving that intent as the output of the ‘Intent Table’ (the RegEx table), so we just need to run a bit of ‘if this, then that’:

The script contains the variable (intent) which references our RegEx table. Then there are 3 ‘IF’ conditions, and if they are true, the jQuery gets executed.

Let’s create this in Tag Manager:

Change Blog Subheader in Tag Manager

You can see that the ‘firing trigger’ is not a normal page view, but the ‘DOM Ready’, which stands for ‘document ready’.

Basically, we need to make sure the elements we want to replace or manipulate have actually loaded. You can create this trigger very easily:

Create a DOM Ready PageView

Save it, and preview. Congrats, you’ve made it! 😃

Note: If you’ve got different copy (or images) on your mobile site, then you need to create a separate tag for that. Just make sure you execute only one of them by creating a trigger for ‘On Mobile’ / ’On Desktop’ as ’Firing Triggers’.


Want to measure how this is affecting your conversion?

We need to add a bit of code that actually only applies this change to users who fall into our “test” group (and not in the “control”).

For that, we first need to decide what percentage of traffic we’d like to expose to the test variation.

Let’s assume we’d like to expose 50% of our visitors, while 50% don’t see the personalisation (our control group).

The splitGroup variable can be any number between 0 and 9. So to expose 50%, we’ll want to show this to anyone who’s in groups 0-4.

Let’s add this little javascript condition to our code:

Cool, push it out and see if it works. Obviously, check what splitGroup you’re in if your preview isn’t showing 😃

What’s next?

  • How to show a different homepage to returning users based on their initial landing page (boosted my conversion 20%)
  • Change the headline on your landing pages based on the campaign or channel your visitors come from
  • How to create intent-based pop ups on your blog to capture email addresses using Sumo.Me (increased our email captures +200%)

(2) Change the headline on your landing pages based on the campaign or channel your visitors come from

It’s a classic feature of popular services like Unbounce – Dynamic Keyword insertion. It’s not hard to build for free though!

We just need to apply the learnings from the homepage personalisation: changing content based on a variable, using jQuery to replace values.

I will go a little less in depth here, but please don’t hesitate to ask any questions in the comments if you’d like to know more!

(1) Create a new variable that captures your customers’ campaign.

I am assuming you’re using UTM parameters here, but really any parameters will work.

Since the visitors to your site will be arriving via a URL that has UTM parameters, we’ll use GTM to capture the UTM parameter as a variable.

Just head to to the Variables section of your GTM account and create a new variable, e.g. utm_campaign (you can do this for utm_source, utm_medium and utm_content in the same way).
Choose URL as your Variable Type, Query as your Component Type, and type in utm_campaign as your Query Key.

The configuration should look like this.

Variable for UTM Campaign in GTM

(2) Create a RegEx table with the different campaigns you’re using, and what value you’d like to assign to them (e.g. the ‘intent’ behind it)

Same principle as before – we’ll be using a RegEx Lookup table to match campaign names with our intent segments.

UTM Intent Lookup Table

(3) Define what change you’d like to make on your page(s) using jQuery

Woop, that’s it!

What’s next?

  • How to show a different homepage to returning users based on their initial landing page (boosted my conversion 20%)
  • Change the headline on your landing pages based on the campaign or channel your visitors come from
  • How to create intent-based pop ups on your blog to capture email addresses using Sumo.Me (increased our email captures +200%)

(3) How to create intent-based pop ups on your blog to capture email addresses using Sumo.Me

I’d like to touch on one example featuring Sumo.Me. For this one, you’ll need the premium version of Sumo. If you’d like to do it on the cheap, don’t despair though – you can also create these in tag manager – check this great article from Marthijn.

A cool and underused feature of Sumo.Me is using “javascript variables” for targeting.

Sumo Javascript Targeting

Well, the nice thing is that we can actually access dataLayer variables directly via javascript!

Wait, what?

Yap – we can just access our previously defined data layer variables within Sumo, and then show different popups, welcome mats etc. based on the intent or the splitGroup of the visitor. 😃

Even if you don’t want to do anything glamorous, there’s a very practical reason: You might want to know how these popups are affecting things like bounce rate, or even conversion rate. Let’s run an A/B test, shall we?

Here’s how it works…

(1) Set up a campaign in Sumo as usual

(2) Define you targeting conditions as usual

(3) Find out where in your dataLayer array the splitGroup variable sits

  • Open your Console, type in ‘dataLayer’. You should see something like this:

DataLayer Array

In my example, splitGroup is in array position ‘3’. So in order to retrieve the value, we just need to query for dataLayer[3].splitGroup. Try it yourself – just paste your value into the Console:

DataLayer splitGroup Array

(4) Define when to show

Select a ‘No Show Rule’, and choose ‘Other’, and “Javascript”. Assuming you’d like to run a 50/50 split test, you can set it as follows: “dataLayer[NUMBER].splitGroup” IS GREATER THAN “4”.

splitGroup Sumo

(3) Save it, and test it out!

You can now segment your sessions by splitGroups, and measure (in Google Analytics) if & how it affects your KPIs. Obviously, this can be used of a whole range of other things!

winning gif

Sweet right?

Alright – these are just some simple use cases. There’s a lot more you can do – and it’s your turn now!

Let me know how you’ve used this guide to create your own personalisations and what results you’ve achieved with this: leave a comment, tweet me at @joradig or drop me a line on LinkedIn. It really keeps me going and motivated.

Btw, did you see you can download most of the tags, triggers and variables I’ve described in this guide in one Google Tag Manager Container file? Yap, it’s all wrapped up nicely for you. Just click below and leave your email address. Don’t worry, I won’t send you any spam. 🤞


Liked it? Click to rate!
[Total: 0 Average: 0]

Published by


Hi, I am Johannes! 🚀Digital Nomad, Former Head of Growth @Truly (trulyexperiences.com), Former PayPal Global SEO lead & Paid Media marketer, 500 Startups mentor & growth consultant. In my spare time, I love 🚴‍♂️, ✈️🌏🗺,🎾. Get in touch: via Email or Tweet @joradig.

12 thoughts on “The Ultimate Guide on Personalising your Website for Free Using Google Tag Manager [Updated May ’18]”

  1. Hey Johannes – fantastic walkthrough! Thoroughly enjoyed it.

    However, I can’t see any of the images – I think there’s a problem with you SSL certificate which is preventing your images to be loaded…

  2. Awesome walkthrough article and some great concepts. Playing with the container you shared in GTM now. I really like how the UUID allows for pseudonymous personalisation through local storage without pushing user data to a third party server. Targeted marketing without creating vendor lock-in or sacrificing user privacy/choice. A solution built for the GDPR era!

    One thing you might want to do for future shareables is set the domain where it needs to be changed (i.e. YOUR-DOMAIN.com) as a variable so people can just switch it up in there rather than hunt it down in individual tags. It will also for more complex usage too.

    1. Thanks Daniel! Thanks for the suggestion to set the Domain as a separate variable, you’re right – it should make the container even more user friendly. Will include this in my next revision.

      Let me know if/how you ended up using it on your site!


  3. Great tutorial…

    Are there any solutions for sub domain local storage, we have multiple sub domains and creating multiple UUID’s for each sub domain for a single user doesn’t make sense for us.

    A single UUID for all sub domains for a single user would be great

Leave a Reply

Your email address will not be published. Required fields are marked *

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