Skill Tracer
Skills › Marketing Skills › analytics › gtm-implementation.md

gtm-implementation.md

396 lines · skills/analytics/references/gtm-implementation.md at 88c79f6

Open on GitHub
1# Google Tag Manager Implementation Reference
2
3Detailed guide for implementing tracking via Google Tag Manager.
4

Google Tag Manager Implementation Reference

Detailed guide for implementing tracking via Google Tag Manager.

Raw lines 1 to 4
5## Contents
6- Container Structure (tags, triggers, variables)
7- Naming Conventions
8- Data Layer Patterns
9- Common Tag Configurations (GA4 configuration tag, GA4 event tag, Facebook pixel)
10- Preview and Debug
11- Workspaces and Versioning
12- Consent Management
13- Advanced Patterns (tag sequencing, exception handling, custom JavaScript variables)

Contents

  • Container Structure (tags, triggers, variables)
  • Naming Conventions
  • Data Layer Patterns
  • Common Tag Configurations (GA4 configuration tag, GA4 event tag, Facebook pixel)
  • Preview and Debug
  • Workspaces and Versioning
  • Consent Management
  • Advanced Patterns (tag sequencing, exception handling, custom JavaScript variables)
Raw lines 5 to 14
15## Container Structure

Container Structure

Raw lines 15 to 16
17### Tags
19Tags are code snippets that execute when triggered.
21**Common tag types:**
22- GA4 Configuration (base setup)
23- GA4 Event (custom events)
24- Google Ads Conversion
25- Facebook Pixel
26- LinkedIn Insight Tag
27- Custom HTML (for other pixels)

Tags

Tags are code snippets that execute when triggered.

Common tag types:

  • GA4 Configuration (base setup)
  • GA4 Event (custom events)
  • Google Ads Conversion
  • Facebook Pixel
  • LinkedIn Insight Tag
  • Custom HTML (for other pixels)
Raw lines 17 to 28
29### Triggers
31Triggers define when tags fire.
33**Built-in triggers:**
34- Page View: All Pages, DOM Ready, Window Loaded
35- Click: All Elements, Just Links
36- Form Submission
37- Scroll Depth
38- Timer
39- Element Visibility
41**Custom triggers:**
42- Custom Event (from dataLayer)
43- Trigger Groups (multiple conditions)

Triggers

Triggers define when tags fire.

Built-in triggers:

  • Page View: All Pages, DOM Ready, Window Loaded
  • Click: All Elements, Just Links
  • Form Submission
  • Scroll Depth
  • Timer
  • Element Visibility

Custom triggers:

  • Custom Event (from dataLayer)
  • Trigger Groups (multiple conditions)
Raw lines 29 to 44
45### Variables
47Variables capture dynamic values.
49**Built-in (enable as needed):**
50- Click Text, Click URL, Click ID, Click Classes
51- Page Path, Page URL, Page Hostname
52- Referrer
53- Form Element, Form ID
55**User-defined:**
56- Data Layer variables
57- JavaScript variables
58- Lookup tables
59- RegEx tables
60- Constants
62---

Variables

Variables capture dynamic values.

Built-in (enable as needed):

  • Click Text, Click URL, Click ID, Click Classes
  • Page Path, Page URL, Page Hostname
  • Referrer
  • Form Element, Form ID

User-defined:

  • Data Layer variables
  • JavaScript variables
  • Lookup tables
  • RegEx tables
  • Constants

Raw lines 45 to 63
64## Naming Conventions

Naming Conventions

Raw lines 64 to 65
66### Recommended Format
68```
69[Type] - [Description] - [Detail]
71Tags:
72GA4 - Event - Signup Completed
73GA4 - Config - Base Configuration
74FB - Pixel - Page View
75HTML - LiveChat Widget
77Triggers:
78Click - CTA Button
79Submit - Contact Form
80View - Pricing Page
81Custom - signup_completed
83Variables:
84DL - user_id
85JS - Current Timestamp
86LT - Campaign Source Map
87```
89---

Recommended Format

[Type] - [Description] - [Detail]

Tags:
GA4 - Event - Signup Completed
GA4 - Config - Base Configuration
FB - Pixel - Page View
HTML - LiveChat Widget

Triggers:
Click - CTA Button
Submit - Contact Form
View - Pricing Page
Custom - signup_completed

Variables:
DL - user_id
JS - Current Timestamp
LT - Campaign Source Map

Raw lines 66 to 90
91## Data Layer Patterns

Data Layer Patterns

Raw lines 91 to 92
93### Basic Structure
95```javascript
96// Initialize (in <head> before GTM)
97window.dataLayer = window.dataLayer || [];
99// Push event
100dataLayer.push({
101 'event': 'event_name',
102 'property1': 'value1',
103 'property2': 'value2'
104});
105```

