Google Tag Manager has a deceptively simple premise: rather than editing your website's code every time you need to add or change a tracking snippet, you manage everything from a single dashboard and publish changes without a developer. In practice, that dashboard can become intimidating quickly — dozens of tags, overlapping triggers, variable lists that grow without a clear structure.

The reason most GTM containers become difficult to manage isn't complexity — it's that people start building before they understand the underlying model. Tags fire when triggers evaluate to true, using values from variables. Once that relationship is clear, every configuration decision in GTM becomes straightforward.

This guide assumes you have GTM installed on your site. If you haven't done that yet, start with our guide on setting up Google Tag Manager correctly — it covers the installation snippet, the data layer initialisation, and how to verify the container is loading before you create any tags.


The mental model: how the three pieces connect

Before touching the GTM interface, this relationship needs to be clear:

  • A trigger watches your site for a specific condition — a page load, a button click, a custom event pushed to the data layer.
  • When that condition is met, the trigger fires any tags assigned to it.
  • Those tags use variables to fill in dynamic values — the current page URL, a product ID, a form field value — rather than hardcoding them.

Think of it like a conditional statement: when [trigger condition] is true, run [tag], using [variable values]. Every single configuration in GTM — no matter how complex — follows that same pattern.

Build in the right order: variables first, triggers second, tags last. Tags reference triggers; triggers reference variables. If you try to build a tag before you've created the trigger it needs, or a trigger before the variables it conditions on, you'll find yourself jumping back and forth. Start with variables, work up to tags.


Variables — the dynamic values everything else references

Variables are named containers for values that change depending on context — what page the user is on, what they clicked, what your site pushed to the data layer. Rather than hardcoding a URL path or a measurement ID into every tag and trigger that needs it, you define it once as a variable and reference it by name everywhere else.

Built-in variables vs. user-defined variables

GTM comes with two categories of variables. Built-in variables are pre-configured by GTM and just need to be enabled — things like Page URL, Page Path, Click Element, and Form ID. User-defined variables are ones you create yourself to read values specific to your site or implementation.

To enable built-in variables, go to Variables → Built-In Variables → Configure. Enable the ones relevant to what you're tracking. For most implementations, you'll want at minimum:

Variable name What it returns When you need it
Page URL The full URL of the current page Trigger conditions scoped to specific pages; passing page location to GA4
Page Path The path portion of the URL — everything after the domain Cleaner page-scoped trigger conditions without worrying about protocol or domain
Click Element The DOM element that was clicked Click triggers that need to match CSS selectors or check element attributes
Click Classes The CSS class string of the clicked element Identifying clicks on elements by their class name
Click ID The id attribute of the clicked element Targeting clicks on a specific element by its HTML ID
Click Text The visible text content of the clicked element Capturing what a user clicked — button label, link text
Form ID The id attribute of a submitted form Scoping form submission triggers to a specific form

The most important user-defined variable types

Beyond built-ins, the variable types you'll use most frequently in a GA4 and GTM implementation are:

Variable 01

Data Layer Variable

Reads a value your site has pushed into the dataLayer object. The most important variable type for any serious implementation — this is how dynamic values like transaction IDs, product names, and user types get from your site into GTM tags.

Variable 02

Constant

Stores a fixed value — your GA4 Measurement ID, a pixel ID, an API endpoint. Define it once and reference it across every tag that needs it. When the value changes, you update one variable instead of every tag.

Variable 03

URL Variable

Extracts a specific component of the current page URL — the hostname, path, query parameter value, or fragment. Particularly useful for trigger conditions and for passing clean page data to GA4 without passing the full URL every time.

Variable 04

JavaScript Variable

Evaluates a JavaScript expression and returns the result. Used for reading values from global objects on your page — window.userType, document.cookie, or any other value accessible in the browser's global scope.

Creating a Data Layer Variable step by step

Data Layer Variables are the most commonly needed user-defined variable type, so here's the exact process:

  1. 1
    Go to Variables → User-Defined Variables → New Click the pencil icon to open the variable configuration panel.
  2. 2
    Choose variable type: Data Layer Variable Click Variable Configuration and select Data Layer Variable from the list.
  3. 3
    Enter the Data Layer Variable Name Type the exact key name from your dataLayer push. If your site pushes dataLayer.push({ transaction_id: 'ORDER-001' }), enter transaction_id here. For nested objects, use dot notation: ecommerce.value.
  4. 4
    Name and save the variable Use a naming prefix that signals the type — dlv - transaction_id for a Data Layer Variable. This makes your variable list scannable as it grows.

