Tags, triggers, and variables
GTM's three primitives, what each one is for, and the rule that keeps a container from becoming a swamp.
Google Tag Manager is a container of JavaScript that loads once on your page and then decides, at runtime, which tags to run and when. It has exactly three building blocks. Everything you will ever do in GTM is a combination of them.
Tags: what to send
A tag is the thing that sends the request. In the left nav, Tags lists every one in the container. Each has a type — the vendor and the shape of request it makes:
- Google tag — loads GA4 (and Google Ads) on the page and sends the automatic
page_view. One per measurement ID. This replaced the older "GA4 Configuration" tag type; if you seegaawcin an old export, that's the legacy one. - Google Analytics: GA4 Event — sends one named event, like
add_to_cart, with parameters. - Google Ads Conversion Tracking, Conversion Linker, Floodlight — the ads family.
- Custom HTML — arbitrary script you paste in. Powerful, un-sandboxed, and the source of most container rot. Use a gallery template when one exists.
- Community templates — vendor tags from the gallery (Meta, TikTok, LinkedIn…). Sandboxed, consent-aware, preferable to Custom HTML.
A tag has zero or more firing triggers and zero or more exceptions (blocking triggers). A tag with no firing trigger will never run — the auditor flags exactly this, and every large container has a few.
Triggers: when to send
A trigger is a condition on an event GTM observed. GTM watches the page and emits its own internal events: gtm.js (container loaded), gtm.dom, gtm.load, gtm.click, gtm.formSubmit, and so on. A trigger says: when this kind of event happens, and these filters match, fire the tags attached to me.
The trigger types you'll use most:
- Page View – All Pages — the built-in one. It fires on
gtm.js, the earliest moment the container is ready. This is where your Google tag goes. - Initialization – All Pages and Consent Initialization – All Pages — even earlier; consent defaults belong on the second one.
- Click – All Elements / Click – Just Links — with filters like Click ID equals
add-to-cart. - Custom Event — fires when the site pushes
{event: "something"}into the dataLayer. This is the one you'll use for ecommerce, and it's the subject of the next lesson. - Element Visibility, Scroll Depth, Form Submission, Timer — the built-in listeners.
One trigger can fire many tags. One tag can have many triggers. Triggers attached to nothing are harmless but are noise — and click/visibility listeners still cost a little on every page.
Variables: which values to send
A variable is a value GTM resolves at fire time. You reference them with double braces: {{Page URL}}, {{Click ID}}, {{DL – order value}}. They appear in tag parameters ("send this as the event value") and in trigger filters ("only when Click Classes contains cta").
Two kinds:
- Built-in —
Page URL,Click Element,Event,Referrer… They exist but are off until you enable them under Variables → Configure. A tag that references{{Click Classes}}when the built-in isn't enabled resolves to nothing. The auditor calls this a missing reference. - User-defined — you create them. The important types: Data Layer Variable (reads a key from the dataLayer — most of your ecommerce values), Constant (a fixed string, like a measurement ID), Lookup Table, Custom JavaScript (runs a function — powerful, and executes on every evaluation).
The rule
Here is the one convention that separates maintainable containers from swamps:
A tag knows what to send. A trigger knows when. A variable knows which values. Nothing else.
Don't put logic into a tag that belongs in a trigger. Don't hardcode a measurement ID into six tags when a Constant variable holds it once — when you migrate properties, that's one edit instead of a hunt. Don't reach into the DOM from a Custom JavaScript variable when the site could push the value into the dataLayer.
Name each one so a stranger can read it: GA4 – Event – add_to_cart, CE – add_to_cart, DL – ecommerce.value. The auditor measures how consistently you do this, because a container someone else can read is a container that gets fixed instead of abandoned.