Integrating AngularJS and Google Tag Manager


If you’ve added Google Tag Manager and Google Analytics to an Angular app, you were in for a surprise. After deploying your code, you may have popped open the Real Time Reports and saw… nothing.

Well, not nothing, but not a whole lot of anything. Where are the page paths? Hell, where are the pageviews? You dove into the Google Analytics docs and came back disappointed. Finally, you hit the search results – someone, somewhere had to know what to do.

Welcome, friend! You’ve come to the right place. Let’s get you straightened out.

But First, The Easy Button

Not interested in what’s going on under the hood? The module you’re looking for is Angulartics (Full disclosure: I’m a contributor on the GA and GTM libraries). It supports:

  • ngRoute and UIRouter
  • Google Tag Manager & Hard-coded Google Analytics
  • Declarative event tracking
  • Advanced hit types like User Timings
  • Exception tracking, scroll tracking, and more advanced features
  • 20+ analytics tools

And there’s a GTM Container file for one-click configuration written by yours truly in the repository.

Get the code here!

What Is Google Tag Manager?

Google Tag Manager (also referred to as GTM) is a tool for delivering Google Analytics tracking code and other tracking snippets on a page. It helps de-clutter your code by moving tracking snippets into a single location, instead of littered throughout the page. It features a WYSIWYG-style interface for creating, testing, and publishing additional tracking snippets on the fly, called Tags. Tags are assigned conditions on when they should be executed, called Triggers. In a nutshell, here’s how it works:

  1. A user interaction (clicking, submitting a form) or programmatic notification is observed by GTM (called an event)
  2. Each Trigger is evaluated against the event to see if the firing conditions set in the interface are met. If they are, the Trigger ‘fires’
  3. All Tags assigned to any Triggers that fire are executed

Most commonly, Google Tag Manager is used to deploy Google Analytics tags, from basic pageview tracking all the way up to complex custom Google Analytics Events. For a more in-depth explanation, my colleague Kaelin wrote a great introduction to Google Tag Manager and the relationship between GTM and Google Analytics.

Our Cookbook

Below, we’ve shared some components that we’ve used in the past. These components are designed to minimize the amount of additional code required to integrate Google Tag Manager and an Angular app. Because GTM sits on top of Google Analytics, the data that you give to it is inert by default; whether anything is fired is controlled in the interface. Because of this, it’s a good idea to be inclusive with the data you share with the dataLayer.

Pageview Tracking

The default Trigger for firing pageviews is called All Pages. The event that this Trigger corresponds to is gtm.js, which fires only when the GTM snippet is first loaded by the browser. This is why your pageviews haven’t been showing up. You need to add an internal listener in your app that notifies GTM when a state change occurs. If you’re using ngRoute, it would look like this:

Once you’ve wired this into your app, Google Tag Manager will be notified any time a route change occurs. In order to translate this into a pageview in Google Analytics, you’ll need to create a Trigger for your ngRouteChange event, like so:

GTM Trigger for Angular Route Change

Then create a Variable to extract your page path from the dataLayer, like so:

GTM Variable for Angular Route

And you’ll need to create a Google Analytics pageview tag, like so:

GTM Tag for Angular Pageview

Don’t forget the Fields to Set configurations!

  • cookieDomain is set to auto
  • page is set to {{DLV – Angular Route}}

If you’re unwilling to wire into your router, you can create a Trigger using the History Change listener built into GTM, watching for pushState events, but we don’t recommend this approach.

Model Change Tracking

Often, you may want to track changes to model values in Google Analytics. A simple way to do this is with a custom Directive that notifies Google Analytics or Google Tag Manager when a model’s value changes. A simple solution for this challenge is to use a custom Directive that binds to the change event.

You can then add notify-gtm on any element with an ng-model that you’d like to observe with Google Tag Manager. In Google Tag Manager, you can use a Data Layer Variable to extract the value of the model or view, or use the element object reference to pull out additional data.

Notifying GTM After A Template Renders

Often, we depend on information in the DOM when capturing data to send to Google Analytics. Normally, we can use the gtm.dom or gtm.load as safe-guards for firing our code, but with an Angular app, it can be hard to ensure the data is ready to go. Unfortunately, the best solution I’ve seen so far is equally ugly; creating a Directive that triggers a function after rendering (hat tip to Guilherme Ferreira).

This provides a balance of flexibility and discretion, but it means you’ll have to remember to add the directive at the bottom of each of your templates. If you’ve got more clever solution, please share it in the comments below.

Tracking Other Interactions

If you’d like to use Google Tag Manager and Google Analytics more extensively in your application, take advantage of Google Tag Manager’s reusable Variables to streamline the process. First, you’ll want to build a reusable service for interacting with GTM.

This can be further evolved to streamline things like event tracking.

With the above example, you could create a single Tag and Trigger for your Event Tracking, and simply invoke GTMService.eventTrack whenever you’d like to fire an event.

