gtm-testing について
GTM のトラッキング実装を検証・デバッグし、ウェブサイトの dataLayer イベントや GA4 タグを確認するスキルです。Playwright による自動テストを優先し、ブラウザーコンソールから GA4 DebugView まで段階的に検証します。
主な機能
- 01Playwright によるヘッドレステスト
- 02dataLayer イベントの捕捉と確認
- 03GTM 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 のトラッキング実装を包括的にテストできるよう、ユーザーをガイドします。可能な限り、手動の手順より自動化されたヘッドレステストを優先します。
テストの方針
自動化レベルの高い順に、4 段階で検証します。
- Tier 0(自動):Playwright のヘッドレステスト(ブラウザー不要、完全自動)
- Tier 1(手動):ブラウザーコンソールでの dataLayer 検証
- Tier 2(手動):GTM プレビューモードでのタグ発火の検証
- Tier 3(手動):GA4 DebugView でのエンドツーエンド検証
ユーザーが「自分で実行できますか」と尋ねたり、自動テストを希望したりする場合は、必ず Tier 0 から開始してください。ブラウザーセッションが必要な GTM コンテナと GA4 の検証に限り、手動の Tier に切り替えてください。
フェーズ 0:ビジネスコンテキストの読み込み(利用可能な場合)
プロジェクトのルートに gtm-context.md があるか確認します。
- 見つかった場合:内容をユーザーに知らせずに読み込み、このスキルの実行中はビジネスコンテキストを使用します(サイトの種類や既知の不足点を参考に、重点を置く検証手順を調整します)。
- 見つからない場合:通常どおり続行します。
このファイルは、gtm-analytics-audit が初回実行の最後に自動作成します。
Tier 0:Playwright による自動テスト(推奨)
最初にこの Tier を実行します。ユーザーによるブラウザー操作は不要で、すべて 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 | GTM スニペットが <head> にありません | GTM コンテナスニペットをレイアウトに追加します |
| イベントが発火しなかった | テストで誤ったセレクターを使用しています | 検出スクリプトを使って実際の ID/クラスを見つけます |
| イベントは発火したがページが読み込まれなかった | Next.js の <Link> をクリックしています | page.click() ではなく dispatchEvent を使用します |
| 外部リンクのクリックをキャプチャできなかった | キャプチャ前にページが移動しました | page.route() を使って外部へのナビゲーションをブロックします |
| ページ読み込み時にイベントがない | GTM ベースタグのトリガー参照が孤立しています | GTM API または UI で修正し、ページビューのトリガーに再割り当てします |
Tier 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:各イベントをテストする
要素を一度に 1 つずつクリックし、コンソールの出力が期待どおりであることを確認します。
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名で発火する - 必須パラメーターがすべて存在し、空でない
- 1 回のクリックでイベントが重複して発火しない
- コンソールに 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 秒以内に表示される
- すべてのイベントパラメーターが表示され、値が正しい
- イベントが正しいページパスに関連付けられている
- 想定外のイベントがない
よくある問題の参照先
| 問題 | 該当する Tier | 原因 | 対処方法 |
|---|---|---|---|
dataLayer が未定義 | 1 | GTM スニペットがない | <head> に GTM スニペットを追加する |
| イベントは発火するが、トリガーは発火しない | 2 | イベント名の不一致(大文字と小文字を区別) | トリガーが {{_event}} を正確なイベント名と照合していることを確認する |
| トリガーは発火するが、タグは発火しない | 2 | トリガーが孤立している、またはタグの設定に誤りがある | タグに有効な発火トリガーが割り当てられていることを確認する |
| Page View タグがまったく発火しない | 2 | ベースタグのトリガー参照が孤立している | ベースタグを有効な Page View トリガーに再割り当てする |
パラメーターに {{DL - X}} と表示される | 2 | Data Layer Variable が作成されていない | 正しい dataLayer キー名で DLV を作成する |
| Preview にはイベントが表示されるが、DebugView には表示されない | 3 | GA4 プロパティが異なる、またはデバッグモードがオフ | Measurement 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