Google Tag Manager has a short list of trigger types and a short list of variable types, and nearly every tracking requirement is some combination of them. This guide is the reference I wish I had when I started: each trigger type, what it is good for, the variables that pair with it, and the patterns I set up on almost every site.
Enable the Built-In Variables First
In Variables, click Configure and enable: Page URL, Page Path, Page Hostname, Referrer; Click Element, Click Classes, Click ID, Click Target, Click URL, Click Text; Form Element, Form ID, Form Classes, Form URL; Scroll Depth Threshold, Scroll Direction; Percent Visible, On-Screen Duration; Video Provider, Video Status, Video Percent, Video Title. These are free; triggers cannot use them until they are on.
Trigger Types and When to Use Them
| Trigger | Fires when | Use it for |
|---|---|---|
| Consent Initialization | Before anything else | Consent platform tags only |
| Initialization | Before page view triggers | Google tag, base pixels |
| Page View | GTM loads | Standard page tags |
| DOM Ready | HTML parsed | Tags that read page elements |
| Window Loaded | Everything loaded | Listeners that depend on other scripts |
| Click, All Elements | Any click | Buttons, non-link elements |
| Click, Just Links | Click on an anchor | Outbound, downloads, phone, email links |
| Element Visibility | An element is on screen | Success messages, sections viewed, CTAs seen |
| Form Submission | Browser submit event | Only with validation; prefer dataLayer |
| Scroll Depth | Percent or pixel thresholds | Content engagement |
| YouTube Video | Embedded YouTube events | Play, progress, complete |
| Timer | Interval elapsed | Time on page milestones |
| History Change | URL changes without reload | Single page apps |
| JavaScript Error | Uncaught error | Monitoring |
| Custom Event | dataLayer push with event key | Every business event |
| Trigger Group | Several triggers have all fired | Combined conditions |
Variable Types and When to Use Them
| Variable | Returns | Use it for |
|---|---|---|
| Data Layer Variable | A key from the dataLayer | Everything the site pushes |
| URL | Parts of the current URL or query parameters | Campaign parameters, thank-you page form parameter |
| First-Party Cookie | A cookie value | gclid storage, consent state, user flags |
| DOM Element | Text or attribute of an element | Reading page data when no dataLayer exists |
| Auto-Event Variable | Click or form element attributes | Rarely needed beyond built-ins |
| Lookup Table and RegEx Table | Mapped values | Page path to section, form ID to form name, event to conversion label |
| Custom JavaScript | Anything computed | Business hours, mapping arrays, normalising values |
| JavaScript Variable | A global JS variable | Reading values the site exposes on window |
| Constant | A fixed string | Measurement IDs, conversion IDs |
| Google Analytics Settings and User-Provided Data | Grouped config | Shared GA4 settings, Enhanced Conversions |
Patterns That Belong on Almost Every Site
Outbound link clicks
Trigger: Click, Just Links. Condition: Click URL does not contain your hostname, and Click URL starts with http. Tag: GA4 Event click with link_url set to Click URL and link_text to Click Text. Enhanced measurement does this too; if it is on, skip this.
File downloads
Trigger: Click, Just Links. Condition: Click URL matches RegEx \.(pdf|docx?|xlsx?|pptx?|zip|csv)$. Tag: GA4 Event file_download with file_name from a Custom JavaScript variable that returns the last path segment.
Phone and email clicks
Trigger: Click, Just Links. Condition: Click URL starts with tel:. Tag: GA4 Event phone_click with phone_location from a Lookup Table keyed on Click Classes or a parent section. A second trigger for mailto: and an email_click event. Add Google Ads conversion tags on the phone trigger where calls matter.
Button clicks that are not links
Trigger: Click, All Elements. Condition: Click Element matches CSS selector button.cta, button.cta *, a.btn-primary, a.btn-primary *. Tag: GA4 Event cta_click with cta_text from Click Text.
Where you can, ask for data-track attributes on the buttons, for example data-track="hero_cta", and read them with an Auto-Event Variable or DOM Element variable. Classes change; data attributes survive redesigns.
Section or CTA viewed
Trigger: Element Visibility, CSS selector #pricing, once per page, 50 percent visible, observe DOM changes. Tag: GA4 Event section_view with section_id set to the selector.
Scroll depth
Trigger: Scroll Depth, vertical percentages 25, 50, 75, 90. Tag: GA4 Event scroll_depth with percent_scrolled from Scroll Depth Threshold. Enhanced measurement covers 90 percent only; use this if you want the curve. Fire only on content pages with a Page Path condition to avoid noise.
Time on page milestones
Trigger: Timer, interval 30000 ms, limit 4, on content pages. Tag: GA4 Event time_on_page with the elapsed seconds from a Custom JavaScript variable that reads the timer's event number. Useful for content sites; skip elsewhere.
Single page app page views
Trigger: History Change. Tag: GA4 Event page_view with page_location and page_title. Set the Google tag to not send its own page view. See the SPA guide for the full approach.
Trigger Conditions That Save You
Page Path matches RegEx ^/blog/to scope content triggers.Click URL does not containyour domain to isolate outbound links.Form ID equalsto isolate one form.Percent Visible greater than 50to require real visibility.- Exceptions: add a blocking trigger, for example a Page View on
/adminto stop everything on admin pages.
Folders and Naming
Prefix by type so the list sorts: GA4 - Event - phone_click, GAds - Conversion - Lead, Meta - Lead, CE - form_submit_success, Click - tel link, dlv - form_name, LT - form id to name. Put each client's or each platform's assets in a folder. The GTM Container Hygiene guide on this site goes further.
Test Every Trigger
In Preview, perform the action and watch the left column. Click the event, open the Variables tab and confirm the values the trigger needed. Then open the tag and confirm it fired once. A trigger that fires on every click, or never, is almost always a condition with a typo or an element selector that is too broad or too narrow.
Outcome
With built-in variables on, a handful of well-scoped triggers, and the dataLayer for business events, you can track nearly any interaction on a site without touching its code, and you will know exactly why each event fired.
