Skip to content

Built-in Variables

GTM ships with a set of pre-built variables that automatically capture common browser values — page URLs, click targets, form data, video progress, and more. You do not write any code to use them. You enable the ones you need, and they become available in trigger conditions and tag configurations.

The catch: most built-in variables are disabled by default to keep your container lean. You have to turn them on before they work. This guide covers every built-in variable category, what each one returns, and which ones you should enable on every new container.

  1. In your GTM container, click Variables in the left navigation.
  2. In the “Built-In Variables” section at the top, click Configure.
  3. A panel slides in showing every available built-in variable organized by category.
  4. Check the box next to any variable to enable it.
  5. Click the X to close. Enabled variables are now available in triggers and tags.

These variables capture information about the current page URL. They are enabled by default in new containers.

VariableWhat it returnsExample
Page URLFull URL including protocol, hostname, path, query, and fragmenthttps://example.com/products?color=blue#reviews
Page HostnameJust the domain (no protocol, no path)example.com
Page PathThe path component only/products
Page ReferrerThe URL of the previous page (empty on direct visits)https://google.com/search?q=...

Page Path is the most-used variable in the set. You will use it constantly in trigger conditions: “fire this tag only when Page Path contains /checkout.”

Page Hostname is essential for multi-domain setups where you need to filter by domain, and for cross-domain tracking conditions.

Page Referrer behaves exactly like document.referrer in JavaScript — it is empty on direct visits, on the first page after clicking a link from a different origin (same-origin referrers show the referring page path), and on pages loaded from bookmarks.

VariableWhat it returns
EventThe name of the current GTM event (e.g., gtm.click, purchase, your custom event name)
Container IDYour GTM container ID in GTM-XXXXXXX format
Container VersionThe version number of the published container
Random NumberA random integer — useful for cache busting and sampling
HTML IDAn alias for Container ID, legacy name
Debug ModeReturns true when the container is running in Preview mode, false otherwise

Event is critical for trigger conditions. It returns the event name exactly as it was pushed to the dataLayer, or the name of built-in GTM events like gtm.js (page load), gtm.dom (DOM ready), gtm.load (window load), gtm.click, gtm.linkClick, gtm.formSubmit.

Debug Mode is useful for conditional logic in Custom JavaScript variables — return test values when in debug mode, real values in production.

These variables capture information about whatever element was clicked when a click trigger fires.

VariableWhat it returnsExample
Click ElementThe DOM element that was clicked (as a JavaScript object)<button class="add-to-cart" data-product-id="123">
Click ClassesSpace-separated string of CSS classes on the clicked elementadd-to-cart btn btn-primary
Click IDThe id attribute of the clicked elementsubmit-button
Click TargetThe target attribute (e.g., _blank for new-tab links)_blank
Click URLThe href attribute if clicked element is or contains a linkhttps://example.com/product
Click TextThe visible text content of the clicked elementAdd to Cart

Click Element is the most powerful of these. It gives you the raw DOM node, which you can then use in Custom JavaScript variables to walk up the DOM tree, read data-* attributes, or check parent elements. For example, if the user clicks a product image inside a card that has the product ID as a data-* attribute on the card’s outer <div>, you can use {{Click Element}}.closest('[data-product-id]').dataset.productId.

Click Classes is often used in trigger conditions to match clicks on specific styled elements. This works, but it is fragile — CSS classes change when developers redesign the UI. Prefer data-* attribute selectors when possible.

Enable all six click variables. In trigger conditions, you will use them constantly for testing in Preview mode even when your production triggers use dataLayer variables.

These populate when GTM’s built-in Form Submission trigger fires.

VariableWhat it returns
Form ElementThe <form> DOM element that was submitted
Form ClassesCSS classes on the form element
Form IDThe id attribute of the form
Form TargetThe target attribute of the form
Form URLThe action attribute of the form
Form TextThe text content of the form (rarely useful)

These populate when an uncaught JavaScript error occurs on the page. They fire on the gtm.pageError event.

VariableWhat it returns
Error MessageThe error message string
Error URLThe URL of the script where the error occurred
Error LineThe line number of the error

