The Only Event Tracking Setup Guide You’ll Ever Need

Analytics is truly a case of garbage in, garbage out.

If you don’t have event tracking set up, you won’t know much about what your users are doing on your website or mobile app. That means you’ll really struggle to make the kinds of decisions that can grow your business.

If you can’t trust your tracking setup, you can’t trust your data. If you can’t trust your data, you can’t make decisions – or worse, you’ll make the wrong decisions.

Despite its importance, I’ve yet to find a business that has a perfect tracking setup.

Sometimes they know their tracking is broken, sometimes they aren’t aware of the limitations of their tools, and sometimes the data they’re measuring is just plain wrong. Most typically though, they just aren’t tracking enough events to see anything useful.

Why? It’s complicated.

Analytics tools were traditionally used by statisticians or developers. Many of the platforms are not too far removed from writing code yourself. Some of the more advanced platforms, like Mode Analytics, actually do require you to write code.

When you’re a non-technical user, finding the data you need is just too hard. Even if you’re lucky enough to have an analyst on your team or in your company, it’s like going to a car mechanic and trying to imitate that noise you heard your car making.

Analytics is like a foreign language and you don’t even know the right way to ask for what you need.

It definitely doesn’t help that as B2B software sold primarily to the numerically gifted, well, I guess it’s no surprise that the platforms tend to look ugly.

urchin tracking

Urchin Tracking Software – the precursor to Google Analytics.

Like anything else that’s ugly and complicated, it gets ignored or pushed to the end of the list.

But you can’t do that. Analytics is too important.

Here are some real-world examples where analytics has helped me grow one of the 70+ businesses I’ve worked with:

  • Cut AdWords budget by 20% without affecting revenue after finding over 1,000 keywords that had never driven a sale.
  • Proved that the CEO writing blog content was not profitable for user acquisition, even assuming he earned minimum wage (he didn’t).
  • Scaled Facebook Ads budget to $2m a year after discovering that, despite being lower quality overall, the significantly lower cost made it ROI-positive.
  • Found over 70 affiliate sites that had given us links to broken product pages – a poor user experience and thousands of dollars in lost commission.
  • Switched to pushing product demos rather than free trials after finding subsequent product engagement justified the cost of running the demos.

I couldn’t have done any of the above without a solid analytics tracking setup. Data is the lifeblood of any business that wants to grow.

So, good news: I’m here to uncomplicate it for you.

When I co-founded a marketing agency, I knew tracking would be a big issue. I just wasn’t prepared for how big an issue it would be.

Looking at 2 years of data, I noticed that 100% of the clients that churned had issues with tracking the effectiveness of our campaigns. Meanwhile, our longest-standing relationships were with clients for whom we nailed tracking early on.

Fixing our tracking setup process was mission critical.

To try and address it, we had to hire a freelancer for 10 hours a week purely to focus on debugging tracking implementation issues. Even so, it still takes each Ladder strategist approximately 10-20 hours of research and testing to get everything working for a client, and another 1-2 hours a month debugging random new issues that come up.

“It shouldn’t be this difficult,” I told myself. “There are lots of smart people writing blog posts about how to solve the very problems we have.”

Yet despite all our research, our strategists were still running into issues.

When I dove into the material myself, reading all the best guides, documentation, blog posts, and answers out there, I realized what the problem was:

Every guru had their own ‘style’ of setting things up.

Because we were all using different sources of information, we ended up with a fragmented mess of hacky solutions, all with their own unique problems and edge cases.

I came to the realization that if we defined our own style of best practice, most of the problems we were running into just wouldn’t appear in the first place. Or when we did run into a problem, we’d at least be able to document it, share it, and solve it more easily, so long as we were all working off the same standard setup.

Because we’d only need to document the best way to do something, not every possible way to do it, our guide would be cleaner, simpler and easier to understand than anything else out there.

Well we built that guide…

…and it has quickly become the most invaluable resource we have.

You’re reading it right now.

We’re sharing it with you because we know how frustrating event tracking can be.

Our tracking problems would have been so much more painful without all the amazing free resources there out there. So it’s only fair that we reciprocate and release our own version.

We want this to truly be the only guide that you’ll ever need, so if you notice any popular use case we’re missing, Tweet at me. We’ll add each Tweet to the bottom of the post with our answer so everyone can benefit.

Table of Contents:

Download a free PDF version of our Event Tracking Setup Guide!

⇒ Download Event Tracking Setup Guide ⇐

Event Tracking Guide

Return to Index

In this guide you’ll learn how to write your own tracking implementation plan; yes actually write the code and instructions that you can pass on to your developer to implement or even implement yourself.

I’ll start with the basics – what to track and why. If you’re a more advanced analyst who already knows this stuff, feel free to skip straight to the code implementation.

Everything is an Event

Back in the old days of the web, if the user wanted to do something, anything at all, they had to load a new web page. Adding a product to your shopping cart? New web page. Purchasing a product? New web page. Signing up to an email list? New web page.

All of the analytics providers that grew up in this era, were built on this premise; they recorded ‘pageviews’. To see how many purchases or email signups they got, they’d just simply check how many people visited the page that came after those actions, the ‘confirmation page’.

This no longer works for most businesses.

You can add a product to cart on without going to the cart confirmation page. You can sign up to a newsletter on the Men’s Health without redirecting too. Sites with Stripe integration even allow you to pay for goods without reloading the page. And on mobile it’s a whole different story: mobile-first analytics platforms like Mixpanel don’t even record pageviews, they record ‘events’.

So what is an event?

It’s really just any interaction that occurs on a website or mobile app, triggered by something the user does. So as well as adding to cart, buying product or signing up to the newsletter, it can also include a whole host of things like sharing the page on social media, filling in a form field, clicking a button or commenting on a post; even pageviews themselves are events!

There are three major advantages with events vs pageviews:

  • We don’t have to load a new ‘confirmation’ page every time the user does something
  • We can track more advanced actions, like scrolling down to the bottom of a blog post
  • We can push additional attributes with events, like user-id, email and purchase amount

So what events should we track?

Your Marketing Funnel

