Implementing The Google Tag


If you’ve used Google Analytics or Google Tag Manager much in the past few years, you’ve probably felt the frustration: Google product teams seemingly have a penchant for abruptly changing recommended implementation approaches, often without clear migration paths or adequate documentation.

Many of us who implemented GA4 early followed Google’s original guidance — set up the GA4 Config tag as a setup tag on all GA4 Event tags — only to later succumb to alert fatigue when logging into GA4 properties and GTM containers suggesting our implementations were now “broken.” If you’re looking for a way to get rid of these pesky warnings, join the club! However if you’re just a practitioner trying to divine Google’s current Best Practices, then also join me on this journey as I try to figure it out myself.

Shifting sands

Since the App + Web days, Google’s GA4 implementation guidance has evolved in pretty significant ways:

I think it’s instructive to consider why Google made these changes in order to understand how best to implement GTM and/or the Google Tag correctly today.

The Google Tag, the Google Tag tag, gtag, Google Tag Manager

Google’s naming choices create confusion even among experienced practitioners. Here’s what each term means:

Timeline: How We Got Here

Understanding the timeline helps explain why many implementations now show warnings:

Now, if you had earlier paid heed to Google’s “no action required” guidance, these warnings understandably caused concern. Google’s current documentation now recommends firing the Google Tag on the Initialization - All Pages trigger (gtm.init system event) rather than as a setup tag for GA4 Event tags. So what happens to implementations that still use the old convention? Unfortunately, there’s no mention in the GA4 documentation about this — however it’s implied that you need to update your containers to accommodate this change.

Understanding Google’s Strategy

Google’s gtag/Google Tag push came as an unwelcome surprise to many implementation engineers. After all, Google had invested heavily in building and documenting the dataLayer approach for consistent data collection.

However, examining Google’s broader strategy reveals why these changes make sense from their perspective:

1. Google has been trying for years to unify tagging for their products

Before gtag, every Google product (Analytics, Ad[Word]s, and Floodlight) had its own JS snippet and tagging requirements. It takes a lot of resources to manage three libraries, each with its own nuances and quirks. Three different sets of documentation, multiple teams, etc. Why not just have a single JS SDK? So, in 2017, Google released the Global Site Tag (gtag.js). This was to be the One Tag to rule them all. But there was one which refused to bow. GTM had relied on dataLayer.push since its inception to send data to it. So Google effectively has had to manage two different implementation approaches that at times conflicted with each other. The solution? Make gtag a wrapper for dataLayer.push. This allowed backwards compatibility with implementations using dataLayer (which is most of them) while getting them closer to a single SDK to send data to all of its products.

2. The GA4 Config tag in GTM was basically just running gtag('config') for your GA4 property

Most sites that have GTM containers don’t just have GA4 tags — they also have tags for Google Ads, Floodlight, etc. Some sites with GTM containers don’t have GA4; they use GTM for managing their Google Ads or Floodlight tagging. However, all of them use gtag.js — even if the Google Tag type isn’t in the container.

Remember: the Google Tag is gtag. When you add a Google Ads Conversion tag or Google Analytics tag to your container, gtm.js will automatically load gtag.js when it runs so it can configure the tags and orchestrate calls. This has been the case for years. Even if you hadn’t included the GA4 Config tag, gtm.js would still load gtag.js with Google’s preferred defaults. Adding the Google Tag tag (fuck) to the container does two things: 1) it tells gtm.js to load gtag.js sooner; 2) it allows you to change the default configuration for your Google products. When you think of it from this perspective, Google just picked a name for that tag (albeit an unhelpful one) that more accurately reflects what it is — although a better name might have been the Google Tag Config tag, since you don’t have to add a Google Tag tag to a container to load the Google Tag. (If you’re able to wrap your head around that, bravo!)

3. Reducing implementation complexity and errors

Data layer implementations often suffer from translation issues between analytics architects and engineering teams, even when detailed specifications are provided. One common sticking point is neglecting to clear the ecommerce object before new ecommerce events, which can lead to data pollution.

While developers understand the technical reasons for this requirement, it’s frequently missed or questioned during implementation. The gtag approach simplifies this by automatically handling ecommerce data clearing, reducing a common source of tracking errors.

Yes, gtag appears more proprietary than dataLayer, but in practice, most dataLayer implementations are proprietary anyway — you can’t simply swap out Google Analytics for Adobe Analytics and expect your dataLayer implementation to “just work” (at least, not without gtag).

While gtag doesn’t replace change management or interpersonal skills, it does provide a single SDK that works for multiple Google products, and that can simplify things.

Should you update your implementation?

If you’re seeing warnings in GA4 or GTM about misconfigured Google Tags, they may not necessarily indicate a problem — many times, the “Urgent” issues with your GTM container are just that Google’s expecting you to tag your lower environments. (Google product owners: if you’re reading this, look up “alert fatigue”.) Even if you’re still using the old setup tag method, you may not necessarily need to update to the new approach. Anecdotally I’ve seen a number of implementations using the old approach that are still working fine.