The Angulartics source code is a great place to learn more about different ways to integrate the two for maximum ease of use.

Other Front-end Frameworks

Many of these same concepts apply to other frameworks, e.g. Knockout, Backbone, and so on. If you’d be interested in knowing how we would approach integrating Google Tag Manager with another framework, let us know in the comments and we’ll see about writing a post covering that particular library.

To Recap

These components should help get you started. Remember, the data pushed to the dataLayer is inert by default, so lean towards ‘over-sharing’. You can automate pageview tracking, model change observation, and template rendering with our example components, and you can use a simple service to interact with the dataLayer in your controllers and other components. Finally, you can further streamline things like event tracking by creating your own services, and I’d recommend reviewing the Angulartics module if you’d like to learn more.

Have you integrated Google Tag Manager and Angular before? What was your experience? Share it with us in the comments.

Dan Wilkerson is a Software Engineer at LunaMetrics. He is passionate about web technology, measurement, and analysis. Dan is the winner of the 1999 Forge Road Elementary School Science Fair for his groundbreaking report on how magnets work. (ICP, take note.) Dan has worked at LunaMetrics in social media, as our marketing manager, and now in our analytics department.

  • Bogdan Gabriel

    Quite successful description. Congratulations. Useful information.

  • Frank Litjens

    This has been a great help, thanks!
    However, I can’t seem to find the newly tracked stats in Google Analytics.

    • Dan Wilkerson

      Hi Frank,

      There was a mistake in the event screenshot – I used routeChange instead of ngRouteChange (I waffled on the naming convention in the middle of writing the post; my bad!). Try that!


  • Stephen M. Harris

    Thanks Dan, this is so helpful!

    Besides being more lightweight than angulartics, are there other advantages to using the code from this post?

    You also say that “the Angulartics source code is a great place to learn more about different ways to integrate the two” … are you recommending using the methods from this post in combination with angulartics for custom tracking? (For instance, to implement event tracking w/o adding markup attributes?)

    • Dan Wilkerson

      Hi Stephen,

      Our cookbook items are plug-and-play/set-and-forget for companies who want to add GTM to their app but don’t want to develop Analytics into their codebase. This works best in companies with clear separation between devs and marketers (which I personally am saddened by, but understanding of).

      Angulartics is better for a company with tightly integrated marketing/development or developers who are looking to measure application performance for themselves. It requires more of a commitment from the developers in terms of understanding how Google Tag Manager and Google Analytics work/model data.

      It’s more often the former rather than the latter, in my experience so far. I think it’s a damn shame, since devs can learn so much from Google Analytics about product usage and performance.

      I call out the Angulartics source because it has more robust mechanisms for doing what these little blurbs do – it supports, for example, way more robust configuration, error tracking (I’ve got a post on that soon, coincidentally), user timings, etc. If a dev wants just bits and pieces, the source is a great starting guide to learning more about how to interact with GTM/GA.


      • Stephen M. Harris

        Got it, thanks Dan!

        Coming from a front/back-end web dev: you’re right! The past couple years I’ve learned to use GA to measure performance of marketing efforts, but before that it was a tool to assist in planning, maintenance, and improvement of the product itself. Out of the box, GA was informing sys/compatibility requirements for new projects, and diagnosing issues in live ones. But it’s way more than that; I wish I knew then what I know now. I keep discovering new ways GA can be used to suggest UI improvements and troubleshoot all sorts of issues. Definitely a sweet tool in the dev’s toolbelt!

        Also agree that it is unfortunate when dev/marketing are not tightly integrated. Separation = transactional approach to measurement implementation = bad. But it’s better than nothing, and way better than *gasp* letting marketing handle implementation 😀

  • JustinBMichaels

    The trigger event name you have in the screenshot is wrong. It has to be identical to what you set in the dataLayer.push object which is ngRouteChange. We didn’t see our pageviews in our Google Analytics account until we had them identical.

    The article was very helpful.

    • Dan Wilkerson

      Hi Justin,

      That will teach me to waffle on naming conventions mid-post – good catch, and thanks for the heads up.


      • Dan Wilkerson

        In my (poor, weak) defense, it was correctly referenced in the text above the image.. 😀

        Fixed the image! Thanks again, Justin.


  • Horia Valeanu

    Hi Dan and thank you for the article. It has helped me for the initial setup, but I don’t really get the GTMService code…
    In the first place, the push function seems redundant, as you could just use dataLayer.push({…}) directly. And maybe because of my ignorance 🙂 but I don’t understand the “forEach” part…Could you please (also) show a snippet of using GTMService.trackEvent() ? How would you call that in a controller? Thank you again!

Contact Us.


24 S. 18th Street, Suite 100,
Pittsburgh, PA 15203

Follow Us



We'll get back to you
in ONE business day.