To use error variables, you need a trigger listening for the gtm.pageError event (create a Custom Event trigger with event name gtm.pageError, or use the JavaScript Error built-in trigger type). Then create a GA4 Event tag that fires on that trigger using these variables as parameters.

This is a quick way to set up client-side error tracking without writing any code. It only captures uncaught errors — try/catch blocks and handled rejections will not be reported.

These fire when the browser’s history API changes — which is how single-page applications (SPAs) handle navigation.

VariableWhat it returns
New History FragmentThe hash fragment after the URL change
Old History FragmentThe hash fragment before the URL change
New History StateThe state object passed to pushState() or replaceState()
Old History StateThe previous state object
History SourceEither pushState, replaceState, or popstate

History variables are used with the History Change trigger to track virtual pageviews in SPAs. History Source is particularly useful — popstate fires when the user hits back/forward, while pushState fires on new navigation. You often want to treat these differently.

These populate when YouTube video interactions occur, provided you have the YouTube Video trigger enabled and enableJsApi=1 is on your embedded YouTube players.

VariableWhat it returns
Video ProviderAlways YouTube for built-in video triggers
Video StatusThe playback state: started, paused, ended, progress
Video URLThe full YouTube video URL
Video TitleThe video title from YouTube’s API
Video DurationTotal duration in seconds
Video Current TimeCurrent playback position in seconds
Video PercentCurrent playback position as a percentage (0–100)
Video VisibleWhether the video was visible in the viewport when the event fired

Configure the YouTube Video trigger to fire at specific progress thresholds (25%, 50%, 75%, 100%) and Video Percent will contain the threshold that was crossed, not the exact position. Use Video Current Time if you need precision.

These populate when a Scroll Depth trigger fires.

VariableWhat it returns
Scroll Depth ThresholdThe percentage or pixel depth that triggered the event
Scroll Depth UnitsEither Pixels or Percent depending on your trigger configuration
Scroll DirectionEither vertical or horizontal

The Scroll Depth trigger has a threshold configuration where you specify values like 25,50,75,100. When the user scrolls past 25%, the trigger fires and Scroll Depth Threshold returns 25. This makes it easy to create a single GA4 Event tag for all scroll depths with {{Scroll Depth Threshold}} as the percent_scrolled parameter value.

These populate when an Element Visibility trigger fires.

VariableWhat it returns
Percent VisibleHow much of the element is visible (0–100)
On-Screen DurationHow long the element has been visible in milliseconds

Use these to track when specific elements come into view — hero banners, product recommendations, call-to-action sections, or above-the-fold/below-the-fold distinctions. On-Screen Duration requires configuring a minimum visible duration in your Element Visibility trigger.

Which variables to enable on every new container

Section titled “Which variables to enable on every new container”

Here is the baseline configuration every container should have from day one:

Always enable:

  • All Page variables (usually already enabled)
  • All Click variables (6 variables)
  • All Form variables (6 variables)
  • Event (utility)
  • Debug Mode (utility)
  • Container ID (utility)

Enable when you need them:

  • Error variables — when setting up error tracking
  • History variables — when working on SPAs
  • Video variables — when tracking YouTube embeds
  • Scroll variables — when adding scroll depth tracking
  • Visibility variables — when tracking element impressions

The practical rule: If you are not sure, enable it. Unused built-in variables do not meaningfully impact container size or performance. The cost of needing a variable in Preview mode and not having it enabled is wasted debugging time.

Page URL returns the full URL: https://example.com/products?sort=price. If you write a trigger condition “Page URL contains /products”, it will match — but so will Page URL contains productsmatchinghttps://products-store.example.com/`. Use Page Path for path-based conditions — it is more precise.

Using Click Text when Click Element is more reliable

Section titled “Using Click Text when Click Element is more reliable”

Click Text captures the visible text content of the clicked element. This sounds useful, but it breaks in two common scenarios: (1) icon buttons with no text, and (2) buttons where the text might be translated or changed for A/B tests. Use Click Element and read a data-* attribute from the DOM instead.

Expecting Form variables to work with React forms

Section titled “Expecting Form variables to work with React forms”

React-controlled forms do not fire the browser’s native submit event in the way GTM expects. The Form Submission trigger and its associated variables will not work. Push a custom event to the dataLayer in your React submit handler instead.