Variables in Google Tag Manager are containers that hold values — a page URL, a click text, a product price, a user ID. They're used inside tags (to send data) and triggers (to decide when tags fire). Understanding variables is the difference between basic GTM usage and precise, powerful tracking.
The Three Types of GTM Variables
GTM organizes variables into three categories based on where they come from and who defines them. Understanding the distinction is foundational — nearly every tracking bug we see in GTM audits traces back to a team using the wrong variable type for the job. Built-in variables are the fastest path to capturing basic page and interaction data, user-defined variables handle anything custom, and event data variables are exclusive to server-side containers.
- Built-In Variables: Pre-configured by Google. Capture page URL, click data, form data, video interactions, scroll depth. Must be enabled in Variables → Configure before they can be used in tags or triggers.
- User-Defined Variables: Custom variables you create. Nine subtypes — the most important are Data Layer, Custom JavaScript, Lookup Table, and 1st Party Cookie.
- Event Data Variables: Used only in server-side GTM to read event data forwarded from the client container. You won't encounter these until you've set up a server container.
Built-In Variables You Should Always Enable
GTM ships with ~30 built-in variables, but most are disabled by default to keep the variable list clean. Enable the ones below in every container you create — they cover roughly 80% of real-world tracking needs and cost nothing to leave on. Go to Variables → Configure at the top-right of the Variables page, tick the checkboxes, close the dialog.
- Page Variables: Page URL, Page Hostname, Page Path, Referrer — used in almost every tag.
- Click Variables: Click Element, Click Classes, Click ID, Click URL, Click Text — required for no-code click tracking.
- Form Variables: Form Element, Form Classes, Form ID, Form URL — required for form submission triggers.
- Scroll Variables: Scroll Depth Threshold, Scroll Depth Units — needed for custom scroll tracking beyond the default 90%.
- Utility: Container ID, Container Version, Debug Mode, HTML ID — invaluable for debugging and conditional tag firing.
User-Defined Variable Types: Data Layer Variable
The Data Layer Variable is the single most important user-defined variable type and should be your default choice for reading any custom value from the page. It reads values from the window.dataLayer object — a global array that both the GTM snippet and your site's code can push into. Data Layer Variables are the GTM team's recommended pattern because they respect event timing, survive SPA navigation better than DOM reads, and make your tracking independent of HTML structure.
If your developer pushes dataLayer.push({event: 'purchase', user_type: 'premium', cart_value: 129.50}), you create three Data Layer Variables (one per key) to access those values in tags. Two configuration details catch teams:
- Data Layer Version: Leave as "Version 2" — Version 1 is legacy and handles nested objects poorly.
- Default Value: Set a sensible fallback (e.g., empty string) so downstream tags don't receive
undefined.
User-Defined Variable Types: JavaScript, Custom JavaScript, DOM Element
Three variable types read data directly from the page rather than the data layer. Each has a specific use case, and each has a specific failure mode. In general, prefer Data Layer Variables whenever possible — these three types are more fragile because they depend on the site's current HTML or JavaScript state at the moment the variable is evaluated.
- JavaScript Variable: Reads a global JavaScript variable. Example: if your site sets
window.userId = '12345', a JavaScript Variable with keyuserIdcaptures it. ⚠️ Reads at evaluation time, so timing-sensitive values can be empty. - Custom JavaScript: Runs an anonymous function and returns the result. Useful for computed values like extracting a product ID from a URL path or formatting a date. Wrap in
function() { return ...; }. - DOM Element: Reads an HTML element's content by ID or CSS selector. Use sparingly — DOM reads are the most fragile variable type and break whenever a developer tweaks markup.
User-Defined Variable Types: Lookup Table, RegExp Table, 1st Party Cookie
These three variable types handle mapping and storage scenarios that the others don't cover well. Lookup tables turn raw values into human-readable categories; regex tables do the same for pattern-matched values; first-party cookie variables read persistent state from the browser without JavaScript.
- Lookup Table: Maps exact input values to output values. Example: map page paths to content categories —
/blog/*(exact path start) → "Blog,"/products/*→ "Products." Ideal for enriching GA4 events with human-readable labels. - RegExp Table: Like Lookup Table but with RE2 regex pattern matching. More powerful when exact matches aren't possible — e.g., matching any product page under
^/products/([^/]+)/. - 1st Party Cookie: Reads a first-party cookie value by name. Useful for grabbing consent status (
_consent_v2), A/B test variants, or user preferences stored in cookies by your CMS or consent manager.
5 Must-Have Custom Variables for Every Container
These five custom variables are the ones we add to nearly every GTM container we set up or audit. They dramatically improve GA4 reporting quality by creating reliable dimensions you can filter, segment, and compare on. Set them up once at the start of a project and they'll power dozens of tags downstream without further maintenance.
- Content Group Variable: Lookup Table mapping page paths to content categories (Blog, Product, Support, Legal, Account).
- Logged-In Status: Data Layer Variable reading
user_logged_in(true/false) — required for segmenting logged-in vs anonymous sessions. - User Type: Data Layer Variable reading
user_type(free, premium, enterprise) — essential for SaaS analytics. - Page Type: Lookup Table or Custom JavaScript categorizing pages (homepage, PDP, PLP, checkout, thank-you).
- Debug Mode Flag: Custom JavaScript that returns true when URL contains
?debug=true. Use this in tag conditions to silence noisy tags during QA.
Variable Scoping and Timing: Why Your Variables Are Sometimes Empty
The #1 GTM bug we debug on client audits is a variable returning empty or undefined when it should have a value. This almost always comes down to timing: variables are evaluated at the moment they're needed (when the tag fires), not when they're defined. If your dataLayer.push happens after the tag fires, the Data Layer Variable reads empty. The fix is to gate the tag on a custom event trigger that only fires after the data is available.
- Developer pushes event:
dataLayer.push({event: 'user_data_ready', user_type: 'premium'})as soon as user data loads. - Create a Custom Event trigger in GTM for
user_data_ready. - Attach your tag to this custom event trigger (not Page View, not DOM Ready).
- Now the Data Layer Variable is guaranteed to have a value because the event is only dispatched once the data exists.
GTM Variable Check
NiceLookingData audits your GTM container for orphaned variables, data layer configuration issues, and missing variable connections. Run a free GTM audit.
Check your GTM container for free
Upload your GTM export or connect live. Our auditor checks 53 best practices and gives you actionable fixes.