JavaScript — dataLayer push your variable will read from

window.dataLayer.push({
  event: 'purchase',
  transaction_id: 'ORDER-10042',  // dlv - transaction_id reads this
  ecommerce: {
    value: 129.00,               // dlv - ecommerce value reads ecommerce.value
    currency: 'GBP'
  }
});

Use consistent naming prefixes for all variable types. dlv - for Data Layer Variables, const - for Constants, url - for URL Variables, js - for JavaScript Variables. When your container has 40+ variables, these prefixes are the difference between a scannable list and an unmanageable one.


Triggers — the conditions that fire your tags

A trigger defines the condition that must be true for a tag to fire. No tag in GTM fires on its own — every tag must have at least one trigger assigned to it. The trigger is what connects "something happened on the page" to "run this code."

Trigger types and when to use them

Trigger type Fires when Best used for
Page View The page loads — either on DOM ready or window loaded, depending on configuration Tags that need to fire on every page, or on specific pages identified by URL conditions
Custom Event A specific event name is pushed to the dataLayer GA4 event tags tied to user actions — form submissions, purchases, feature activations — where your site code controls the trigger via a dataLayer push
Click — All Elements Any element on the page is clicked Tracking clicks on buttons, divs, images, or any non-link element — always paired with conditions to scope it to the right element
Click — Just Links An anchor tag (<a>) is clicked Outbound link tracking, download link tracking, internal navigation tracking
Form Submission A form fires its native submit event Simple forms that use standard HTML form submission — less reliable on SPAs or AJAX-based forms
Scroll Depth A user scrolls to a defined percentage or pixel depth Content engagement tracking — firing GA4 events at 25%, 50%, 75%, 90% scroll thresholds
Timer A set number of milliseconds have elapsed since the page loaded Time-on-page engagement signals — firing after 30 seconds, 60 seconds, etc.
Element Visibility A specific element enters the viewport Tracking when a user sees a key section — a pricing table, a CTA block, a video thumbnail

All triggers vs. some triggers

Every trigger type in GTM gives you a choice: fire on All instances of this event, or fire on Some based on conditions. You should almost always choose Some and add at least one condition — a trigger scoped to All page views or All clicks is usually too broad and will cause your tag to fire in unintended contexts.

GTM — Example trigger conditions for common use cases

// Scope a page view trigger to the thank-you page only
Trigger type:  Page View
Fire on:       Some Page Views
Condition:     Page Path  contains  /thank-you

// Scope a click trigger to a specific CTA button
Trigger type:  Click — All Elements
Fire on:       Some Clicks
Condition:     Click Element  matches CSS selector  button.btn-primary

// Scope a custom event trigger to a single event name
Trigger type:  Custom Event
Event name:    form_submit
Fire on:       All Custom Events

Custom Event triggers match on exact event name. If your dataLayer push uses event: 'form_submit' but your GTM trigger is configured for formSubmit or form submit, the trigger will never fire. The event name in the trigger must match the value of the event key in your dataLayer push character for character — including case.

Creating a Custom Event trigger step by step

Custom Event triggers are the most important trigger type for GA4 implementations, since they're how you connect dataLayer pushes from your site to GA4 event tags in GTM.

  1. 1
    Go to Triggers → New Click the pencil icon to open the trigger configuration panel.
  2. 2
    Choose trigger type: Custom Event Click Trigger Configuration and select Custom Event from the list.
  3. 3
    Enter the event name exactly as it appears in your dataLayer push If your site pushes event: 'form_submit', type form_submit in the Event Name field. Leave Use regex matching unchecked unless you need to match multiple event names with a pattern.
  4. 4
    Set to fire on All Custom Events For a single named event, All Custom Events is fine — the event name field already scopes it precisely. If you need additional conditions (e.g. only fire when form_id equals a specific value), switch to Some Custom Events and add the condition.
  5. 5
    Name and save the trigger Use a name that describes what it listens for: CE - form_submit or Custom Event - Purchase. The prefix makes trigger lists scannable alongside page view and click triggers.

Tags — the code that runs when your trigger fires

A tag is a snippet of code that GTM executes when an assigned trigger fires. In a GA4 implementation, your tags are primarily GA4 Event tags — each one sends a named event with parameters to your GA4 property. But GTM supports dozens of tag types: Meta Pixels, LinkedIn Insight Tags, custom HTML, and more.

Tag types you'll use most often

Tag 01

Google Tag (GA4 Config)

The base GA4 tag. Initialises the GA4 library and sends the initial page_view event. Should fire on All Pages via a Page View trigger. Every GA4 event tag in your container depends on this tag having already loaded.