If you haven’t read our post on Marketing Funnel Analysis, I recommend it at this point. Once you read it, you’ll know that successful analysis relies on the ability to segment your users. This can get very advanced, particularly for larger enterprises, however we only need to start with one segment: the stage in the buying cycle. For example, here’s a marketing funnel:

economic model

It’s simple enough; to build a model like this, you need to fire events for each of these funnel stages. Then you can track the number of people who reach each stage, work out the conversion rate between stages and then work backwards derive how much a user at each stage is worth to you.

It seems pretty basic, but 90% of businesses I talk to do not have a good model of their business like the one above. It’s absolutely essential to make any marketing decision confidently, so let’s walk through how to set this up.

Picking Funnel Stages

It’s easy to get carried away here. I get it, you want to track everything. My advice is to start with a minimum viable tracking solution first (i.e. the bare minimum to track your funnel), then build on that solid foundation over time as needed. Otherwise you risk spending hours of your time (and developers time) and getting a half-baked, over complicated solution, that your team will rarely look at.

Tracking is never a ‘one and done’ activity; it’s a process that will evolve over time as you grow and get more sophisticated.

So how do you decide what funnel stages to track?

Awareness isn’t possible to track (at least not in your analytics package) because it happens on other people’s sites. When you run ads you get an ‘impression’ and ‘reach’ count, and Google even gives you the numbers for SEO, but you should ignore it for the purposes of this guide.

Acquisition – this one is really easy; every analytics platform tracks the number of people who visit your site or app by default. No additional tracking required, though you may want to store additional variables / attributes regarding this user for more advanced segmentation (we’ll cover this later on).

Activation – this is the most important stage to get right. This is the first sign of intent from the user, and most marketing activity will be focused on driving people to this goal. This is most commonly collection of an email address or creation of an account, but can also be a view of a key page on the site (i.e. a product or pricing page).

Conversion – this can mean a lot of different things depending on your business, but this should only relate to the event where people actually pay you money, or you’ll get in trouble with this metric. If that event happens offline (for example a B2B business with a long sales cycle), there are ways to linking it back (which we’ll discuss later). If it doesn’t happen at all (i.e. you’re a startup that isn’t focused on revenue right now) I suggest you make a strong assumption to use as a placeholder.

Retention – for advertising based startups, this is easy; how many people come back and give you the opportunity to show ads? For B2B, also easy; it’s your upsell revenue minus the lost revenue from customers that churned. For e-commerce and other business models, this number might be very low. But it’s still important to measure so you can work out your lifetime value. For example printer companies actually lose money on the sale of the printer, but make it back when they sell you ink every few months. If they weren’t tracking retention they wouldn’t be able to afford their user acquisition costs. Depending on your product this may or may not be possible to track within analytics, but you do want to have a good estimate of this number.

Referral – this is probably the hardest metric to track. You’re probably getting a tonne more referrals than it’s possible to measure by conventional means. My best recommendation is focus on a tangible action (like sharing on social) and then make a best guess estimate of what that share is worth (based on how much traffic you get from social shares, and how much that traffic is worth to you). I’ll explain this more in detail later.

The important thing is that you only track events that are economically meaningful, and that precede each other. Meaning that if a user can skip a funnel stage, that stage shouldn’t be in your funnel (or should be combined with another action).

For example on AirBnB the main action on the home page is to search. However I can scroll down and click into one of their content pages, and choose a listing from there, without searching. Or maybe I came in from SEO directly to a destination page. If AirBnB included the ‘search’ action in their funnel, their numbers would be off; some users would book without searching, so the numbers would be skewed.

A better ‘activation’ metric for AirBnB would be creating an account, as you have to do that to make your first booking; you can’t skip that step, like you can search. Alternatively a view of a listing page could also work; this is particularly useful as it’s a more meaningful metric when looking at existing user engagement (who created an account maybe years ago).

Now I’m not saying AirBnB shouldn’t track searches; searches are a great indication someone is interested in the product, and it’s economically valuable. I’m just saying that it shouldn’t be the first thing they track, or part of the main funnel model they build. It’s likely they have separate funnel just for people who search, but that’s a level of complexity you won’t need at first.

Basic Concepts of Tracking

Return to Index

google analytics setup

When someone visits your website a snippet of JavaScript code on your website ‘fires’; sending that information to your analytics platform. That piece of code will look something like this:

<!-- Google Analytics -->



(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),



ga('create', 'UA-XXXXX-Y', 'auto');

ga('send', 'pageview');


<!-- End Google Analytics -->

You don’t need to know what that code does, you just have to copy and paste it into the ‘head’ section of your website. It has to go on every page of your site. If that sounds complicated, don’t worry – it isn’t. All modern websites are built using templates (which means the developer just has to copy and paste it once).

The important part is this bit:

ga('create', 'UA-XXXXX-Y', 'auto');

When you copy your code from within Google Analytics, you’ll have your own ID here; this is what tells Google that it’s your website that’s sending the information.

See this bit?:

ga('send', 'pageview');

That tells Google Analytics that someone viewed a page. Just this basic code gives you a lot of functionality. It allows you to segment your users by all the following variables:

  • Marketing channel
  • New vs returning visitor
  • Geo-location
  • Device
  • Landing page
  • Pages viewed
  • Time spent

All of that is recorded automatically by GA.

It also allows you to set up pageview-based goals; if your users land on a ‘confirmation’ page after purchasing, you can designate that page as a ‘goal’ and work out the conversion rate.

However, as we discussed at the beginning of this guide, not every important action happens on a specific ‘confirmation’ page. For that we need an event tag that fires after the head tag.

ga event tracking

Go to your website, take each important action a user would take on your site. Which ones didn’t drop you on a new page? To track those actions you need to add an event tag.

The code to track these events is below:

Event 1

