关于 gtm-testing
用于指导 GTM 跟踪实现测试与故障排查的技能,适合验证网站上的 dataLayer 事件及 GA4 标签。它优先采用 Playwright 自动化测试,并提供从浏览器控制台到 GA4 DebugView 的分层检查流程。
主要功能
- 01Playwright 无头自动化测试
- 02捕获并检查 dataLayer 事件
- 03通过 GTM API 检查容器配置
- 04浏览器控制台事件验证
- 05GTM Preview 标签检查
- 06GA4 DebugView 端到端验证
适用场景
- 01自动检查网站跟踪事件
- 02定位未触发的 GTM 标签
- 03核对事件参数和测量 ID
- 04确认事件是否到达 GA4
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ aimonk2025/ google-tag-manager-automation --skill gtm-testing安装后在 Claude Code 中输入/gtm-testing确认已加载。
附带文件examples/sample.md
详细介绍
GTM 测试 - 验证与调试
引导用户全面测试 GTM 跟踪实现。尽可能优先使用自动化无头测试,而不是手动步骤。
测试理念
按自动化程度排序的四级验证方法:
- 第 0 级(自动化):Playwright 无头测试(无需浏览器,完全自动化)
- 第 1 级(手动):通过浏览器控制台验证 dataLayer
- 第 2 级(手动):通过 GTM 预览模式验证标签触发情况
- 第 3 级(手动):通过 GA4 DebugView 端到端验证
如果用户询问“你能自己完成吗”,或希望进行自动化测试,始终从第 0 级开始。只有在验证 GTM 容器和 GA4 时才退回手动级别,因为这些步骤需要浏览器会话。
阶段 0:加载业务背景(如有)
检查项目根目录中是否存在 gtm-context.md:
- 如果存在:静默读取,并在本次技能运行过程中使用其中的业务背景(网站类型和已知缺口有助于确定重点验证步骤)
- 如果不存在:正常继续
此文件由 gtm-analytics-audit 在首次运行结束时自动创建。
第 0 级:自动化 Playwright 测试(首选)
首先运行此级别。无需用户进行任何浏览器交互,Claude 可独立完成。
检查前置条件
# Check if Playwright is installed
npx playwright --version
# If not installed as a project dependency:
npm install --save-dev playwright
npx playwright install chromium
# Check if dev server is running
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000
# If not running, start it:
# npm run dev
核心辅助函数:captureDataLayerEvents
此辅助函数会拦截操作期间所有 dataLayer.push() 调用,并返回捕获到的事件。请在每项测试中使用它。
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}
常见元素类型的关键模式
Next.js Link 组件(导航、课程按钮):
不要使用 page.click()——它会在 onClick 处理程序触发前触发导航。请改用 dispatchEvent:
await page.evaluate(() => {
const btn = document.querySelector('a.js-module_nav');
if (btn) btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
});
await page.waitForTimeout(400);
出站链接(href 指向外部域名): 阻止导航,以便页面在事件触发期间保持加载:
await page.route('**github.com**', route => route.abort());
// Then use dispatchEvent as above
普通按钮和内部操作: 直接使用标准点击即可:
await page.locator('#element-id').click({ force: true });
测试脚本模板
在项目根目录中创建 scripts/test-tracking.js:
const { chromium } = require('playwright');
const BASE_URL = 'http://localhost:3000';
const results = { passed: [], failed: [], warnings: [] };
function pass(test, detail = '') {
results.passed.push({ test, detail });
console.log(` PASS ${test}${detail ? ' - ' + detail : ''}`);
}
function fail(test, detail = '') {
results.failed.push({ test, detail });
console.log(` FAIL ${test}${detail ? ' - ' + detail : ''}`);
}
function warn(test, detail = '') {
results.warnings.push({ test, detail });
console.log(` WARN ${test}${detail ? ' - ' + detail : ''}`);
}
async function captureDataLayerEvents(page, action) {
await page.evaluate(() => {
window.__testEvents = [];
const original = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (...args) {
window.__testEvents.push(args[0]);
return original(...args);
};
});
await action();
await page.waitForTimeout(300);
return await page.evaluate(() => window.__testEvents || []);
}
async function runTests() {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
console.log('\n=== GTM dataLayer Event Tests ===\n');
// TEST: dataLayer initialisation
console.log('Test: dataLayer initialisation');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const hasDataLayer = await page.evaluate(() => Array.isArray(window.dataLayer));
hasDataLayer ? pass('dataLayer initialised') : fail('dataLayer not found');
const gtmEvent = await page.evaluate(() => window.dataLayer.find(e => e['gtm.start']));
gtmEvent ? pass('GTM bootstrap event present') : fail('GTM bootstrap event missing - container may not be installed');
await page.close();
}
// TEST: cta_click event
// Adjust selector to match your actual element ID
console.log('\nTest: cta_click event');
{
const page = await context.newPage();
await page.goto(BASE_URL, { waitUntil: 'networkidle' });
const events = await captureDataLayerEvents(page, async () => {
const el = await page.$('#your-cta-id');
if (el) await page.evaluate(el => el.dispatchEvent(new MouseEvent('click', { bubbles: true })), el);
});
const e = events.find(e => e.event === 'cta_click');
e ? pass('cta_click fired', `location=${e.cta_location}`) : fail('cta_click did not fire');
await page.close();
}
// Add more tests following the same pattern...
// RESULTS
await browser.close();
console.log('\n=== RESULTS ===');
console.log(` Passed: ${results.passed.length}`);
console.log(` Failed: ${results.failed.length}`);
console.log(` Warnings: ${results.warnings.length}`);
if (results.failed.length > 0) {
console.log('\nFailed:');
results.failed.forEach(f => console.log(` - ${f.test}: ${f.detail}`));
}
process.exit(results.failed.length > 0 ? 1 : 0);
}
runTests().catch(err => { console.error('Fatal:', err.message); process.exit(1); });
查找正确的元素选择器
编写测试前,务必检查页面实际渲染的内容。使用此发现脚本:
// Add to test script or run as a separate debug script
const page = await context.newPage();
await page.goto(`${BASE_URL}/your-page`, { waitUntil: 'networkidle' });
const tracked = await page.evaluate(() => {
return Array.from(document.querySelectorAll('[id], .js-track, [data-track]')).map(el => ({
id: el.id,
tag: el.tagName,
class: el.className,
text: el.textContent.trim().substring(0, 40),
href: el.getAttribute('href'),
}));
});
console.log(JSON.stringify(tracked, null, 2));
通过 API 验证 GTM 容器配置
运行浏览器测试前,请确认 GTM 容器本身配置正确。这可以发现孤立的触发器引用和缺失的衡量 ID。
// scripts/audit-gtm-coverage.js
// Uses googleapis + gtm-credentials.json + gtm-token.json + gtm-config.json
// Critical checks:
// 1. Base GA4 config tag (googtag) - must fire on Page View trigger
// If firingTriggerId references a non-existent trigger, NO pages are tracked
// 2. GA4 event tags (gaawe) - must have measurementIdOverride set
// Parameter key is "measurementIdOverride" NOT "measurementId"
// 3. All triggers must be used by at least one tag
// 4. All tags must have at least one firing trigger
需要留意的关键 GTM API 错误:gaawe(GA4 Event)标签类型使用 measurementIdOverride 和 eventSettingsTable(而非 measurementId 或 eventParameters)。正确的参数结构如下:
// CORRECT structure for gaawe tags via API
{
type: 'gaawe',
parameter: [
{ type: 'boolean', key: 'sendEcommerceData', value: 'false' },
{ type: 'template', key: 'eventName', value: 'your_event_name' },
{ type: 'template', key: 'measurementIdOverride', value: 'G-XXXXXXXXXX' },
{
type: 'list',
key: 'eventSettingsTable',
list: [
{
type: 'map',
map: [
{ type: 'template', key: 'parameter', value: 'param_name' },
{ type: 'template', key: 'parameterValue', value: '{{DL - Variable Name}}' },
],
},
],
},
],
}
运行并解读结果
node scripts/test-tracking.js
退出代码 0 = 所有测试均通过。退出代码 1 = 存在失败项。
结果类型:
PASS- 事件已触发,且参数正确FAIL- 事件未触发,或未找到所需元素WARN- 组件包含跟踪代码,但尚未在任何页面上渲染(这不是错误)
常见失败原因及修复方法:
| 失败情况 | 原因 | 修复方法 |
|---|---|---|
dataLayer not found | <head> 中缺少 GTM 代码片段 | 将 GTM 容器代码片段添加到布局中 |
| 事件未触发 | 测试中使用了错误的元素选择器 | 使用发现脚本查找真实的 ID/类名 |
| 事件已触发,但页面已卸载 | 点击了 Next.js <Link> | 使用 dispatchEvent,而非 page.click() |
| 未捕获出站点击 | 页面在捕获前已跳转 | 使用 page.route() 阻止外部导航 |
| 页面加载时没有事件 | GTM 基础标签引用了孤立的触发器 | 通过 GTM API 或界面修复——重新分配到 Page View 触发器 |
第 1 级:浏览器控制台测试(手动)
需要在与网站交互时手动验证事件时使用。
步骤 1:检查 dataLayer 是否存在
window.dataLayer
// Expected: [...] array
// If undefined: GTM not installed
步骤 2:实时监控 dataLayer
const _push = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function(...args) {
console.log('%c dataLayer.push', 'background:#222;color:#0f0;padding:2px 6px', args[0]);
return _push(...args);
};
// Now every push is logged in green
步骤 3:测试每个事件
逐个点击元素,并确认控制台输出符合预期:
Expected for cta_click:
{
event: "cta_click",
cta_location: "hero",
cta_type: "primary",
cta_text: "Start Course",
cta_destination: "/claude-code"
}
验证清单 - Tier 1
-
window.dataLayer是一个数组 - 存在 GTM 引导事件(
gtm.start) - 每个事件触发时使用正确的
event名称 - 所有必需参数均存在且非空
- 单击时不会重复触发事件
- 控制台中没有 JavaScript 错误
Tier 2:GTM 预览模式(手动)
确认 GTM 容器接收事件并触发标签。需要访问 GTM UI。
设置
- 前往 tagmanager.google.com
- 选择容器
- 点击 预览
- 输入网站 URL,然后点击 连接
- 网站底部会出现调试面板
验证内容
对于每个事件,预览面板应显示:
Event fired: "cta_click"
Triggers: CE - CTA Click [FIRED]
Tags: GA4 - CTA Click [FIRED]
点击已触发的标签以验证:
measurementIdOverride使用了正确的 GA4 ID- 所有事件参数均已填充(不是空的
{{DL - ...}}字符串)
验证清单 - Tier 2
- 预览模式成功连接
- 页面加载时触发 GA4 配置标签(没有孤立标签)
- 事件列表中显示每个自定义事件
- 每个事件均触发了正确的触发器
- 每个触发器均触发了正确的标签
- 标签参数显示已解析的值(不是未解析的变量引用)
- 没有意外触发的标签
Tier 3:GA4 DebugView(手动)
确认事件已携带正确参数传达到 GA4。需要访问 GA4 媒体资源。
启用调试模式
选项 A - URL 参数:在页面 URL 后追加 ?debug_mode=true
选项 B - Chrome 扩展程序:安装 Google Analytics Debugger 并启用
打开 DebugView
GA4 > 管理员 > 媒体资源 > DebugView
你与网站交互时,事件会实时显示。
验证内容
- 显示事件名称(例如,
cta_click) - 显示所有参数及其正确值
- 每次页面导航时都会触发
page_view事件 - 重复操作时事件计数会递增
验证清单 - Tier 3
- 所有页面均会触发
page_view事件 - 自定义事件会在触发后 1-3 秒内显示
- 所有事件参数均可见且值正确
- 事件归属于正确的页面路径
- 没有意外事件
常见问题参考
| 问题 | 发现层级 | 原因 | 修复方法 |
|---|---|---|---|
dataLayer 未定义 | 1 | 缺少 GTM 代码片段 | 将 GTM 代码片段添加到 <head> |
| 事件已触发,但触发器未触发 | 2 | 事件名称不匹配(区分大小写) | 确认触发器使用 {{_event}},且等于准确的事件名称 |
| 触发器已触发,但标签未触发 | 2 | 触发器孤立或标签配置错误 | 检查标签是否分配了有效的触发器 |
| 页面浏览标签从未触发 | 2 | 基础标签上的触发器引用孤立 | 将基础标签重新分配给有效的页面浏览触发器 |
参数显示为 {{DL - X}} | 2 | 未创建数据层变量 | 使用正确的 dataLayer 键名创建 DLV |
| 预览中有事件,但 DebugView 中没有 | 3 | GA4 媒体资源错误或未开启调试模式 | 确认测量 ID 匹配,并启用调试模式 |
| GA4 中缺少参数 | 3 | 未在标签的 eventSettingsTable 中映射 | 在 GTM 标签配置中添加参数映射 |
完整工作流
1. Run Tier 0 (automated)
PASS → proceed to publish GTM
FAIL → fix code or GTM config, re-run
2. Run Tier 1 (console) — optional manual spot-check
PASS → proceed
FAIL → fix before Tier 2
3. Run Tier 2 (GTM Preview)
PASS → proceed
FAIL → fix GTM tags/triggers/variables
4. Run Tier 3 (GA4 DebugView)
PASS → publish GTM container
FAIL → fix GA4 config or parameter mappings
5. Publish GTM → GTM UI > Submit > Publish version
6. Disable debug mode in production
7. Monitor GA4 Reports > Engagement > Events
参考资料
references/debugging-guide.md- 扩展版问题诊断指南references/test-checklist.md- 可打印的清单模板examples/sample.md- 测试运行输出示例,展示 PASS/FAIL/WARN 格式和常见故障修复方法- 相关技能:
gtm-implementation、gtm-analytics-audit、gtm-reporting