Tag 02

GA4 Event

Sends a named event to GA4 with optional parameters. This is the tag type you'll create for every custom event — form submissions, button clicks, purchases, scroll depth milestones. Each event tag needs a trigger and optionally references variables for its parameters.

Tag 03

Custom HTML

Runs arbitrary JavaScript. Used for third-party tracking snippets that don't have a native GTM template, for setting cookies, or for pushing values to the data layer from within GTM itself.

Tag 04

Third-party templates

GTM's template gallery includes pre-built tags for Meta Pixel, LinkedIn Insight, Google Ads Conversion Tracking, Hotjar, and many others. These are the easiest way to add common marketing tags without writing custom HTML.

Creating a GA4 Event tag step by step

Here's the complete process for creating a GA4 Event tag that fires when a contact form is submitted — using the trigger and variables we created in the sections above.

  1. 1
    Go to Tags → New Click the pencil icon to open the tag configuration panel.
  2. 2
    Choose tag type: Google Analytics: GA4 Event Click Tag Configuration and select Google Analytics: GA4 Event. This is distinct from the older Universal Analytics tag type — make sure you're selecting the GA4 version.
  3. 3
    Enter your Measurement ID Type your GA4 Measurement ID (format: G-XXXXXXXXXX) in the Measurement ID field. Better practice: use a Constant variable — {{const - GA4 Measurement ID}} — so if the ID ever changes you update one variable, not every tag.
  4. 4
    Enter the Event Name Type the GA4 event name exactly as you want it to appear in your reports. Use a recommended event name where one applies — generate_lead for a contact form, purchase for a transaction. For custom events, follow the lowercase underscore convention.
  5. 5
    Add Event Parameters Click Add Row under Event Parameters to add key-value pairs. The Parameter Name is what appears in GA4 — use GA4's standard parameter names where they exist (form_id, value, currency). The Value is where you reference your variables using double curly braces: {{dlv - form_id}}.
  6. 6
    Assign the trigger Scroll down to the Triggering section and click the + button. Select the trigger you created — CE - form_submit. The tag will now fire every time that Custom Event trigger evaluates to true.
  7. 7
    Name the tag and save Use the naming convention [Platform] - [Tag type] - [Scope]: GA4 - Event - Form Submit. Click Save.

Your complete tag configuration for this form submission example should look like this when assembled:

GTM — GA4 Event tag configuration summary

Tag type:        Google Analytics: GA4 Event
Measurement ID:  {{const - GA4 Measurement ID}}
Event Name:      generate_lead

Event Parameters:
  form_id     →  {{dlv - form_id}}
  form_name   →  {{dlv - form_name}}
  page_path   →  {{Page Path}}

Trigger:         CE - form_submit

When a user submits your contact form, your site pushes event: 'form_submit' to the dataLayer. GTM's Custom Event trigger detects it and fires this tag. The tag sends a generate_lead event to GA4, with the form_id and form_name read from the dataLayer and page_path read from GTM's built-in Page Path variable.


Testing everything in Preview mode

Never publish a GTM container without testing in Preview mode first. GTM Preview lets you walk through your site as a real user while a debug panel shows you every event GTM detects, which tags fired on each event, and the value of every variable at the moment of firing.

  1. 1
    Click Preview in the GTM workspace The Preview button is in the top-right of the GTM interface. Enter your site's URL when prompted and click Connect. A new browser tab opens with your site, and the GTM debug panel appears at the bottom.
  2. 2
    Reproduce the action your tag should fire on Submit the form, click the button, or complete the purchase — whatever the trigger is designed to detect. The left panel in the debug window will log a new event each time GTM detects something.
  3. 3
    Find your event in the left panel and click it Look for the Custom Event matching your dataLayer push — it will be listed by its event name. Click it to inspect what happened on that event.
  4. 4
    Check the Tags tab — confirm your tag shows as Fired Your GA4 Event tag should appear under Tags Fired. If it appears under Tags Not Fired, click the tag name to see which trigger condition failed.
  5. 5
    Check the Variables tab — confirm parameter values are correct Click the Variables tab and scroll to your Data Layer Variables. Confirm dlv - form_id and dlv - form_name are showing the expected values. If a variable shows undefined, the dataLayer key name doesn't match what you configured in the variable.

Verify in GA4 DebugView as well as GTM Preview. GTM Preview confirms the tag fired and the parameters were correct inside GTM. GA4 DebugView (GA4 Admin → DebugView) confirms the event actually arrived in GA4 with the correct structure. Both checks together give you full confidence before publishing — GTM can fire correctly but still send malformed data to GA4 if parameter types are wrong.


