Adding Google Tag Manager to a Hugo site

I prefer to keep the Google Tag Manager container ID in Hugo’s configuration instead of repeating it in templates. Add a parameter to config.toml and replace the placeholder with your container ID:

[params]
   gtm = "GTM-XXXXXX"

In your theme’s header.html partial, add the main Tag Manager script inside <head>. The condition keeps the whole block out when no container ID is configured.

{{ if $.Site.Params.gtm }}
  <!-- Google Tag Manager -->
  <!-- create dataLayer -->
  <script>
   <!-- OPTIONAL dataLayer -->
    var dataLayer = window.dataLayer = window.dataLayer || [];
    dataLayer.push({
      page:'{{ .Title }}',
      categories:'Your dataLayer'
    });
  </script>
  <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
  'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
  })(window,document,'script','dataLayer','{{ $.Site.Params.gtm }}');</script>
  <!-- End Google Tag Manager -->
  {{ end }}

Google also provides a fallback for visitors without JavaScript. Put this block immediately after the opening <body> tag:

{{ if $.Site.Params.gtm }}
    <!-- Google Tag Manager (noscript) -->
    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ $.Site.Params.gtm }}"
    height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <!-- End Google Tag Manager (noscript) -->
 {{ end }}

You can also give the browser an early hint about the Tag Manager origin:

<link href="https://www.googletagmanager.com" rel="preconnect" crossorigin>
<link rel="dns-prefetch" href="https://www.googletagmanager.com">

Keep local visits out of analytics

Local development traffic is usually noise. Wrap the Tag Manager blocks in this condition if your local base URL contains localhost:

{{ if not (in (.Site.BaseURL | string) "localhost") }}
...
{{ end }}

After rebuilding, inspect the rendered HTML rather than only the Hugo template. You should see the container ID in both snippets on the production URL and no Tag Manager request on localhost.