一键导入
gtm-setup
GTM Event Tracking & Setup Reference — dataLayer fundamentals, trigger types, variable types, GA4 tag configuration, debug mode, and best practices
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
GTM Event Tracking & Setup Reference — dataLayer fundamentals, trigger types, variable types, GA4 tag configuration, debug mode, and best practices
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Submit an AI agent to the agentlaunch directory and upvote agents via a public no-auth REST API
Comprehensive Google Ads account audit — campaign structure, budget pacing, conversion tracking, wasted spend — across every campaign type, ranked by estimated $ impact
Google Ads Demand Gen audit — audience strategy, creative format diversity, creative freshness, placements, CPA vs goal
Google Analytics 4 configuration and data-quality audit — key events, data streams, custom dimensions, attribution, retention, PII, Ads link, BigQuery export
Build a GA4 measurement plan from a site URL — event taxonomy, parameters, custom dimensions, and key events to mark as conversions
Weekly GA4 check — sessions, users, key-event conversions, revenue, channel mix — with week-over-week deltas and tracking-break alerts
| name | gtm-setup |
| description | GTM Event Tracking & Setup Reference — dataLayer fundamentals, trigger types, variable types, GA4 tag configuration, debug mode, and best practices |
| version | 1.0.0 |
| author | Cogny AI |
| platforms | [] |
| user-invocable | true |
| argument-hint | <topic or question> |
| allowed-tools | ["WebFetch","WebSearch","Bash","Read","Write","mcp__cogny__google_tag_manager__tool_list_accounts","mcp__cogny__google_tag_manager__tool_list_containers","mcp__cogny__google_tag_manager__tool_list_tags","mcp__cogny__google_tag_manager__tool_list_triggers","mcp__cogny__google_tag_manager__tool_list_variables","mcp__cogny__google_tag_manager__tool_get_tag","mcp__cogny__google_tag_manager__tool_get_trigger","mcp__cogny__google_tag_manager__tool_get_variable","mcp__cogny__google_tag_manager__tool_get_workspace_status","mcp__cogny__google_tag_manager__tool_search_tags"] |
Complete reference guide to Google Tag Manager event tracking, including dataLayer fundamentals, trigger and variable types, GA4 tag configuration, debug mode, and implementation best practices.
Full docs: https://cogny.com/docs/gtm-event-tracking
/gtm-setup # Full GTM reference overview
/gtm-setup dataLayer # dataLayer fundamentals and syntax
/gtm-setup purchase # Show purchase event dataLayer.push()
/gtm-setup triggers # All trigger types explained
/gtm-setup variables # All variable types explained
/gtm-setup tags # GA4 tag configuration
/gtm-setup debug # Debug mode and troubleshooting
/gtm-setup best practices # Naming conventions, organization
/gtm-setup common mistakes # Race conditions, missing data, duplicates
You are a Google Tag Manager expert. Use this reference to help users implement event tracking, configure tags/triggers/variables, debug GTM issues, and follow best practices.
When the user asks a question, find the relevant section below and provide precise, actionable answers with ready-to-use code snippets.
If the user provides a specific topic as an argument, focus on that area. Otherwise, provide an overview of GTM concepts and ask what they need help with.
If Cogny GTM MCP tools are available, use them to inspect the user's actual GTM container, list their tags/triggers/variables, and provide recommendations based on their real configuration.
The dataLayer is a JavaScript array that acts as a message bus between your website and GTM. When you push objects onto the dataLayer, GTM reads them to fire triggers and populate variables.
Declare the dataLayer before the GTM snippet to capture early pushes:
<script>
window.dataLayer = window.dataLayer || [];
</script>
<!-- GTM snippet follows -->
// Push data AND fire a trigger (event key is required for trigger evaluation)
dataLayer.push({
'event': 'custom_event_name',
'key1': 'value1',
'key2': 'value2'
});
// Push data without firing a trigger (no 'event' key)
dataLayer.push({
'user_type': 'premium',
'user_id': '12345'
});
Later pushes override earlier values. Nested objects use shallow merge (the entire nested object is replaced, not deep-merged):
dataLayer.push({ 'user': { 'name': 'John', 'plan': 'free' } });
dataLayer.push({ 'user': { 'plan': 'premium' } });
// Result: user = { plan: 'premium' } — user.name is GONE
Always push null before e-commerce events to prevent stale data contamination:
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'view_item',
'ecommerce': {
'items': [{ 'item_id': 'SKU-001', 'item_name': 'Blue T-Shirt', 'price': 29.99 }]
}
});
dataLayer.push({
'event': 'page_view',
'page_location': window.location.href,
'page_title': document.title,
'page_referrer': document.referrer,
'content_group': 'blog'
});
For SPAs (React, Next.js, Vue), fire on route change:
useEffect(() => {
dataLayer.push({
'event': 'page_view',
'page_location': window.location.href,
'page_title': document.title
});
}, [location.pathname]);
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T-20250211-001',
'value': 149.97,
'tax': 12.50,
'shipping': 5.99,
'currency': 'USD',
'coupon': 'SUMMER20',
'items': [
{
'item_id': 'SKU-001',
'item_name': 'Blue T-Shirt',
'item_brand': 'BrandName',
'item_category': 'Apparel',
'item_category2': 'T-Shirts',
'item_variant': 'Blue',
'price': 29.99,
'quantity': 2
},
{
'item_id': 'SKU-045',
'item_name': 'Running Shoes',
'item_brand': 'BrandName',
'item_category': 'Footwear',
'item_variant': 'Black/Size-10',
'price': 89.99,
'quantity': 1
}
]
}
});
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'currency': 'USD',
'value': 29.99,
'items': [{
'item_id': 'SKU-001',
'item_name': 'Blue T-Shirt',
'item_brand': 'BrandName',
'item_category': 'Apparel',
'price': 29.99,
'quantity': 1
}]
}
});
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'remove_from_cart',
'ecommerce': {
'currency': 'USD',
'value': 29.99,
'items': [{
'item_id': 'SKU-001',
'item_name': 'Blue T-Shirt',
'price': 29.99,
'quantity': 1
}]
}
});
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'view_item',
'ecommerce': {
'currency': 'USD',
'value': 29.99,
'items': [{
'item_id': 'SKU-001',
'item_name': 'Blue T-Shirt',
'item_brand': 'BrandName',
'item_category': 'Apparel',
'price': 29.99
}]
}
});
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'view_item_list',
'ecommerce': {
'item_list_id': 'category_apparel',
'item_list_name': 'Apparel',
'items': [
{ 'item_id': 'SKU-001', 'item_name': 'Blue T-Shirt', 'index': 0, 'price': 29.99 },
{ 'item_id': 'SKU-002', 'item_name': 'Red T-Shirt', 'index': 1, 'price': 29.99 }
]
}
});
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'begin_checkout',
'ecommerce': {
'currency': 'USD',
'value': 149.97,
'coupon': 'SUMMER20',
'items': [
{ 'item_id': 'SKU-001', 'item_name': 'Blue T-Shirt', 'price': 29.99, 'quantity': 2 },
{ 'item_id': 'SKU-045', 'item_name': 'Running Shoes', 'price': 89.99, 'quantity': 1 }
]
}
});
dataLayer.push({
'event': 'form_submit',
'form_id': 'contact_form',
'form_name': 'Contact Us',
'form_destination': '/thank-you'
});
dataLayer.push({
'event': 'generate_lead',
'currency': 'USD',
'value': 50.00,
'lead_source': 'contact_form'
});
dataLayer.push({ 'event': 'sign_up', 'method': 'google' });
dataLayer.push({ 'event': 'login', 'method': 'email' });
dataLayer.push({
'event': 'search',
'search_term': 'blue t-shirt',
'search_results_count': 42
});
dataLayer.push({
'event': 'scroll',
'percent_scrolled': 90
});
// video_start
dataLayer.push({
'event': 'video_start',
'video_title': 'Product Demo',
'video_url': 'https://youtube.com/watch?v=abc123',
'video_provider': 'youtube',
'video_duration': 180
});
// video_progress
dataLayer.push({
'event': 'video_progress',
'video_title': 'Product Demo',
'video_percent': 50,
'video_current_time': 90,
'video_duration': 180
});
// video_complete
dataLayer.push({
'event': 'video_complete',
'video_title': 'Product Demo',
'video_duration': 180
});
| Sub-Type | Fires When | Use Case |
|---|---|---|
| Page View | gtm.js (immediately) | GA4 config tag, consent checks |
| DOM Ready | gtm.dom (DOM parsed) | Tags that read DOM elements |
| Window Loaded | gtm.load (all resources loaded) | Tags depending on images/scripts |
Filter by Page Path, Page Hostname, or Page URL.
| Sub-Type | Fires When | Use Case |
|---|---|---|
| All Elements | Any element clicked | Buttons, divs, images |
| Just Links | <a> element clicked | Outbound links, downloads |
Variables available: Click Element, Click Classes, Click ID, Click Target, Click URL, Click Text.
Fires when a specific event value is pushed to the dataLayer. Set Event Name to match the event key value. Supports regex (e.g., form_submit.*).
dataLayer.push({ 'event': 'form_submit' });
// Fires trigger where Event Name = "form_submit"
Fires when an element enters the viewport.
| Setting | Description |
|---|---|
| Selection Method | CSS Selector or Element ID |
| When to fire | Once per page / once per element / every time |
| Minimum % visible | Default 50% |
| Minimum on-screen duration | Milliseconds |
Fires at a set interval (milliseconds). Configure a limit to cap the number of firings.
Fires at specified scroll thresholds (percentages or pixels). Supports vertical and horizontal.
Variables: Scroll Depth Threshold, Scroll Depth Units, Scroll Direction.
Built-in support for embedded YouTube videos. Captures: Start, Complete, Pause, Seeking, Buffering, Progress (at configurable thresholds).
Variables: Video Provider, Video Status, Video URL, Video Title, Video Duration, Video Current Time, Video Percent, Video Visible.
Fires on form submit. Options: Wait for Tags (delay submission up to 2000ms), Check Validation (only fire if browser validation passes).
Variables: Form Element, Form Classes, Form ID, Form Target, Form URL, Form Text.
Fires on URL fragment changes or pushState/replaceState. Essential for SPAs.
Variables: New History Fragment, Old History Fragment, New History State, Old History State, History Source.
Combine multiple triggers. Tag fires only when ALL triggers in the group have fired at least once during the page lifecycle.
Reads a value from the dataLayer by key name. Use dot notation for nested values (e.g., ecommerce.transaction_id). Always use Version 2.
Reads a global JS variable (e.g., document.title, navigator.language).
Reads text content or an attribute from a DOM element by CSS selector or ID.
Extracts URL components: Full URL, Protocol, Host Name, Port, Path, Query (with optional Query Key), Fragment.
Stores a fixed value. Use for Measurement IDs, Pixel IDs, and configuration strings shared across tags.
Runs an anonymous function and returns its value:
// Get viewport width
function() {
return window.innerWidth;
}
// Classify page type from URL
function() {
var path = window.location.pathname;
if (path === '/') return 'homepage';
if (path.indexOf('/product/') === 0) return 'product';
if (path.indexOf('/category/') === 0) return 'category';
if (path.indexOf('/blog/') === 0) return 'blog';
if (path.indexOf('/checkout') === 0) return 'checkout';
return 'other';
}
// Read a cookie
function() {
var match = document.cookie.match(new RegExp('(^| )user_segment=([^;]+)'));
return match ? match[2] : undefined;
}
Maps input values (from another variable) to output values. Example: Page Path / maps to Homepage, /pricing to Pricing.
Like Lookup Table but uses regex patterns. Example: ^/product/.* maps to Product Page. Supports capture groups and case sensitivity settings.
Sets up the GA4 measurement stream. Fire on All Pages.
| Setting | Description |
|---|---|
| Measurement ID | G-XXXXXXXXXX (use a Constant variable) |
| Send page_view | Auto-send page_view on load |
| Fields to Set | debug_mode, send_page_view, user_id |
| User Properties | User-scoped dimensions |
Sends a custom event to GA4.
| Setting | Description |
|---|---|
| Configuration Tag | Your GA4 Config tag |
| Event Name | GA4 event name (e.g., generate_lead) |
| Event Parameters | Key-value pairs (e.g., transaction_id, value) |
Runs arbitrary HTML/JavaScript. Always wrap in try/catch:
<script>
(function() {
try {
thirdPartySDK.track('event', { value: {{DLV - Value}} });
} catch (e) {
console.warn('GTM Custom HTML error:', e);
}
})();
</script>
Fires a pixel request (1x1 image). Configure Image URL with tracking parameters. Enable cache busting.
Click Element, Click Classes, Click ID, Click Target, Click URL, Click Text
Form Element, Form Classes, Form ID, Form Target, Form URL, Form Text
Page URL, Page Hostname, Page Path, Referrer
Scroll Depth Threshold, Scroll Depth Units, Scroll Direction
Video Provider, Video Status, Video URL, Video Title, Video Duration, Video Current Time, Video Percent, Video Visible
Event, Environment Name, Container ID, Container Version, HTML ID, Random Number, Debug Mode
Click "Preview" in GTM workspace. Tag Assistant opens and shows:
// View entire dataLayer
console.table(dataLayer);
// Filter for specific events
dataLayer.filter(function(item) { return item.event === 'purchase'; });
// Watch pushes in real time
(function() {
var orig = dataLayer.push;
dataLayer.push = function() {
console.log('dataLayer.push:', arguments[0]);
return orig.apply(dataLayer, arguments);
};
})();
Add debug_mode: true to your GA4 Config tag fields, then view events at GA4 Admin > DebugView.
Filter by collect in DevTools Network tab to see GA4 hits. Verify payload parameters.
| Element | Convention | Example |
|---|---|---|
| Tags | [Platform] - [Action] - [Detail] | GA4 - Event - Purchase |
| Triggers | [Type] - [Condition] | CE - form_submit |
| Variables | [Type prefix] - [Name] | DLV - Transaction ID |
| Custom Events | snake_case | generate_lead |
| Folders | By platform or function | GA4, Meta, Consent |
GA4/
GA4 - Config - All Pages
GA4 - Event - Purchase
GA4 - Event - Add to Cart
Meta/
Meta - Pixel - Base Code
Meta - Event - Purchase
Consent/
HTML - Consent Banner Init
HTML - Consent Mode Update
Q1-2025-GA4-ecommerce)Use Tag Sequencing to ensure setup tags fire before dependent tags. Use tag firing priority (higher number = fires first) when order matters on the same trigger.
// Default (before user choice)
dataLayer.push({
'event': 'consent_default',
'consent': {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
}
});
// After user grants consent
dataLayer.push({
'event': 'consent_update',
'consent': {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
}
});
Tags fire before dataLayer contains required data. Fix: use Custom Event triggers tied to the specific event push, not Page View triggers.
Tags fire on all pages instead of specific ones. Fix: always add trigger filters (e.g., Page Path equals /thank-you).
Stale data from previous pushes contaminates events. Fix: always dataLayer.push({ ecommerce: null }) before ecommerce events.
Same event sent multiple times. Causes: multiple triggers, conditions too broad, wrong firing option. Fix: use "Once per Page" or review trigger conditions.
JS errors in Custom HTML block other tags. Fix: wrap all Custom HTML in try/catch.
Causes: key name mismatch (case-sensitive), data pushed after trigger, wrong DLV version, incorrect dot-notation path.
Route changes not captured. Fix: use History Change trigger or push custom page_view events on route change:
// Next.js App Router
'use client';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';
export function GTMPageView() {
const pathname = usePathname();
useEffect(() => {
dataLayer.push({
'event': 'page_view',
'page_location': window.location.href,
'page_title': document.title
});
}, [pathname]);
return null;
}
Users counted as new sessions across domains. Fix: configure cross-domain linker in GA4 Config tag or GA4 Admin > Data Streams > Configure your domains.
Fix: add blocking trigger where Debug Mode equals true, or filter internal traffic via traffic_type parameter.