Tag sequencing and firing priority

One detail that matters once you have multiple tags: GTM doesn't guarantee the order tags fire when multiple tags share the same trigger. If you have a tag that depends on another tag having run first — for example, a GA4 Event tag that requires the GA4 Config tag to have initialised — you need to control firing order explicitly.

GTM provides two mechanisms for this:

  • Tag Sequencing — in any tag's Advanced Settings, you can specify a Setup Tag that must fire before this tag, and a Cleanup Tag that fires after. Use this to ensure your GA4 Config tag always fires before any GA4 Event tags on the same trigger.
  • Tag Priority — also in Advanced Settings, you can assign a numeric priority. Tags with higher priority numbers fire first. This is a cruder control than sequencing but useful when you need one category of tags to consistently fire before another.

For most GA4 setups, sequencing isn't needed. The GA4 Config tag fires on All Pages via a Page View trigger, which always fires before any Custom Event triggers. By the time a user submits a form or completes a purchase, the Config tag has already loaded GA4. Sequencing becomes relevant when you have tags on the same trigger that depend on each other — which is uncommon in standard GA4 implementations.


Publishing and version control

When your tag is tested and working correctly in Preview, the final step is publishing. In GTM, publishing creates a numbered version — a permanent snapshot of every tag, trigger, and variable in your container at that moment. This version history is your safety net: if a publish breaks something, you can roll back to the previous version in seconds.

  1. 1
    Click Submit in the GTM workspace The Submit button is next to Preview in the top-right. It opens the submission panel where you configure the version details before publishing.
  2. 2
    Fill in the Version Name and Description This is not optional — it's the information you'll rely on when you need to diagnose which publish caused a problem three weeks from now. Use the format YYYY-MM-DD — [what changed]: 2026-07-07 — Add GA4 generate_lead tag for contact form.
  3. 3
    Click Publish GTM deploys the new container version to your site. Changes are live within seconds — no cache to clear, no server deployment required.
  4. 4
    Verify on the live site Open your live site (not Preview mode) and trigger the same action you tested. Confirm the event appears in GA4's Realtime report or DebugView. This live verification step catches any environment-specific issues that Preview didn't surface.

To roll back: go to Versions, find the last working version, and click Publish. In GTM, navigate to Versions in the left sidebar. Each version shows its name, date, and who published it. Click any previous version and hit Publish to make it live instantly — you don't need to undo individual changes. This is why version names matter: you need to know which version was the last good one.


Common mistakes and how to avoid them

The same errors appear in almost every GTM container that hasn't been set up with a clear structure. These are the ones most worth guarding against from the start:

  • Hardcoding Measurement IDs directly in tags. Store your GA4 Measurement ID as a Constant variable and reference it everywhere. When IDs change — and they do — you update one variable rather than hunting through every tag.
  • Using All Pages triggers for event tags. A GA4 Event tag on an All Pages trigger fires on every page load. Unless you genuinely want an event on every page, scope every event tag to a Custom Event trigger or a page-conditioned Page View trigger.
  • Not enabling the Click Variables before using click triggers. GTM's Click Element, Click Classes, Click ID, Click Text, and Click URL variables must be enabled in Built-In Variables before they're available for trigger conditions. Without them, your click conditions evaluate against nothing and silently fail.
  • Mixing event case and format. form_submit, formSubmit, and Form Submit are three different event names as far as GA4 and GTM are concerned. Pick a convention — lowercase underscores, matching GA4's recommended event names — and apply it consistently across your dataLayer pushes and Custom Event triggers.
  • Publishing without a version description. Every single publish should have a name and description. Containers without version notes become unmanageable within months — you can't tell which version introduced a problem without opening each one individually.
  • Deleting old tags instead of archiving them. Deleted tags disappear from version history context. Pause a tag, move it to an Archive folder, and leave it — the audit trail stays intact and it's trivial to recover if you need to reference the configuration later.

Tags, triggers, and variables each have a single job — and once those jobs are clear, building even complex tracking setups in GTM becomes a predictable, repeatable process. The patterns in this guide — variables first, triggers second, tags last, Preview before every publish — apply to every implementation from a single GA4 Config tag to a container with hundreds of events across a dozen platforms.

Need your GTM container built or audited?

We build clean, maintainable GTM containers from scratch and audit existing ones to find misfiring tags, missing events, and structural problems before they affect your data. Book a free 30-minute audit — we'll tell you exactly what's wrong with your current setup and what it would take to fix it.