ga('send', {

hitType: 'event',

eventCategory: 'videos',

eventAction: 'play',

eventLabel: 'fall campaign'


Event 2

ga('send', {

hitType: 'event',

eventCategory: 'checkout',

eventAction: 'complete',

eventLabel: 'blue sweater',

eventValue: 37


This first event, tells Google Analytics that someone played the fall campaign video. The second one tells you someone completed the checkout process, (i.e. made a purchase) and you made 37 bucks. So far, so good; you (or your developer) just need to add this code to the handful of events in your funnel stage, and you’re tracking your whole funnel in Google Analytics.

However life is never that simple.

What if you start advertising on Google Adwords and Facebook, and need to add their tracking code to your website? Google Adwords just needs the event tag, but Facebook needs the head and the event tag. Now your setup looks like this:

analytics advertising tracking

Ok, a little more complicated… but not too difficult so long as your developer set them all up correctly to fire at the same time, and doesn’t accidentally miss one off when making changes to that page…

So Facebook and Google Adwords are working well and you want to expand to Twitter and Bing ads

…and maybe Google Display Network

…plus your buddy told you to try Pinterest ads

…then a sales rep at Adroll sold you on retargeting but you want to test it versus Perfect Audience

…and you read in a blog post that SumoMe works to collect emails

…and you heard that Mixpanel was a better tool than Google analytics .

..but you’re also interested in collecting qualitative information with something like Hotjar or Qualaroo

…and you need to add Klaviyo code to your website for email retargeting.

Before you know it, you end up with this set up:

analytics tags

What are the chances that your developer set all this correctly? Will they all be firing off the same rules? How likely is it that they won’t miss one tag off accidentally next time they edit this page? How will firing all these tags slow down your page loading speed? Could one of these tags misfire and stop your page from loading?

All these problems only get worse as you grow and your marketing gets more sophisticated.

The solution? Tag Management.

google tag manager

Rather than hand code every single tag that you need, you only have to add the tag manager code once in the head, and fire the event tag once when something happens. Google Tag Manager will then send that information to all of the other tags that you need to send it to.

As well as making things easier for the developer, who now only has to remember one tag when they make changes to the page, it makes it easier for you too; you can now add new tags that fire off exactly the same rules as the other tags, and you can do it yourself, instantly, without a developer, product manager or product release in sight.

And it’s actually pretty easy.

The code for this is really similar to the code you need to set up Google Analytics:

<!-- Google Tag Manager -->

<noscript><iframe src="//"

height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>


new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],




<!-- End Google Tag Manager -->

The event code is similar as well:


'attribute1' : ‘value_for_attribute_1’,

'attribute2' : ‘vaue_for_attribute_2’,

'event' : 'event-name'


Note that the attributes part is fully customizable; we’re not limited to using eventAction, eventLabel, etc used in the Google Analytics tag (though it would help, if we’re planning to push this information into Google Analytics via Tag Manager).

To do that we’d do something like this:


'eventCategory' : value_for_Event_Category,

'eventAction' : value_for_Event_Action,

'eventLabel' : value_for_Event_Label,

'eventValue' : value_for_Event_Value,

'event' : 'EventName'


Then within Google Tag Manager we can set this up so that the values get passed into Google Analytics and any other tag that we need to set up.

There are a couple more cool features of Google Tag Manager we can explore:

  • Preview mode to see what’s firing and where
  • Roll back to previous versions that were working
  • Track button clicks without adding event code
  • Collect variables directly from the page
  • Conditional tag firing (fire this one THEN this one)

Ok, at this point, your head is probably exploding.

Bear with me, we’re just getting to the good part: a step-by-step guide of how to actually set up each popular tracking use case.

First I’m going to talk about naming conventions, then a little context on how tracking works on mobile, but feel free to skip these sections and come back to them later.

Naming Conventions

You can actually call your events and variables whatever you want. However please remember that this is a Garbage In, Garbage Out situation, just like we discussed with utm parameters. Misspellings and mistakes can’t be corrected afterwards; your data for that time period will be forever corrupted. If you don’t name your events in a useful way, you’ll struggle to see pull the right types of reports, you might miss data or overinflate it.

For example if you fire one signup event as:


'eventCategory' : ‘Registration’,

'eventAction' : ‘Complete’,

'eventLabel' : ‘Homepage form’,

'event' : 'RegistrationEvent'


And a different one as:


'eventCategory' : ‘Signup’,

'eventAction' : ‘Submit’,

'eventLabel' : ‘landing page’,

'event' : 'SignupEvent'


You’ll have to remember to include both ‘Submit’ and ‘Complete’ actions in your weekly signups report. You might have used ‘submit’ for your contact us form, which isn’t really a signup and would inflate your numbers. As your marketing gets more complex, and you have team members come and go, this knowledge (and therefore the data) can easily get lost.

Best practice is to use the same convention for the same (or similar actions). That way you can easily for example look in Google Analytics and pull a report of all similar actions aggregated. For example, selecting the ‘click’ eventAction and reporting on clicks by eventLabel. Or selecting the ‘variation 1’ eventLabel and seeing all the eventActions associated.

Internally at Ladder, we try to stick to this naming convention:

  • eventCategory – what is the purpose of measuring this event? To see the path towards new registrations? To measure how many leads we drove? eCommerce sales?
  • eventAction – what did the user just do? Click a button? Submit a form?
  • eventLabel – what form is this? If this is part of an A/B test, what variation?
  • eventValue – how much is this action worth? If we have a basic estimate at least we can more easily combine all ‘value’ generated across different conversion types together to see an aggregate of how our traffic is performing.
  • event – for this use the same name as the event category (capitalized) plus ‘Event’.

So for example:


'eventCategory' : ‘Registration’,

'eventAction' : ‘Submit’,

'eventLabel' : ‘Home-Var_A’,

'eventValue' : 10,

'event' : ‘RegistrationEvent’



In order to keep all my naming conventions consistent, and make sure I haven’t forgotten to track any key actions, I find it helpful to create what I call a ‘CRUDS map’.

CRUDS stands for Create, Read, Update, Delete and Search.

These are the fundamental building blocks of any object on a website. So for example an ‘Account’ is an object, which can be created, read (viewed), updated, deleted or searched for.

The main product you’re selling on your site will also tend to have these properties, for example on AirBnB a listing can be created (a host adds a property), read (someone views the property page), updated (they update the details of the listing) or deleted (the listing gets removed).

Even a ‘Session’ can be thought of as having been created and deleted, though there won’t always be a perfect mapping. For example, here is a CRUDS map for the Ladder Planner.

cruds map

There are obviously a million ways you can choose to name your events, and your needs will naturally evolve as your marketing gets more complex. This is not a ‘one and done’ type of task; you’ll always be improving it.

My advice is not overthink it – to paraphrase General George S. Patton; a good tracking plan violently executed today is better than a perfect tracking plan executed next month.

Mobile: A Different Beast

Tracking on mobile isn’t as mature and standardized as web tracking. As discussed, apps are more dynamic than websites and therefore aren’t typically built around ‘pages’ that you can deep link into. Therefore, mobile analytics packages are typically built more around ‘events’ than pages. Though Google Analytics does work with events and on mobile, mobile app developers tend to use more modern, mobile-focused analytics vendors.

Even if you do have deep link pages within your app, the Apple app store doesn’t pass referrer information or utm parameters! This means you can’t see what campaigns drove your app users or how users coming from different marketing campaigns behave. You also can’t drop a user directly into a deeplink page. Even if someone shared a specific page with them, once they install the app, they land on the generic homepage with no context as to how to get to the page they needed. As well as being bad for tracking, it’s a poor user experience; one the major mobile vendors are working hard to improve.

There are a number of different tools which solve one or both of these problems, but we’ve seen the most success with The tool ‘fingerprints’ (records information about) a user that clicks on a marketing link, and then recognizes that user once they install and open the app. They can then push that information into an analytics platform (for example Localytics) and/or land a user on the right deep link page (for example if they came via a friend sharing a link to a specific page).

Step-by-Step Tracking Guides

Return to Index

Now it’s time to really dig into the code that you’ll need to implement to get tracking setup. I’ll focus specifically on walking through the most popular use cases we’ve run into; from the most basic setup (Unbounce page) to the most advanced (Mobile app – coming soon).

Note: this post is a work in progress – I’ll keep adding new guides as we go, including exploring more advanced tools like Segment and Mixpanel. If you have one you want to see, Tweet at me.

If you aren’t familiar with the basics of JavaScript, this guide may seem a little alien to you. However, you should just be able to send this guide to your developer and they’ll know what to do. If you do want to learn a bit more about doing it yourself, Codecademy’s course on how to build an interactive website should teach you enough of the basics.

Unbounce Page

Return to Index

Let’s start with the easiest example; a simple Unbounce landing page.

This is easier than most tracking implementations because there are only two actions to track:

  • The user visited the site (just a single page, really)
  • The user only takes one action (signup)

So let’s get started.

I’m going to assume you already have a page (or multiple pages) ready to track. If you don’t know how to build a page, I’d recommend you check out this Unbounce workshop.

For the purposes of this guide, I’ll use the minimalist Boxee Green template.

unbounce landing page

Step 1 – prepare your Google Tag Manager code

If you login you’ll see your ID (GTM-XXXXXX) in the top nav bar, click it to get your code.

<!-- Google Tag Manager -->

<noscript><iframe src="//"

height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>


new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],




<!-- End Google Tag Manager -->

Step 2 – Click on the ‘JavaScripts’ section.

unbounce javascript

Paste in the Google Tag Manager code. Change ‘Placement’ to ‘Head’. Name the script ‘Google Tag Manager’. Save the Code.

unbounce gtm code

Step 3 – Now go back and click on the Form Confirmation Dialog page.

unbounce confirm page

Click JavaScripts and do the same.

gtm javascript

Step 4 – Now head over to Google Tag Manager.

tag manager

Click into Tags and add a new tag.

save new tag

Name the tag, add a Universal Analytics tag, and fill in your Google Analytics ID. Now add a Page View Track Type, and a trigger on ‘All Pages’.

universal tag

And actually that’s it!

Unbounce automatically does the rest for you. Even though no actual new URL loads when someone submits their email, Unbounce pushes a ‘virtual’ pageview when the Form Confirmation Dialog page pops up. We’ll see this in a second.

Checking it worked

To put this live and check it’s working, publish both the Unbounce page and the Google Tag Manager changes. Then visit the page. If you head to Google Analytics and click into the ‘Real Time’ section, you can see yourself surfing the site!

analytics realtime

Just to double check, you can also try out ‘Preview’ mode in Google Tag Manager, by clicking the down arrow next to ‘Publish’ and click Preview.

analytics preview

Now you can see what is firing from Google Tag Manager on the bottom of the page.

tag manager live

To test the form, you can actually add a plus sign after your normal gmail address (but before the and sign up with a unique email (if you have a welcome email set up, it’ll still go through to your normal email inbox).

email test

Even though the formatting isn’t great, you can actually see the tag firing in preview mode on the Form Dialogue page there too.

email submit confirmation

Finally, if you go to Real Time > Content you can see the actual page URL you were on. This is the ‘virtual’ pageview we were talking about earlier.

realtime content

The full URL path looks like this:

/tracking-blog-post/[email protected]

So to track this as a ‘Goal’ in Google Analytics, it would be contains ‘form_confirmation’.

goal tracking

Now, we could have just added the GA tracking code directly in the Unbounce script editor (which in itself, is a kind of tag management system)… so why didn’t we?

Well, just as described earlier in this post, that approach doesn’t scale. If I now want to add Mixpanel, Intercom, SumoMe, HotJar, Facebook Conversion tracking and a number of other tools and analytics pixels, I’d have to add them all one by one into Unbounce.

This wouldn’t be too much of a problem, but what if I am also using these scripts on my main website, on my blog and in a number of other places? I might forget a tag or make a mistake.

Keeping everything in Google Tag Manager makes it easier to see what’s firing (and why), and it decreases the chances of a mistake.

To add a new pixel, say for example the Facebook Website Retargeting code, it’s as easy as adding another tag off the same ‘all pages’ trigger (this time as a ‘custom HTML’ tag).

facebook tracking pixel

We don’t even have to log into Unbounce – I can publish it live to the site directly from Google Tag Manager.

Sure this doesn’t look like that great of a benefit considering how easy it is to publish within Unbounce, but for those of you who need an IT ticket, approval from a product manager, an hour of developer’s time and a release date window 2-12 weeks in the future to get something live on your site, this ability is mind-bogglingly useful!

The in-built capabilities of Google Tag Manager are pretty powerful.

Say we don’t want to add a tag to every page of the site, but ONLY to the Form Confirmation Dialogue page. For example adding a ‘conversion’ event, in this example for Facebook. We can actually do that pretty easily, just by modifying the trigger.

This is what the Facebook conversion event looks like:

<script>fbq(‘track’, ‘Lead’);</script>

There are a lot of different options, and you can even create your own custom ones, but ‘Lead’ will do for now.

facebook pixel

In Tag Manager we need to add a custom HTML tag like we did before, but this time, filter the trigger so that instead of ALL pages, it only shows on the ‘form_confirmation’ page (just like we saw in the live content report, and set up in Google Analytics Goals).

Step 1 – we set up the trigger.

pixel trigger

Step 2 – we add the custom HTML to fire on that trigger.

pixel html

Step 3 – Publishing and hitting preview again, we can check if it worked, in the exact same manner we did before.

pixel tracking

Our Facebook Retargeting pixel is working, but the Conversion event isn’t firing. Good start.

facebook retargeting

And there we go – Facebook Lead Conversion is firing on the popup as expected.

Now what if we didn’t HAVE a confirmation page at all? Say for example we wanted to track clicks on the social share buttons.

That’s actually pretty easy too with Google Tag Manager.

Step 1 – you have to find is the element ID. Right click on the button and click ‘inspect’.

inspect element

Now this might not mean too much to you if you don’t code, but it’s not that difficult if you ignore all but the one piece you need: the ID.

element hover

Here you can see that the button has a unique ID – “lp-pom-button-37”.

Step 2 – add click id targeting to Tag Manager, by going to ‘Variables’ clicking ‘Configure’ and adding ‘Click ID’.

click id

Step 3 – set up a trigger that fires when that ID is clicked.

click id trigger

Step 4 – set up a Google Analytics event.

analytics event

Step 5 – check via Google Analytics Real Time.

google analytics real time

Note: we check this via GA Real Time, because this click refreshes the page, and therefore we don’t see the event happen quick enough in GTM preview mode to check it’s working.

Now this doesn’t just work for the social buttons, but we can also us it on the main CTA button, or any button for that matter; we just need the ID:

social buttons

…and actually we don’t even need the ID.

We can also use the Text of the button, in this case “GET NOTIFIED”, the URL (i.e. track all clicks that lead to a certain domain) or even the element class (all buttons with the ‘lp-pom-button’ class). Be careful with that last one that you’re not firing events off clicks on buttons you don’t want to track, that have the same class.

misleading clicks

What we’ve learned so far is pretty powerful. Using a combination of only these methods, you can add pretty much any JavaScript tool, analytics software or track any event you need.

Hope your head isn’t hurting too much at this point and you can absorb this next section, because it helps you take your analytics to a whole new level.

Custom Events

Ok so we talked earlier about how Unbounce was making it easier for us by pushing a ‘virtual’ pageview when the Form Confirmation Dialogue page was popped up… what if they weren’t? We’d have to find another way to fire our conversion event.

This is how:

<script>dataLayer.push({'event' : ‘UnbounceSignup’});</script>

Now you need to go back to Unbounce, to the Form Confirmation Dialogue page and add this. Even though this is extra work, it’s the only way to be 100% sure your event will fire.

gtm conversion

This method, rather than relying on pageviews, is what most modern web developers use to fire their analytics events – particularly those working on websites where the majority of user interactions DON’T reload the page.

It’s actually pretty easy to add a trigger for these events, just create a ‘custom event’ trigger and match the name to what you added to Unbounce (or your developer added to your site).

unbounce signup

From there you can add your event tag as normal.

event tag

Now we kept this simple and just fired a simple event name, then added more context for the event manually in Google Tag manager… what if we wanted that context to be added at the code level and pushed through GTM into our other tags?
⇒ Download Event Tracking Setup Guide ⇐


For example, Unbounce is built for A/B testing – what if you want to know which variation was shown to the user before they signed up?

Luckily Unbounce provides this as a variable on the page, that we can access. If you (after clicking ‘inspect element’) click on ‘console’ and type ‘window.ub’ you can see the variables Unbounce pushes to the page.

unbounce variables

We’re interested in variationID, and we can pull that info into the event, as a variable.

If we go into Variables within Google Tag Manager, and pick ‘JavaScript variable’ and type in “”, we now have this as a resource to add to our tags.

variant id

To use this in a tag, we just need to put it in curly brackets, like this “{{Unbounce Variant ID}}”.

ga conversion

And voila – we’re tracking the variant ID directly from the page.

variant tracking

Again, this looks like extra work right now, but if we were A/B testing 10s or 100s of variations we’d very much like to not have to code each one manually.

Of course, this is just the beginning:

We could for example push any of the other Unbounce variables into our tags, like page name:

unbounce variable tags

We could push the URL into our tag:

urls in tags

Or really anything our developers can hard code for us.

Script Management

Now to make life easier for ourselves, we can take a couple actions to avoid repeatedly adding these scripts every time.

For example, we could drop the eventCategory and eventAction down to the code level, rather than having multiple triggers in GTM.



‘eventCategory’: ‘Signup’,

‘eventAction’: ‘Submit’,

‘event’: ‘SignupEvent’



Note: when adding multiple variables, each but the last needs to have a comma after.

Add the right code (plus values) into Unbounce.


Add the variable for eventCategory.

event category

Add the variable for eventAction.

event action

Note: these are both ‘dataLayer’ variables, because you’re ‘pushing’ them to the dataLayer.

Now incorporate into the actual event send.

event send

Now you never have to set up another event in GTM again for Unbounce – you can just fire the GTM tag with the naming convention you want, and it’ll pass through GTM to GA (and the other tags you have set up). This is a good practice to adopt, particularly when working with more complex, self-hosted websites and working with your own developers.

We’ll go into more detail here when we talk about eCommerce stores, but a common use of ‘variables’ is to pass the transaction value whenever someone makes a purchase – that’s something you couldn’t possibly hard code yourself unless you can pull it from the page.

I don’t know about you, but I’m always forgetting my GA ID and having to look it up. You can actually store this as a ‘constant’ variable and never have to remember it again!

Create a ‘constant’ variable.

constant variable

Use the variable to fill in your Tracking ID.

tracking ID

Another time saving feature is Unbounce’s Script Manager. It allows you to automatically fire the right events on the right pages, based on domain.

script manager

There are also more direct integrations with GTM and GA to save you more time.

direct integration

The major benefit I’ve found is in not forgetting to add your script to that new page you launched – if it’s on the same domain it’s automatically added.

Combined with the power of Variables, you can save yourself a lot of duplication and time.

ProTip 1 – Capturing utm parameters along with email as hidden form fields.

Note: read our post on utm parameters if you aren’t sure what these are.

Although Google Analytics can show you which marketing channels drove leads, it can’t tell you what leads specifically it drove. It’s against Google’s guidelines to record any personally identifiable information about those leads (i.e. email address) in your analytics.

Additionally if you have a long sales cycle, particularly if much of it happens offline, you’ll struggle to attribute the final sale you make to the right marketing channel.

To solve this, we need to capture the utm parameters when a user signs up using the hidden form fields feature in Unbounce.

Step 1 – click on the email input and click ‘edit form fields’ on the right.

email input

Step 2 – click on ‘hidden field’ and change the name to (exactly) ‘utm_source’.

hidden field

Step 3 – add utmmedium and utmcampaign in exactly the same way, then hit done, save the page and republish.

utm parameters

…and that’s it. Unbounce makes it easy for you by automatically looking into the URL for the UTM parameters, then adding them to a hidden form field, which means they’re captured alongside email in the database when the user submits.

We can test this by adding our own made up values for utm parameters to the link when we visit the page, and seeing if they end up in the database.

lead tracking

From Unbounce you can push that information into any CRM (via WebHooks and Zapier if you don’t see the one you use here).

crm hooks

This is a great way to build trust between marketing and sales; seeing the marketing source right alongside those leads in the database, makes it hard to argue about who drove that lead.

Now we mentioned earlier that Unbounce automatically pulls the parameters from the URL and adds them to the form for you. If you aren’t using Unbounce, pass this post along to your developer and they should be able to figure out how to code this behaviour on your own site.

If your website has multiple pages, or a user comes back multiple times, you’ll lose your utm information. The solution is to store the utms in a cookie or in local browser storage, until the user finally signs up, at which point pull the data back out and use our hidden fields trick.

Again, this will take some development work, but the flexibility to be able to use your own attribution rules and being 100% confident in the data is really quite valuable.

Ghost Blog

Return to Index

For the Ladder blog, rather than WordPress we use a modern simpler CMS (Content Management System) called Ghost. We prefer it for the simplicity, and because our developers are full-stack JavaScript engineers so they can edit the JS-based Ghost templates themselves, rather than hiring a PHP developer (the language WordPress is built on). Regardless of what blogging platform you use, the process will largely be the same.

Step 1 – log into your Ghost CMS. The URL is (substitute for your own URL)

Step 2 – click into ‘code injection’ and paste your Google Tag Manager code.

ghost code injection

If you read the first step-by-step guide in this post on Unbounce Pages, you’ll notice this section looks like a simplified version of Unbounce’s script manager. Almost every CMS or platform has their own space where you can add tracking code. You just need to find it, or or override it if there are limitations (which we’ll see in the Shopify guide).

Step 3 – add the Google Analytics tracking code.

ghost analytics tracking

Great – nice and simple, just like adding it to Unbounce. Let’s see how we can take this further.

Access Automated Audits - Book 30 Minutes

Email List

Return to Index

Any professional blogger will tell you that building an email list is key. Having a big email list allows you to continually communicate with your audience, remind them to come back for new content and helps you build your traffic over time. So naturally you’ll want to track how many signups you’re getting.

On the Ladder blog, to collect emails we use a tool called SumoMe. Among other things their ‘List Builder’ and ‘Scroll Box’ are excellent ways to increase your email conversion rate.


To implement, it’s as simple as adding one line of code.

<script src="//" data-sumo-site-id="b078079d9a476c7c12d02f76a29b38b2e973681602a05d50ff1ca4a1d20952e1" async="async"></script>

sumome snippet

To track signups, just like Unbounce and Ghost, they make it easy for you by giving you a place to put your tracking code. However it’s a little clunky as you have to add it for every single individual popup. Here’s an example below.

sumome list builder

You’ll notice there’s a place for when the popup is shown, as well as one for when someone submits their email. This is helpful because you can work out your show rate (% of people who see the popup) as well as your conversion rate (% who submit their email when shown the popup). To differentiate these, I pushed the events as ‘sm-show’ and ‘sm-signup’.

To add a bit more context, I also pushed two variables, ‘sm-label’, the name of the popup and ‘sm-app’, so I can compare for example whether List Builder or Scroll Box is more effective.

The next step, if you’re following along, is to add those variables in GTM so you can use them.

sumome gtm

Next we create the trigger that will fire on email submit.

sumome email trigger

Thanks to this set up, rather than create a different Tag for every single new email popup, I can just pass those variables into one.

passing variables

I’d repeat the above for ‘sm-show’ and as long as I remember my GTM code when making new popups, I should never have to modify my GTM setup for SumoMe again.

…wait there’s just one issue. One of my SumoMe tools, Smart Bar, doesn’t capture email addresses, it drives clicks out to my website. How to do I track that?

smart bar

If we remember back to the Unbounce guide, we can track clicks on an element, given its ID, Class or Text. Well, if we right click on the button, and click ‘inspect element’, we can see that the button has a ‘class’ of ‘sumome-smartbar-button’.

smart bar link

I didn’t see an ID, and rather than use the text, which can change, this class looks like a surefire bet to track all Smart Bar button clicks.

Just like before, we’re pulling in the click class variable, then only firing the tag when it matches.

smart bar click

Again, we can do the same to track social shares, another SumoMe app.

social sharing

Triggering based on the sumome-share-client-share class seems to be best.

sumome share

Set up the tag. Push the ‘text’ as a variable so you can see what CTAs work best.

sharing buttons


Return to Index

Why stop at shares and clicks to our website? Why not track all outbound clicks. For example It’s very useful to see:

  • How much traffic you’re sending to other websites
  • What websites you’re sending the most traffic to
  • How much traffic you send back to your main site
  • How much traffic you’re sending to your affiliates
  • What blog posts send the most outbound traffic

To do this with GTM, it’s actually pretty easy.

Step 1 – setup a trigger on all link clicks.

Note: I wouldn’t choose to ‘wait for tags’ unless it’s really important that you measure 100% of clicks, because it can significantly slow down loading times and hurt user experience.

link clicks

Step 2 – configure the Click URL variable.

click url

Step 3 – add the GA event firing off the clickout trigger we created.

clickout trigger

By adding the clickout URL in the Event Label, we can track which URLs we’re sending the most traffic to. Additionally I added a value of 1 to the firing of this event, which will automatically allow us to see how many events we’ve fired in the ‘event value’ field.

If outbound clicks are worth something to your business, you might want to dynamically add this value via a hardcoded variable. You could also incorporate a lookup table to stop competitors prying sensitive like how much your affiliates pay you per outbound click.

hardcoded variable

Scroll Tracking

It can also be helpful to track how far someone reads down a page. While we haven’t implemented this on our blog yet, Optimize Smart put together a few good solutions for doing this, which your developer should hopefully be able to understand.

Bounce Rate

It’s important to understand that any event you fire decreases your bounce rate. This is a good thing; normally you have no idea what percentage of those ‘bounces’ were true bounces, i.e. they left without doing anything. By tracking clicks out to other sites and tracking scroll depth, you can see how many actually engaged with your site, and adjust your content / traffic strategy accordingly. If you don’t want these events to count against bounce rate, simply set ‘non-interaction hit’ to True in the Tag configuration.

bounce rate

Custom Dimensions

What if you want to provide some context about a user’s behaviour, but it didn’t necessarily want to fire an event every time? For example if a user has shared on social in the past.

That’s where Custom Dimensions come in.

First we have to set one up in GA. It can be at the ‘hit’ (pageview) level, or per session or user.

custom dimensions

We then make a note of the dimension index, in this case 2 (you only get 20, so use sparingly).

dimension index

Now it’s as simple as adding our custom dimension to our SM-Share event, and we’re golden. Now we’ll be able to split any of our traffic in GA reports by whether they have shared or not.

share event

Heatmaps, Surveys, Recordings, Scroll Analytics

It’s not all about quantitative tools; GTM can help you add qualitative tools too. For example running surveys, seeing where people click or scroll and even recording their screens. SumoMe has their own heat maps (see where people click) and Content Analytics (see how far they scroll) tools, and the good news is that we already implemented it; we just need to turn them on.

SumoMe Content Analytics (scroll depth).

content analytics

SumoMe Heatmaps (click patterns).


More good news; it’s pretty much the same process to install any of these tools. For example here’s how to install Hotjar, which has heat maps, surveys, screen recording and more.


Hotjar Screen Recording.

hotjar screen recording

Hotjar Heatmap.

hotjar heatmap

This is how polls look on Hotjar.

hotjar polls

If you’re interested in surveys / polls specifically, check out our post on Qualaroo, which is a more advanced tool we recommend in this space.

ProTip 2 – wipe utm referrers.

If you’re really savvy, you’ll notice the utm system isn’t perfect. If I come through a Google Adwords campaign, but then I share my URL with you (complete with utm parameters), GA will attribute both of us to Adwords, inflating the marketing numbers. This is a big issue when you’re seeing a lot of share activity on your site. Luckily it can be solved by wiping the referral information once you’re done with it. Note: Buzzfeed, the king of shareable content, does something similar as the basis for their proprietary Pound analytics tool.

WordPress Blog

Return to Index

Now although we prefer to use Ghost at Ladder, WordPress IS the most popular CMS in the World, so it would be remiss of us to leave it out. If you’re looking to add tracking to a WP blog, I’d first recommend you read the above Ghost guide we put together, as 90% will be the same.

The major difference? Plugins.

wordpress plugins

For almost any major marketing technique, tool or platform, there’s a WordPress plugin. Installing Google Tag Manager is as easy as installing this plugin by DuracellTomi.

wordpress tag manager

Right out of the box it not only adds the GTM code to every page of your WordPress site, but it also build a basic Data Layer for you!

  • post/page titles
  • post/page dates
  • post/page category names
  • post/page tag names
  • post/page author ID and names
  • post/page ID
  • post types
  • post count on the current page + in the current category/tag/taxonomy
  • logged in status
  • logged in user role
  • logged in user ID (to track cross device behavior in Google Analytics)
  • search data

Want something a little more customizable? Try Header and Footer, a script injection plugin.

header and footer

SumoMe? One click integration with the plugin they built for WordPress Users.

wordpress sumome

The point is that whatever you need to accomplish in WordPress, there’s probably a plugin out there that helps you do it.

If not, you can always edit the theme manually. If you go this route, make sure you know what you’re doing – it’s really easy to screw up your site by changing the wrong thing. I’d recommend finding a good midrange WP developer on Upwork to make any manual changes.

If you want more flexibility than Header and Footer, but without the risk of messing up your site by coding it manually in the theme, try something like the Code Snippets plugin instead.

Shopify Store

Return to Index

Ok so I’ve got great news for you. If you read the Unbounce, Ghost and WordPress guides above, you’ll already know 80% of what you need to know for a Shopify Tag Manager implementation! Even better, the other 20% is done for you by Shopify. ?

Just like the other platforms, it has a place to paste your tracking code on the conversion page.

shopify tracking

But you don’t really have to worry about that for GA, because it has a direct integration (including advanced eCommerce tracking! – though remember to turn it on in GA Admin).

Note: you need a Shopify ‘Plus’ account in order to be able to track revenue.

shopify analytics

Just like WordPress, Shopify has their own app store, which make more advanced integrations (we recommend Google Shopping, Justuno, ReferralCandy and Klaviyo) super easy.

shopify plus

One thing I would consider however, is an A/B testing software. On Unbounce this was built in, and on the blog platforms, there wasn’t much to test. However with eCommerce you can test changes that directly impact revenue, and track those changes using GTM. To learn more about A/B testing, check out this post on Shopify or read our A/B testing guide.

Optimizely has a direct integration with Shopify, but it’s not too difficult to implement manually.

Note: it is not advised to implement Optimizely within Google Tag Manager as it can affect the performance of your tests by showing a visible ‘flicker’ as the content loads.

Go to Online Store > Themes > Edit HTML / CSS > theme.liquid

shopify apps

Then just paste Optimizely in the ‘head’ part of the document. Just like SumoMe, it’s one simple line of code, example below:

<script src=""></script>

In order to report on revenue in your tests, you can also push a revenue event into Optimizely. This can be done in GTM, or in the ‘checkout’ space for tracking code in Shopify we saw earlier.

<script type="text/javascript">

var optimizely = optimizely || [];

var revenueInCents = {{ subtotal_price | money_without_currency }} * 100;

optimizely.push(['trackEvent', 'conversion', revenueInCents]);


I highlighted the piece in double curly brackets, because if you follow along, you should recognize what this is by now; a variable! Yes, just like GTM variables, Shopify has their own variables they make available on the page.

We can do the same thing to push revenue into Facebook, so we can report on revenue directly from our Facebook ads manager, saving us time digging around in GA.


fbq('track', 'Purchase', {'value':'{{ total_price | money_without_currency }}','currency':'USD'});


But there’s more than just revenue. For example we could reconstruct the entire advanced ecommerce tracking object and push it into GTM, if we didn’t want to do it via Shopify’s integration. This would allow us to push that information into more than just GA, without relying on there being a native Shopify App integration with the platform we want to use.

<!-- Checkout Page GTM -->



'orderId': {{ order_number }},

'productValue': {{ total_price | money_without_currency }},

'productId': [{% for item in line.items %} {{ item.sku || }}, {% endfor %}],

'orderItems': [{% for item in line.items %} {

sku: {{ item.sku || }},

price: {{ item.product.price | money_without_currency }},

quantity: {{ item.quantity }}

}{% endfor %}]



Now that might be pretty scary and complicated, but don’t worry. For a relatively small fee you can find talented Shopify developers on Upwork that live and breathe this stuff and can do it for you. You only have to do it once and you’ll have solid data from then on, so it’s worth it.

Custom eCommerce Sites

But what if you don’t have a Shopify site, with all these integrations and pre-baked variables?

If you have a custom eCommerce site, take a look at how Shopify does it first, then ask your developer (or an Upworker) to write their own custom version for your website.

So long as they can make the variable values you need to track, available on the page, it can be pushed into GTM, and from there, into any other platform.

With the right combination of Variables and Events, you can truly track anything!

From the DOM

Ok so you’re saying you have a custom site AND you can’t afford a developer off Upwork?

Well… there’s still hope for you yet.

With a little knowledge of how websites work, a little knowledge of code and a lot of trial and error, you can use GTM to pull information right out of the web page and into your tags!

DOM means ‘Document Object Model’, and it’s simply just a representation of how the website is put together. All you need to know, is that every element on the page can be referenced by ID and Class. Remember we did this earlier in the Ghost guide for tracking Smart Bar clicks. We can also access whatever is in the URL, by pulling document ‘window.location.href’, as we did earlier in the Unbounce guide.

Let’s take the Best Buy website as an example.

If we take a look at this Acer Chromebook page, what do we notice?

best buy acer chromebook

Well, the word Acer is right there in the URL.

Is this a pattern? If it isn’t consistent we won’t be able to use it.


It looks like it is: the brand name is always in between “site/” and a dash “-”. Using regex* we can actually pull that variable from the URL and use it as a variable in GTM. Great start!

Note: regex is a tough subject and I won’t cover it here (because honestly I suck at it), but you can usually hash something together by methodologically testing different combinations.

What else can we see in the URL? There’s something called the “skuId” – that must be the product ID. This appears twice, and it’s harder to grab the one at the end with regex (unless we write it carefully, we’ll grab anything else at the end of the URL), so we’ll go for the first one.


We can also see that, although they appear in different places in the URL depending on the brand name, the word ‘Chromebook’ is always there in the URL. This isn’t ideal, as we’d have to write a ‘contains X’ rule for every category we wanted to tag. However if we’re doing a special Chromebook sale, this might be worthwhile.


We could also write a regex rule for memory, emmc flash, etc.. you get the idea.


We’ve got quite a lot, and that’s just from the URL. What else can we get from the page itself?

The answer? Quite a lot more.

For starters, the name helpfully has a unique id “sku-title”.

best buy sku

Pulling this out as a variable is very similar to the click text trick we used in the Unbounce guide. However we need to do a little more digging to get the value we need.

If we switch over to the console and type the following code:

var name = document.getElementById("sku-title").textContent;


We get our value!

“Acer – 14″ Chromebook – Intel Celeron – 4GB Memory – 32GB eMMC Flash Memory – Sparkly silver”

acer chromebook

To use this in GTM, we just need to add a Custom JavaScript Variable, and we can then use that like any other variable in our tags.

best buy get name

function () {

var name = document.getElementById("sku-title").textContent;

return name;


Note: we have to wrap the code in a function, and make sure it returns a value to make it work.

So what else can we get? Anything with a unique ID!

Model Number

best buy model number


best buy reviews


best buy price

Note: the last two were classes rather than IDs, but they look unique so we should be fine. We just need to modify the code to say getElementsByClassName(“example”)[0], which gets the first element with that class in the document (in case there are multiple).

best buy spectre

Pretty powerful right? I’ll leave you with one last clever one.

How would we check if the user is logged in? Well we’d just check what the text of the signin button says, of course!

sign in button

var loggedIn = document.getElementsByClassName("user link-text")[0].textContent;


logged in var

Now this approach isn’t perfect. All it takes is for one developer to change the ID or Class of an element and your tracking is broken. It could be days before you even notice and that data is lost forever if it isn’t captured in the moment.

Even though it’s pretty satisfying to be able to work around the development team’s busy schedule, or save yourself some budget, it’s best to use this only as a temporary workaround.

⇒ Download Event Tracking Setup Guide ⇐

Work In Progress Event Tracking Guide

As mentioned, this post is a work in progress. I hope you’ve enjoyed what we’re written so far – I’d be happy to take any feedback, changes or additions you think would be valuable. I plan to keep adding new guides as I get the time to create them.

So far, these are the most requested:

  • Mixpanel vs Google Analytics
  • Segment vs Google Tag Manager
  • Mobile App Tracking (+
  • Offline events (using Google’s Measurement Protocol)

Any others you can think of? Dying to see one of the above? => Tweet at me.

Access Automated Audits - Book 30 Minutes