Basic Structure

// Initialize (in <head> before GTM)
window.dataLayer = window.dataLayer || [];

// Push event
dataLayer.push({
  'event': 'event_name',
  'property1': 'value1',
  'property2': 'value2'
});
Raw lines 93 to 106
107### Page Load Data
109```javascript
110// Set on page load (before GTM container)
111window.dataLayer = window.dataLayer || [];
112dataLayer.push({
113 'pageType': 'product',
114 'contentGroup': 'products',
115 'user': {
116 'loggedIn': true,
117 'userId': '12345',
118 'userType': 'premium'
119 }
120});
121```

Page Load Data

// Set on page load (before GTM container)
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  'pageType': 'product',
  'contentGroup': 'products',
  'user': {
    'loggedIn': true,
    'userId': '12345',
    'userType': 'premium'
  }
});
Raw lines 107 to 122
123### Form Submission
125```javascript
126document.querySelector('#contact-form').addEventListener('submit', function() {
127 dataLayer.push({
128 'event': 'form_submitted',
129 'formName': 'contact',
130 'formLocation': 'footer'
131 });
132});
133```

Form Submission

document.querySelector('#contact-form').addEventListener('submit', function() {
  dataLayer.push({
    'event': 'form_submitted',
    'formName': 'contact',
    'formLocation': 'footer'
  });
});
Raw lines 123 to 134
135### Button Click
137```javascript
138document.querySelector('.cta-button').addEventListener('click', function() {
139 dataLayer.push({
140 'event': 'cta_clicked',
141 'ctaText': this.innerText,
142 'ctaLocation': 'hero'
143 });
144});
145```

Button Click

document.querySelector('.cta-button').addEventListener('click', function() {
  dataLayer.push({
    'event': 'cta_clicked',
    'ctaText': this.innerText,
    'ctaLocation': 'hero'
  });
});
Raw lines 135 to 146
147### E-commerce Events
149```javascript
150// Product view
151dataLayer.push({ ecommerce: null }); // Clear previous
152dataLayer.push({
153 'event': 'view_item',
154 'ecommerce': {
155 'items': [{
156 'item_id': 'SKU123',
157 'item_name': 'Product Name',
158 'price': 99.99,
159 'item_category': 'Category',
160 'quantity': 1
161 }]
162 }
163});
165// Add to cart
166dataLayer.push({ ecommerce: null });
167dataLayer.push({
168 'event': 'add_to_cart',
169 'ecommerce': {
170 'items': [{
171 'item_id': 'SKU123',
172 'item_name': 'Product Name',
173 'price': 99.99,
174 'quantity': 1
175 }]
176 }
177});
179// Purchase
180dataLayer.push({ ecommerce: null });
181dataLayer.push({
182 'event': 'purchase',
183 'ecommerce': {
184 'transaction_id': 'T12345',
185 'value': 99.99,
186 'currency': 'USD',
187 'tax': 5.00,
188 'shipping': 10.00,
189 'items': [{
190 'item_id': 'SKU123',
191 'item_name': 'Product Name',
192 'price': 99.99,
193 'quantity': 1
194 }]
195 }
196});
197```
199---

E-commerce Events

// Product view
dataLayer.push({ ecommerce: null }); // Clear previous
dataLayer.push({
  'event': 'view_item',
  'ecommerce': {
    'items': [{
      'item_id': 'SKU123',
      'item_name': 'Product Name',
      'price': 99.99,
      'item_category': 'Category',
      'quantity': 1
    }]
  }
});

// Add to cart
dataLayer.push({ ecommerce: null });
dataLayer.push({
  'event': 'add_to_cart',
  'ecommerce': {
    'items': [{
      'item_id': 'SKU123',
      'item_name': 'Product Name',
      'price': 99.99,
      'quantity': 1
    }]
  }
});

// Purchase
dataLayer.push({ ecommerce: null });
dataLayer.push({
  'event': 'purchase',
  'ecommerce': {
    'transaction_id': 'T12345',
    'value': 99.99,
    'currency': 'USD',
    'tax': 5.00,
    'shipping': 10.00,
    'items': [{
      'item_id': 'SKU123',
      'item_name': 'Product Name',
      'price': 99.99,
      'quantity': 1
    }]
  }
});

Raw lines 147 to 200
201## Common Tag Configurations

Common Tag Configurations

Raw lines 201 to 202
203### GA4 Configuration Tag
205**Tag Type:** Google Analytics: GA4 Configuration
207**Settings:**
208- Measurement ID: G-XXXXXXXX
209- Send page view: Checked (for pageviews)
210- User Properties: Add any user-level dimensions
212**Trigger:** All Pages

GA4 Configuration Tag

Tag Type: Google Analytics: GA4 Configuration

