Session
Created on the first page of a visit and kept in session storage.
{
"session": {
"id": "c2c...",
"timestamp": "2024-01-01T12:00:00Z",
"source": "organic"
}
} Analytics Lab / Tag management
Google Tag Manager reads events from window.dataLayer. Each dataLayer.push() with an
event key is evaluated against the container's triggers, and matching tags fire. The controls on
this page push events; the console on the right shows each push and the trigger that would match it.
Push session, user, and page values before the container snippet loads. Data Layer Variables in GTM can then read them on every event without each tag redefining them.
Created on the first page of a visit and kept in session storage.
{
"session": {
"id": "c2c...",
"timestamp": "2024-01-01T12:00:00Z",
"source": "organic"
}
} Non-identifying traits. Do not push email addresses or other PII.
{
"user": {
"authState": "anonymous",
"persona": "marketer",
"role": null
}
} Describes the current page so reports group it consistently.
{
"page": {
"name": "gtm-sandbox",
"category": "analytics-lab",
"language": "en-US"
}
}
Each event adds an interaction object with the element, module, and any value captured at the
time of the interaction. In GTM, read nested keys with a Data Layer Variable using dot notation, for
example interaction.element.
dataLayer.push({ event: 'cta_click', ... }). GTM merges the keys into its data model.event value. Built-in triggers cover Click (All Elements, Just Links), Form Submission, History Change, Element Visibility, Scroll Depth, and Timer.
Each control carries data-gtm-* attributes. A small script reads them and pushes an event.
Where GA4 has a recommended event name, the example uses it.
Event: cta_click · Trigger: Custom Event
Event: documentation_open · Trigger: Custom Event
Event: generate_lead · Trigger: Custom Event
Push the event after the form validates and submits, not on button click.
Event: nav_select · Trigger: Custom Event
Records which top-level navigation items visitors use.
PricingEvent: search · Trigger: Custom Event
Pushes the search term. In GA4, send it as the search_term parameter.
Event: video_progress · Trigger: Custom Event
Progress events at 10, 25, 50, 75, and 90 percent separate partial views from completions. GA4 uses
the video_percent parameter.
Event: file_download · Trigger: Custom Event
Without a push, a Click - Just Links trigger filtered on Click URL ending in .pdf does the same job.
Event: consent_update · Consent Mode v2
Changing the toggle pushes a custom event and calls gtag('consent', 'update', ...) with
ad_storage, ad_user_data, and ad_personalization.
Event: scroll · Trigger: Custom Event
This marker pushes once when it is fully visible. Without a push, a Scroll Depth trigger set to 90% vertical
does the same. GA4 enhanced measurement sends scroll at 90% by default.
Event: modal_open · Trigger: Custom Event
Tracks the modal opening and the button used to close it.
Modal closed.
Event: accordion_toggle · Trigger: Custom Event
Pushes the open or closed state. Use it to see which questions visitors expand.
Yes. Upgrades apply immediately. Downgrades apply at the next billing date.
Every plan includes a 14-day trial. No card is required.
Accordion collapsed.
Event: tooltip_toggle · Trigger: Custom Event
Records whether the tooltip is shown or hidden, to measure which help text gets used.
Annual billing charges once a year at a 15% discount over monthly billing.
Tooltip hidden.
Event: share · Trigger: Custom Event
Copying a link sends the GA4 share event with method: 'copy'.
Nothing copied yet.
Event: preference_update · Trigger: Custom Event
Switches the preview theme and pushes the previous and new values.
Current theme: Light
Theme set to light.
Events: tutorial_begin / tutorial_step / tutorial_complete
tutorial_begin and tutorial_complete are GA4 recommended events.
tutorial_step is a custom event for the steps between them.
No steps logged.
generate_lead, search, add_to_cart, purchase) where they fit.gtag('consent', 'default', ...) before the container snippet.{ event: 'add_to_cart', ecommerce: { items: [...] } }, and push { ecommerce: null } first so items from the previous event do not carry over.
Place the consent defaults and the container script as high in <head> as possible. Place
the <noscript> iframe immediately after the opening <body> tag. Replace
GTM-XXXXXXX with your container ID.
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Consent Mode v2 defaults. Update them when the visitor makes a choice.
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
wait_for_update: 500
});
</script>
<script>
(function(w,d,s,l,i){
w[l]=w[l]||[];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),
dl=l!='dataLayer'? '&l='+l : '';
j.async=true;
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
</script>
<noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>