Here’s how to actually decide whether to take action:

⚠️ Update immediately if you have:

⏸️ Update when you can if you have:

Current good practices for Google Tag implementation

I’m not a fan of the term “best” practices, because what’s best for one site may not be for another. Regardless, whether you’re optimizing an existing implementation or starting fresh, here are some general guidelines I’ve found for implementing the Google Tag:

GTM Configuration

  1. Fire the Google Tag on the Initialization - All Pages trigger. This is Google’s current recommendation. The Google Tag in GTM is basically the gtag(‘config’) command. If the config command happens too late, it can mess up attribution or sessionization.

  2. Add one Google Tag tag for each Google product you use. That means if you have Google Analytics, Google Ads, and Floodlight, then add three Google Tag tags. If you have tags for more than one Google Ads account/conversion ID on your site, add one for each of them (you can share config options with the Configuration Settings variable). This is not required — Google will automatically inject gtag.js and the requisite gtag commands for each product you use — however, adding one for each product/account allows you to configure them and gives gtag.js more time to load.

  3. Use Enhanced Measurement whenever possible. My hot take (which I stole from Ken Williams). For better or worse, Google has done a lot of work with GTM to minimize the need for developer involvement. You can use Enhanced Measurement to track page views, form submissions, scroll depth, YouTube video views, and more. Even if you don’t use Enhanced Measurement, you can use an array of built-in trigger and variable types that reduce the need for bespoke cleverness. Engineers have a tendency to complicate, and complexity often results in brittle implementations. Only customize when you have a legitimate reason to do so.

When should you customize?

  • If you have an ecommerce site, you need developers to add gtag or dataLayer.push calls for all ecommerce events.
  • If you’ve enabled Form interactions, but the built-in gtm.formSubmit events don’t fire when you submit your forms.
  • If you embed videos from providers other than YouTube on your site.
  • Custom events not covered by automatic or enhanced measurement

These are just a few situations where you need to ask a developer to add gtag('event') or dataLayer.push() calls. Knowing when to customize comes with experience. As a general guideline though, try starting with what comes out of the box and work from there.

A bell curve meme with the idiot and jedi both saying use Enhanced Measurement and the midwit saying noooo you have to customize everything!
  1. Use a Google Tag: Configuration Settings variable to set all gtag config settings. Even if you only have one Google Tag in your container, having the config settings in a separate variable means you don’t have to touch the Google Tag when you just want to update config parameters. Be careful about sharing Configuration Settings variables between products — not all gtag('config') parameters are supported by all products!

  2. Use a Google Tag: Event Settings variable to manage all global event settings. This variable should be included in all GA4 Event tags as well as the Google Tag. Then set any event-specific parameters on their respective GA4 Event tag.

Data Layer Best Practices

Google recommends that you use gtag('event') instead of dataLayer.push(), but it will still support dataLayer.push() for the foreseeable future.

You absolutely don’t need to replace dataLayer.push() with gtag('event') in existing codebases — but when a product team starts talking about replatforming, weigh the pros and cons of using gtag instead. Recall that gtag is (among other things) a wrapper for dataLayer.push().

  1. Make sure all page and user data is in the data layer prior to the gtm.init event. This makes e.g. user_id available on Initialization when the Google Tag needs it.

  2. Only send a manual page_view event message if absolutely necessary. Start with Enhanced Measurement page views, and only send the page_view event separately if you need more control over when the page_view fires. If implementing on a site that uses a SPA framework, make sure to enable “Fire on history changes” in the Enhanced Measurement config screen. There are always tradeoffs, but manually instrumenting page_view is fraught with peril and can stymie even experienced teams.

  3. Clear the ecommerce object before each ecommerce event message. Use the following pattern to prevent data persisting across calls (note that you don’t need to do this with gtag):

window.dataLayer = window.dataLayer || [];
dataLayer.push({ ecommerce: null }); // Clear previous ecommerce data

dataLayer.push({
  event: 'view_item',
  ecommerce: {
    item_id: 'ABC123',
    item_name: 'The Google Tag Tag Type T-Shirt',
    /* etc. */
  }
});

Key Takeaways

For existing implementations:

For new implementations:

The bigger picture: Google’s changes, while disruptive and often leaving much to be desired in terms of communication, reflect a long-term strategy to streamline data collection across their products. Understanding the reasoning behind these changes helps us make better implementation decisions and anticipate future developments.

Whether you’re updating an existing implementation or starting fresh, focus on the fundamentals: accurate data collection, proper timing, maintainable configuration, and minimal complexity. The specific method matters less than getting these basics right.

Got suggestions or questions about your specific implementation? Reach out!