Settings:

  • Measurement ID: G-XXXXXXXX
  • Send page view: Checked (for pageviews)
  • User Properties: Add any user-level dimensions

Trigger: All Pages

Raw lines 203 to 213
214### GA4 Event Tag
216**Tag Type:** Google Analytics: GA4 Event
218**Settings:**
219- Configuration Tag: Select your config tag
220- Event Name: {{DL - event_name}} or hardcode
221- Event Parameters: Add parameters from dataLayer
223**Trigger:** Custom Event with event name match

GA4 Event Tag

Tag Type: Google Analytics: GA4 Event

Settings:

  • Configuration Tag: Select your config tag
  • Event Name: {{DL - event_name}} or hardcode
  • Event Parameters: Add parameters from dataLayer

Trigger: Custom Event with event name match

Raw lines 214 to 224
225### Facebook Pixel - Base
227**Tag Type:** Custom HTML
229```html
230<script>
231 !function(f,b,e,v,n,t,s)
232 {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
233 n.callMethod.apply(n,arguments):n.queue.push(arguments)};
234 if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
235 n.queue=[];t=b.createElement(e);t.async=!0;
236 t.src=v;s=b.getElementsByTagName(e)[0];
237 s.parentNode.insertBefore(t,s)}(window, document,'script',
238 'https://connect.facebook.net/en_US/fbevents.js');
239 fbq('init', 'YOUR_PIXEL_ID');
240 fbq('track', 'PageView');
241</script>
242```
244**Trigger:** All Pages

Facebook Pixel - Base

Tag Type: Custom HTML

<script>
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
  n.callMethod.apply(n,arguments):n.queue.push(arguments)};
  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
  n.queue=[];t=b.createElement(e);t.async=!0;
  t.src=v;s=b.getElementsByTagName(e)[0];
  s.parentNode.insertBefore(t,s)}(window, document,'script',
  'https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', 'YOUR_PIXEL_ID');
  fbq('track', 'PageView');
</script>

Trigger: All Pages

Raw lines 225 to 245
246### Facebook Pixel - Event
248**Tag Type:** Custom HTML
250```html
251<script>
252 fbq('track', 'Lead', {
253 content_name: '{{DL - form_name}}'
254 });
255</script>
256```
258**Trigger:** Custom Event - form_submitted
260---

Facebook Pixel - Event

Tag Type: Custom HTML

<script>
  fbq('track', 'Lead', {
    content_name: '{{DL - form_name}}'
  });
</script>

Trigger: Custom Event - form_submitted


Raw lines 246 to 261
262## Preview and Debug

Preview and Debug

Raw lines 262 to 263
264### Preview Mode
2661. Click "Preview" in GTM
2672. Enter site URL
2683. GTM debug panel opens at bottom
270**What to check:**
271- Tags fired on this event
272- Tags not fired (and why)
273- Variables and their values
274- Data layer contents

Preview Mode

  1. Click "Preview" in GTM
  2. Enter site URL
  3. GTM debug panel opens at bottom

What to check:

  • Tags fired on this event
  • Tags not fired (and why)
  • Variables and their values
  • Data layer contents
Raw lines 264 to 275
276### Debug Tips
278**Tag not firing:**
279- Check trigger conditions
280- Verify data layer push
281- Check tag sequencing
283**Wrong variable value:**
284- Check data layer structure
285- Verify variable path (nested objects)
286- Check timing (data may not exist yet)
288**Multiple firings:**
289- Check trigger uniqueness
290- Look for duplicate tags
291- Check tag firing options
293---

Debug Tips

Tag not firing:

  • Check trigger conditions
  • Verify data layer push
  • Check tag sequencing

Wrong variable value:

  • Check data layer structure
  • Verify variable path (nested objects)
  • Check timing (data may not exist yet)

Multiple firings:

  • Check trigger uniqueness
  • Look for duplicate tags
  • Check tag firing options

Raw lines 276 to 294
295## Workspaces and Versioning

Workspaces and Versioning

Raw lines 295 to 296
297### Workspaces
299Use workspaces for team collaboration:
300- Default workspace for production
301- Separate workspaces for large changes
302- Merge when ready

Workspaces

Use workspaces for team collaboration:

  • Default workspace for production
  • Separate workspaces for large changes
  • Merge when ready
Raw lines 297 to 303
304### Version Management
306**Best practices:**
307- Name every version descriptively
308- Add notes explaining changes
309- Review changes before publish
310- Keep production version noted
312**Version notes example:**
313```
314v15: Added purchase conversion tracking
315- New tag: GA4 - Event - Purchase
316- New trigger: Custom Event - purchase
317- New variables: DL - transaction_id, DL - value
318- Tested: Chrome, Safari, Mobile
319```
321---

Version Management

Best practices:

  • Name every version descriptively
  • Add notes explaining changes
  • Review changes before publish
  • Keep production version noted

Version notes example:

v15: Added purchase conversion tracking
- New tag: GA4 - Event - Purchase
- New trigger: Custom Event - purchase
- New variables: DL - transaction_id, DL - value
- Tested: Chrome, Safari, Mobile

Raw lines 304 to 322
323## Consent Management

Consent Management

Raw lines 323 to 324
325### Consent Mode Integration
327```javascript
328// Default state (before consent)
329gtag('consent', 'default', {
330 'analytics_storage': 'denied',
331 'ad_storage': 'denied'
332});
334// Update on consent
335function grantConsent() {
336 gtag('consent', 'update', {
337 'analytics_storage': 'granted',
338 'ad_storage': 'granted'
339 });
341```

Consent Mode Integration

// Default state (before consent)
gtag('consent', 'default', {
  'analytics_storage': 'denied',
  'ad_storage': 'denied'
});

// Update on consent
function grantConsent() {
  gtag('consent', 'update', {
    'analytics_storage': 'granted',
    'ad_storage': 'granted'
  });
}
Raw lines 325 to 342
343### GTM Consent Overview
3451. Enable Consent Overview in Admin
3462. Configure consent for each tag
3473. Tags respect consent state automatically
349---

GTM Consent Overview

  1. Enable Consent Overview in Admin
  2. Configure consent for each tag
  3. Tags respect consent state automatically

Raw lines 343 to 350
351## Advanced Patterns

Advanced Patterns

Raw lines 351 to 352
353### Tag Sequencing
355**Setup tags to fire in order:**
356Tag Configuration > Advanced Settings > Tag Sequencing
358**Use cases:**
359- Config tag before event tags
360- Pixel initialization before tracking
361- Cleanup after conversion

Tag Sequencing

Setup tags to fire in order: Tag Configuration > Advanced Settings > Tag Sequencing

Use cases:

  • Config tag before event tags
  • Pixel initialization before tracking
  • Cleanup after conversion
Raw lines 353 to 362
363### Exception Handling
365**Trigger exceptions** - Prevent tag from firing:
366- Exclude certain pages
367- Exclude internal traffic
368- Exclude during testing

Exception Handling

Trigger exceptions - Prevent tag from firing:

  • Exclude certain pages
  • Exclude internal traffic
  • Exclude during testing
Raw lines 363 to 369
370### Custom JavaScript Variables
372```javascript
373// Get URL parameter
374function() {
375 var params = new URLSearchParams(window.location.search);
376 return params.get('campaign') || '(not set)';
379// Get cookie value
380function() {
381 var match = document.cookie.match('(^|;) ?user_id=([^;]*)(;|$)');
382 return match ? match[2] : null;
385// Read a machine-readable amount, not the localized display text.
386// Example: <span class="product-price" data-price="1234.56">$1,234.56</span>
387function() {
388 var el = document.querySelector('.product-price');
389 var raw = el ? el.getAttribute('data-price') : null;
390 if (raw === null || !/^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/.test(raw)) return null;
391 var amount = Number(raw);
392 return isFinite(amount) ? amount : null;
394```
396For monetary tracking, prefer the numeric amount and currency from the application data layer. If a DOM variable is needed, have the application render `data-price` as an unformatted, non-negative decimal in major currency units; pass its currency separately. Do not infer the amount or currency from presentation text: `parseFloat` turns `$1,234.56` into `1` after removing `$`, and localized separators have different meanings. A missing or invalid amount returns `null`, so skip that monetary event or diagnose it before sending; reserve `0` for an explicitly free item.

Custom JavaScript Variables

// Get URL parameter
function() {
  var params = new URLSearchParams(window.location.search);
  return params.get('campaign') || '(not set)';
}

// Get cookie value
function() {
  var match = document.cookie.match('(^|;) ?user_id=([^;]*)(;|$)');
  return match ? match[2] : null;
}

// Read a machine-readable amount, not the localized display text.
// Example: <span class="product-price" data-price="1234.56">$1,234.56</span>
function() {
  var el = document.querySelector('.product-price');
  var raw = el ? el.getAttribute('data-price') : null;
  if (raw === null || !/^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/.test(raw)) return null;
  var amount = Number(raw);
  return isFinite(amount) ? amount : null;
}

For monetary tracking, prefer the numeric amount and currency from the application data layer. If a DOM variable is needed, have the application render data-price as an unformatted, non-negative decimal in major currency units; pass its currency separately. Do not infer the amount or currency from presentation text: parseFloat turns $1,234.56 into 1 after removing $, and localized separators have different meanings. A missing or invalid amount returns null, so skip that monetary event or diagnose it before sending; reserve 0 for an explicitly free item.

Raw lines 370 to 396