feat: add GTM editor & validator skills (61, 62), update GTM audit (60)

Restructure GTM skills into audit → edit → validate workflow:
- 60-gtm-audit: MCP-based page scan, site audit, gap analysis, tag design (new code/SKILL.md)
- 61-gtm-editor: tag/trigger/variable creation via GTM API, ES5 Custom HTML, dataLayer generation
- 62-gtm-validator: QA toolkit with 7 validation modes, naming conventions, cross-platform mapping
All three skills use DTM Agent + Chrome DevTools MCP with clear handoff patterns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-17 21:37:18 +09:00
parent 8d5cfb69fd
commit f905ef6314
12 changed files with 1665 additions and 10 deletions

View File

@@ -0,0 +1,140 @@
---
name: gtm-audit
description: >
Automated GTM audit and analysis. Scans websites for tracking coverage, compares
against GTM container config, identifies gaps, and reports to Notion. Uses Chrome
DevTools MCP for browser inspection and DTM Agent MCP for container operations.
Triggers on "GTM audit", "audit website", "scan page", "check tracking",
"tracking coverage", "gap analysis", "site audit", "tag firing check".
NOT for creating/modifying tags (use gtm-editor) or validating/QA (use gtm-validator).
---
# GTM Audit Skill
Analyze GTM implementations by scanning websites and comparing against container configuration.
## Available Tools
### Browser Inspection (Chrome DevTools MCP)
- `navigate_page` — Load target URL
- `evaluate_script` — Capture dataLayer, detect GTM containers, check JS globals
- `list_network_requests` — Capture tag firing network requests
- `take_screenshot` — Document page state
- `click` / `hover` — Simulate user interactions
- `list_console_messages` — Check for JS errors
### GTM Container (DTM Agent MCP)
- `dtm_status` — Check auth and active container
- `dtm_list_tags` / `dtm_list_triggers` / `dtm_list_variables` — Get container config
- `dtm_audit_scan` — Scan page with collected data (returns structured PageData)
- `dtm_audit_gap` — Run gap analysis (returns GapReport with OK/MISSING/ORPHAN)
### Reporting (Notion MCP)
- Write findings to GTM Audit Log: `collection://2cf581e5-8a1e-815a-a7f8-000b88b93585`
## 4 Audit Modes
### Mode A: Page Scan (`/gtm-audit scan <url>`)
Quick single-page diagnostics. No GTM container needed.
1. `navigate_page` to URL, wait for load
2. `evaluate_script`: capture dataLayer
```javascript
JSON.stringify(window.dataLayer || [])
```
3. `evaluate_script`: detect GTM containers
```javascript
(function(){var s=document.querySelectorAll('script[src*="googletagmanager.com/gtm.js"]');var ids=[];s.forEach(function(el){var m=el.src.match(/id=(GTM-[A-Z0-9]+)/);if(m)ids.push(m[1]);});return JSON.stringify(ids);})()
```
4. `evaluate_script`: detect tracking pixels
```javascript
(function(){var f=[];if(window.fbq)f.push('Meta Pixel');if(window.gtag)f.push('GA4');if(window.clarity)f.push('Clarity');if(window.kakaoPixel)f.push('Kakao');if(window.wcs)f.push('Naver');if(window.ttq)f.push('TikTok');return JSON.stringify(f);})()
```
5. `list_network_requests` — filter for tag domains
6. Call `dtm_audit_scan` with collected html, network_requests, datalayer_json
7. Report findings
### Mode B: Site Audit (`/gtm-audit site <url>`)
Full website coverage audit with auto-discovery.
1. Navigate to root URL
2. `evaluate_script`: extract all internal links
3. Classify pages by type (home, product, service, form, blog, about)
4. For each page type: run Mode A scan
5. Build coverage matrix (page type × event × platform)
6. Run Mode C gap analysis against container
7. Write comprehensive report to Notion
### Mode C: Gap Analysis (`/gtm-audit gap <url>`) — MOST IMPORTANT
Compare GTM container config against actual tag firing.
1. `dtm_status` — verify auth and active container
2. `dtm_list_tags` + `dtm_list_triggers` — get expected configuration
3. `navigate_page` to URL
4. `evaluate_script` — capture dataLayer
5. `list_network_requests` — capture actual tag firings
6. Call `dtm_audit_gap` with network_requests
7. Analyze gaps: MISSING (in GTM, not firing), ORPHAN (firing, not in GTM)
8. Write to Notion GTM Audit Log
### Mode D: Tag Design (`/gtm-audit design <url>`)
AI-powered analysis of what SHOULD be tracked on a page.
1. `navigate_page` to URL
2. `take_screenshot` — visual reference
3. `evaluate_script` — inspect DOM: forms, buttons, links, product elements
4. `evaluate_script` — capture existing dataLayer schema
5. `dtm_list_tags` — check existing configuration
6. Design recommendations: which events, triggers, variables are needed
7. Output as structured blueprint (hand off to gtm-editor for implementation)
## Detection Patterns
### Cloudflare Zaraz Proxy
URLs with `/1tbv/` path proxy GA4/Ads through the site's domain:
```
https://site.com/1tbv/ag/g/c?tid=G-XXXXX → GA4
https://site.com/1tbv/ag/g/c?tid=AW-XXXXX → Google Ads
```
### Server-Side GTM (sGTM)
Custom subdomains: `stms.*`, `sgtm.*`, `ss.*`, `tag.*`
```
https://stms.site.com/g/collect?tid=G-XXXXX → GA4 via sGTM
```
### GA4 Multiple Endpoints
One GA4 page_view fires to multiple endpoints — this is normal:
- `google-analytics.com/g/collect`
- `analytics.google.com/g/s/collect`
- `stats.g.doubleclick.net/g/collect`
- `www.google.com/ccm/collect` (Consent Mode)
- Zaraz proxy endpoints
## Notion Report Fields
| Field | Value |
|-------|-------|
| Site | domain name |
| URL | full URL |
| Container IDs | GTM-XXXXX |
| Audit Status | Pass / Warning / Fail |
| GTM Status | Installed / Not Found / Multiple Containers |
| Tags Fired | [GA4, Google Ads, Meta Pixel, Kakao, Naver, ...] |
| Journey Type | full / pageview / scroll / form / checkout / datalayer |
| Critical Issues | count |
| Issues Count | count |
| Summary | AI-generated findings |
## Rules
- Always check `dtm_status` before gap analysis
- Wait for page to fully load before capturing network requests
- Use `evaluate_script` to check consent mode before interpreting missing tags
- Orphan count may be high due to GA4 multi-endpoint — note this in reports
- Hand off tag creation work to `gtm-editor` skill
- Hand off QA/validation work to `gtm-validator` skill

View File

@@ -0,0 +1,186 @@
---
name: gtm-editor
description: >
GTM implementation toolkit. Creates, updates, and modifies GTM tags, triggers,
variables via API. Generates Custom HTML with ES5 compliance. Handles workspace
lifecycle, DOM analysis for trigger design, and dataLayer code generation.
Triggers on "create GTM tag", "generate dataLayer", "modify trigger", "update variable",
"inject tracking code", "write custom HTML", "manage GTM", "design tags",
"create conversion tag", "set up tracking".
NOT for auditing (use gtm-audit) or validation/QA (use gtm-validator).
---
# GTM Editor Skill
Create, modify, and deploy GTM configurations via API. Generates ES5-compliant Custom HTML tags.
## Available Tools
### GTM Container Management (DTM Agent MCP)
- `dtm_status` — Check auth and active account/container
- `dtm_set_account` / `dtm_set_container` — Switch context
- `dtm_list_tags` / `dtm_get_tag` / `dtm_create_tag` / `dtm_update_tag` / `dtm_delete_tag`
- `dtm_list_triggers` / `dtm_get_trigger` / `dtm_create_trigger` / `dtm_delete_trigger`
- `dtm_list_variables` / `dtm_get_variable` / `dtm_create_variable` / `dtm_delete_variable`
- `dtm_list_folders` / `dtm_list_workspaces` / `dtm_get_workspace_status`
- `dtm_list_versions` / `dtm_get_live_version` / `dtm_create_version`
### Browser Analysis (Chrome DevTools MCP)
- `navigate_page` — Load page for DOM analysis
- `evaluate_script` — Inspect forms, buttons, links, CSS selectors
- `take_snapshot` — Get page structure for trigger design
- `list_network_requests` — Verify tags fire after changes
### Reporting (Notion MCP)
- Write implementation plans and tag configurations to Notion
## Core Capabilities
### 1. Tag Creation via GTM API
Create tags directly in GTM — no manual pasting. The API handles workspace lifecycle automatically (auto-creates new workspace if current one is published).
**GA4 Event Tags:**
```
GA4 event tags use type "gaawe" with:
- eventName: the GA4 event name (snake_case)
- measurementIdOverride: {{GA4 Measurement ID variable}} (NOT measurementId)
- eventParameters: list of name/value maps
```
**CRITICAL: measurementIdOverride, NOT measurementId**
GA4 event tags inherit from config — use `measurementIdOverride` to reference the measurement ID variable. The API rejects `measurementId`.
### 2. Trigger Design from DOM Analysis
Analyze page DOM to design precise triggers:
```javascript
// Extract forms
(function(){var forms=document.querySelectorAll('form');return JSON.stringify(Array.from(forms).map(function(f){return{id:f.id,action:f.action,fields:Array.from(f.querySelectorAll('input,textarea,select')).map(function(el){return{name:el.name,type:el.type,id:el.id}})}}));})()
// Extract CTAs and buttons
(function(){return JSON.stringify(Array.from(document.querySelectorAll('a[class*="btn"],button,[role="button"]')).map(function(el){return{text:(el.textContent||'').trim().substring(0,50),href:el.href||'',classes:el.className,id:el.id}}));})()
```
**Trigger types:**
| Type | Use For | Key Parameter |
|------|---------|---------------|
| `linkClick` | `<a>` elements | `autoEventFilter` with CSS selector |
| `click` | Any element | `filter` on Click ID/Classes |
| `formSubmission` | Form submit | `filter` on Form ID |
| `customEvent` | dataLayer events | `custom_event_filter` on `{{_event}}` |
| `scrollDepth` | Scroll tracking | `verticalThresholdsPercent` |
| `timer` | Time on page | `interval`, `limit` |
| `domReady` | DOM loaded | No filter needed |
### 3. Custom HTML Generation (ES5 MANDATORY)
GTM Custom HTML uses a JavaScript compiler that does NOT support ES2020+.
**FORBIDDEN:**
```javascript
// NO: optional chaining, arrow functions, const/let, template literals,
// destructuring, spread, async/await
```
**REQUIRED:**
```javascript
// YES: var, function(){}, string concatenation, explicit property access
(function() {
var form = document.getElementById('contact-form');
if (!form) return;
form.addEventListener('submit', function() {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'generate_lead',
'lead_type': form.querySelector('#requestType').value
});
});
})();
```
### 4. Workspace Lifecycle Management
GTM workspaces become **read-only after publishing**. The DTM Agent auto-handles this:
- If create/update fails with "Workspace is already submitted"
- Auto-creates a new workspace
- Retries the operation
- Caches the workspace ID for subsequent calls
**You don't need to manage workspaces manually.** Just call `dtm_create_tag` etc. and it works.
### 5. DataLayer Code Generation
Generate dataLayer push code for common tracking scenarios:
**E-commerce:**
```javascript
// purchase event
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null }); // Clear previous
window.dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': /* order ID */,
'currency': 'KRW',
'value': /* total */,
'items': [{ item_id: '', item_name: '', price: 0, quantity: 1 }]
}
});
```
**Forms/Leads:**
```javascript
window.dataLayer.push({
'event': 'generate_lead',
'lead_type': /* form type */,
'form_id': /* form element ID */
});
```
## Korean Market Patterns
| Context | Pattern |
|---------|---------|
| Currency | KRW (no decimals) |
| Payment buttons | 장바구니, 결제하기, 주문하기, 문의하기 |
| Payment methods | 카카오페이, 네이버페이, 토스, 신용카드 |
| Platforms | Kakao Pixel (`track.kakao.com`), Naver Analytics (`wcs.naver.net`) |
## Supported Tag Types
| GTM Type | Name | Platform |
|----------|------|----------|
| `googtag` | Google Tag | GA4 config |
| `gaawe` | GA4 Event | GA4 events |
| `gclidw` | Conversion Linker | Google Ads |
| `awct` | Ads Conversion | Google Ads |
| `html` | Custom HTML | Any (Meta, PostHog, Kakao, etc.) |
| `cvt_MQDKZ` | Clarity | Microsoft Clarity |
| `cvt_WF3R3` | Amplitude | Amplitude |
## FB Conversions API Integration
When creating tags that should trigger FB CAPI:
1. Check existing FBEventName mapping table (Regex Table variable)
2. If your custom event isn't mapped, add a new rule: `event_name → FB_Standard_Event`
3. Key mappings: `generate_lead → Lead`, `purchase → Purchase`, `page_view → PageView`
## Workflow
1. **Analyze**: Use Chrome DevTools to inspect the page (or receive from gtm-audit Mode D)
2. **Design**: Determine events, triggers, variables needed
3. **Create**: Use DTM Agent MCP tools to create in GTM
4. **Verify**: Hand off to gtm-validator for QA
5. **Document**: Write implementation details to Notion
## Rules
- Always use `dtm_status` first to verify auth and active container
- Always use `measurementIdOverride` for GA4 event tags (NOT `measurementId`)
- All Custom HTML must be ES5-compatible
- Use `--dry-run` conceptually — verify trigger selectors via Chrome DevTools before creating
- Rate limit: space API calls 1 second apart in batch operations
- Never delete tags without explicit user confirmation — move to Archive folder instead
- After creating tags, suggest user run gtm-validator to verify

View File

@@ -0,0 +1,224 @@
---
name: gtm-validator
description: >
GTM QA and validation toolkit. Verifies tags fire correctly on live pages,
tests trigger conditions against actual DOM, validates dataLayer schemas,
checks naming conventions, compares cross-platform events, and runs QA checklists.
Uses Chrome DevTools MCP for live page testing.
Triggers on "validate tags", "check triggers", "verify tracking", "QA GTM",
"test events", "debug GTM", "troubleshoot", "naming conventions",
"GTM question", "GTM best practice", "compare versions".
NOT for auditing (use gtm-audit) or creating/modifying (use gtm-editor).
---
# GTM Validator Skill
Verify GTM implementations work correctly on live pages. Test triggers, validate dataLayer, check naming conventions.
## Available Tools
### Browser Testing (Chrome DevTools MCP)
- `navigate_page` — Load page to test
- `evaluate_script` — Check dataLayer state, test selectors, verify globals
- `list_network_requests` — Verify tag firing after interactions
- `click` / `hover` — Simulate user actions to trigger events
- `list_console_messages` — Check for JS errors
- `take_screenshot` — Document test results
### GTM Container (DTM Agent MCP)
- `dtm_status` — Check active container
- `dtm_list_tags` / `dtm_get_tag` — Get tag configurations
- `dtm_list_triggers` / `dtm_get_trigger` — Get trigger conditions
- `dtm_list_variables` / `dtm_get_variable` — Get variable definitions
- `dtm_list_versions` / `dtm_get_live_version` — Compare versions
## Validation Modes
### 1. Tag Firing Verification
Test that specific tags fire on the correct pages and interactions.
**Steps:**
1. `dtm_list_tags` — get all active tags with their triggers
2. `navigate_page` to target URL
3. `list_network_requests` — capture initial tag firings
4. For click triggers: `click` the element, then check `list_network_requests` again
5. Compare: expected tags (from GTM config) vs actual network requests
**Verification script for specific tag:**
```javascript
// Check if GA4 event fired
(function(){
var dl = window.dataLayer || [];
var events = dl.filter(function(e){return e.event && e.event !== 'gtm.js' && e.event !== 'gtm.dom' && e.event !== 'gtm.load';});
return JSON.stringify(events.map(function(e){return {event: e.event, params: Object.keys(e).filter(function(k){return k !== 'event' && !k.startsWith('gtm.')})}}));
})()
```
### 2. Trigger Condition Testing
Verify trigger CSS selectors and conditions match the actual page DOM.
**Steps:**
1. `dtm_get_trigger` — get trigger filter/autoEventFilter
2. Extract CSS selectors from trigger config
3. `evaluate_script` — test if selectors match elements on page:
```javascript
// Test CSS selector
(function(selector){
var els = document.querySelectorAll(selector);
return JSON.stringify({
selector: selector,
matchCount: els.length,
elements: Array.from(els).slice(0,5).map(function(el){
return {tag: el.tagName, id: el.id, classes: el.className, text: (el.textContent||'').trim().substring(0,30)};
})
});
})('.hero a.btn')
```
4. If selector matches 0 elements → trigger will NEVER fire → **CRITICAL issue**
5. If selector matches too many elements → trigger may fire incorrectly → **WARNING**
### 3. DataLayer Schema Validation
Verify dataLayer pushes contain required fields with correct types.
**GA4 Recommended Event Schemas:**
| Event | Required Fields |
|-------|----------------|
| `page_view` | (automatic) |
| `generate_lead` | — (value, currency optional) |
| `purchase` | transaction_id, value, currency, items[] |
| `add_to_cart` | items[] (item_id, item_name, price, quantity) |
| `form_start` | form_id, form_name |
| `form_submit` | form_id, form_name |
**Validation script:**
```javascript
// Check dataLayer for specific event schema
(function(eventName){
var dl = window.dataLayer || [];
var events = dl.filter(function(e){return e.event === eventName;});
if(events.length === 0) return JSON.stringify({found: false, event: eventName});
var e = events[events.length-1];
return JSON.stringify({found: true, event: eventName, keys: Object.keys(e), data: e});
})('generate_lead')
```
### 4. Naming Convention Check
Verify all GTM resources follow D.intelligence naming standards.
**Tag naming:**
```
[Platform] - [event_name] [context]
Examples:
GA4 - generate_lead (contact form)
sGTM - purchase
cHTML - Contact Form dataLayer Events
FB_CONVERSIONS_API-PIXEL_ID-Web-Tag-GA4_Event
```
**Trigger naming:**
```
[Type] - [description] Trigger
Examples:
Click - Hero CTA (consult)
CE - contact_form_submit
Form Submit - contact-form
Scroll - 50pct Depth
PV - consult booking Trigger
```
**Variable naming:**
```
[prefix] - [description]
Prefixes: dlv (dataLayer), cjs (Custom JS), aev (Auto-Event),
jsv (JS Variable), URL query, cookie, c (Constant)
Examples:
dlv - contact_form.request_type
cjs - Social platform
aev - click url hostname
```
**Validation steps:**
1. `dtm_list_tags` / `dtm_list_triggers` / `dtm_list_variables`
2. Check each name against patterns above
3. Flag violations: missing prefix, wrong case, unclear description
### 5. Cross-Platform Event Mapping Verification
Verify the same user action sends consistent events to all platforms.
| User Action | GA4 | Meta (FB) | Google Ads | Kakao | Naver |
|------------|-----|-----------|------------|-------|-------|
| Page view | page_view | PageView | — | pageView | — |
| Product view | view_item | ViewContent | — | viewContent | — |
| Add to cart | add_to_cart | AddToCart | — | addToCart | — |
| Purchase | purchase | Purchase | purchase | purchase | — |
| Lead form | generate_lead | Lead | submit_lead_form | participation | — |
**Steps:**
1. Trigger a user action (click, form submit)
2. `list_network_requests` — capture all resulting requests
3. Check each platform received the correct event:
- GA4: `google-analytics.com/g/collect?en=...`
- Meta: `facebook.com/tr/?ev=...`
- Google Ads: `googleads.g.doubleclick.net/pagead/...`
### 6. QA Checklist Execution
Run through a standard QA checklist for GTM implementation:
- [ ] GTM container snippet in `<head>` (not `<body>`)
- [ ] GTM noscript fallback in `<body>`
- [ ] No duplicate GTM containers on same page
- [ ] dataLayer initialized before GTM snippet
- [ ] All P1 tags fire on page load (GA4 config, Consent Mode)
- [ ] Click triggers use specific selectors (not generic classes)
- [ ] Form triggers match form IDs that exist on page
- [ ] Custom HTML tags use ES5 syntax only
- [ ] No console errors related to GTM/tags
- [ ] Consent Mode properly blocks tags before consent
- [ ] sGTM endpoint responding (no SSL errors)
- [ ] Cross-domain tracking configured if needed
### 7. Version Comparison
Compare tags between two container versions to identify changes.
1. `dtm_list_versions` — get version list
2. `dtm_get_live_version` — get current live version with all tags
3. Compare tag counts, trigger counts, new/modified/deleted items
4. Report changes since last publish
## Reference Files
| File | Content |
|------|---------|
| `references/datalayer-schema.md` | GA4 recommended event schemas |
| `references/platform-mapping.md` | GA4 ↔ Meta ↔ Kakao ↔ Ads event mapping |
| `references/naming-conventions.md` | Tag/trigger/variable naming rules |
| `references/qa-checklist.md` | Full QA checklist |
## Workflow
1. **Receive** tag list from gtm-editor (or run `dtm_list_tags`)
2. **Navigate** to the target page via Chrome DevTools
3. **Test** each trigger's CSS selector matches actual DOM elements
4. **Simulate** user actions (clicks, form submits, scrolls)
5. **Capture** network requests after each action
6. **Verify** correct events fired to correct platforms
7. **Report** pass/fail with evidence (screenshots, network logs)
## Rules
- Always test on the LIVE published version, not preview (unless debugging)
- Test on both desktop and mobile viewports when possible
- Check consent mode state before flagging missing tags
- Document every test result with screenshots or network request evidence
- If a trigger selector doesn't match, suggest a fix and hand off to gtm-editor
- GTM questions, best practices, and architecture advice are also in scope

View File

@@ -0,0 +1,193 @@
# DataLayer Schema Reference
GA4 권장 이벤트 기반 DataLayer 스키마 정의.
## Core Principles
1. GTM 스니펫 이전에 dataLayer 초기화
2. 이벤트 발생 시점에 push (사전 아님)
3. ecommerce 객체는 push 전 clear 필수
4. PII 데이터 직접 수집 금지
## Base Structure
### Page Load
```javascript
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'page_data',
'page': {
'type': 'home|category|product|cart|checkout|thankyou|content|search',
'name': 'Page Name',
'category': 'Category/Subcategory',
'language': 'ko'
},
'user': {
'status': 'logged_in|logged_out',
'id': 'hashed_user_id', // SHA256, 로그인 시에만
'type': 'new|returning|member|guest',
'loginMethod': 'email|kakao|naver|google'
}
});
```
## E-commerce Events
### view_item
```javascript
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'view_item',
'ecommerce': {
'currency': 'KRW',
'value': 29000,
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Product Name',
'item_brand': 'Brand Name',
'item_category': 'Category',
'item_variant': 'Blue / Large',
'price': 29000,
'quantity': 1
}]
}
});
```
### add_to_cart
```javascript
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'currency': 'KRW',
'value': 29000,
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Product Name',
'price': 29000,
'quantity': 1
}]
}
});
```
### begin_checkout
```javascript
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'begin_checkout',
'ecommerce': {
'currency': 'KRW',
'value': 58000,
'coupon': 'WELCOME10',
'items': [/* cart items */]
}
});
```
### purchase
```javascript
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T_20250115_001',
'affiliation': 'Store Name',
'value': 53000,
'tax': 4818,
'shipping': 3000,
'currency': 'KRW',
'coupon': 'WELCOME10',
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Product Name',
'price': 29000,
'quantity': 1
}]
}
});
```
## Lead Gen Events
### generate_lead
```javascript
dataLayer.push({
'event': 'generate_lead',
'currency': 'KRW',
'value': 50000,
'lead': {
'source': 'contact_form|landing_page',
'type': 'inquiry|quote_request'
}
});
```
### form_submit
```javascript
dataLayer.push({
'event': 'form_submit',
'form': {
'id': 'contact_form',
'name': 'Contact Us Form',
'type': 'contact',
'success': true
}
});
```
## Engagement Events
### login / sign_up
```javascript
dataLayer.push({
'event': 'login', // or 'sign_up'
'method': 'email|kakao|naver|google'
});
```
### search
```javascript
dataLayer.push({
'event': 'search',
'search_term': 'user search query',
'search': {
'results_count': 42,
'category': 'product|content'
}
});
```
## Item Object Reference
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| item_id | string | Yes | SKU |
| item_name | string | Yes | 상품명 |
| price | number | Yes | 단가 |
| quantity | number | Yes | 수량 |
| item_brand | string | No | 브랜드명 |
| item_category | string | No | 카테고리 |
| item_category2-5 | string | No | 하위 카테고리 |
| item_variant | string | No | 옵션 |
| coupon | string | No | 쿠폰 코드 |
| discount | number | No | 할인 금액 |
| index | number | No | 목록 위치 |
## Validation Rules
```javascript
// ✅ Correct
'price': 29000 // number
'quantity': 1 // number
'currency': 'KRW' // uppercase
// ❌ Wrong
'price': '29000' // string
'currency': 'krw' // lowercase
```
### Array Limits
- items[]: 최대 200개
- 초과 시 분할 전송

View File

@@ -0,0 +1,130 @@
# GTM Naming Conventions
일관된 GTM 컨테이너 관리를 위한 네이밍 규칙.
## Tag Naming
### Pattern
```
[Platform] - [Type] - [Description]
```
### Examples
| Platform | Type | Description | Tag Name |
|----------|------|-------------|----------|
| GA4 | Config | Main | GA4 - Config - Main |
| GA4 | Event | purchase | GA4 - Event - purchase |
| GAds | Conversion | Purchase | GAds - Conversion - Purchase |
| Meta | Event | Purchase | Meta - Event - Purchase |
| Kakao | Event | purchase | Kakao - Event - purchase |
## Trigger Naming
### Pattern
```
[Type] - [Condition] - [Context]
```
### Type Codes
| Code | Type | Example |
|------|------|---------|
| PV | Page View | PV - All Pages |
| DL | DataLayer Event | DL - purchase |
| Click | Click | Click - CTA Button |
| Form | Form Submit | Form - Contact |
| Scroll | Scroll Depth | Scroll - 75% |
| Vis | Element Visibility | Vis - Video Player |
### Examples
```
PV - All Pages
PV - Thank You Page
DL - purchase
DL - add_to_cart
Click - CTA Button - Hero
Form - Contact Form
Scroll - 90%
```
## Variable Naming
### Pattern
```
[Type] - [Name/Path]
```
### Type Codes
| Code | Type | Example |
|------|------|---------|
| DLV | DataLayer Variable | DLV - ecommerce.value |
| CJS | Custom JavaScript | CJS - Item IDs Array |
| Const | Constant | Const - GA4 Measurement ID |
| LT | Lookup Table | LT - Page Type Mapping |
| URL | URL Variable | URL - Path |
| DOM | DOM Element | DOM - Product Title |
### Examples
```
DLV - event
DLV - ecommerce.transaction_id
DLV - ecommerce.items
CJS - Items for Meta
CJS - Formatted Price
Const - GA4 Measurement ID
Const - Meta Pixel ID
LT - Payment Method Mapping
```
## Folder Structure
```
📁 01. Configuration
📁 02. GA4 Events
📁 03. Google Ads
📁 04. Meta Pixel
📁 05. Kakao Pixel
📁 06. Other Platforms
📁 07. Utilities
📁 99. Deprecated
```
## Built-in Variables to Enable
```
Pages: ✅ Page URL, Path, Hostname, Referrer
Utilities: ✅ Event, Container ID, Random Number
Clicks: ✅ Element, Classes, ID, URL, Text
Forms: ✅ Element, Classes, ID, URL, Text
History: ✅ New/Old History Fragment/State
Videos: ✅ All YouTube variables
Scrolling: ✅ Depth Threshold, Units, Direction
Visibility: ✅ Percent Visible, On-Screen Duration
```
## Anti-patterns
```
❌ Tag 1, New Tag, Test
❌ GA4 purchase event (일관성 없음)
❌ G4-E-Pch (과도한 약어)
❌ Very Long Tag Name for Purchase Complete Event (너무 김)
✅ GA4 - Event - purchase
✅ DL - purchase
✅ CJS - Items for Meta
```
## Version Notes
```
v[Major].[Minor] - [Description]
예: v12.1 - Added form_submit event
## Changes
- Added:
- Modified:
- Removed:
## Reason
[변경 이유]
```

View File

@@ -0,0 +1,215 @@
# Phase 6: Progressive Audit & Update
설정된 GTM Container에 대한 주기적 진단, 유효성 검증, 마이너 업데이트 및 태그 추가.
## Objectives
1. GTM 컨테이너 건강 상태 점검
2. 태그 발화 및 데이터 정합성 검증
3. 최신 요구사항 반영 업데이트
4. D.intelligence GTM Toolkit 연계 자동화
## Audit Schedule
| Frequency | Scope | Trigger |
|-----------|-------|---------|
| Weekly | Tag firing validation | 자동 스케줄 |
| Monthly | Full container review | 월간 리포트 |
| Quarterly | Architecture review | 분기 회의 |
| Ad-hoc | Issue investigation | 이슈 발생 시 |
## Audit Checklist
### 1. Container Health Check
- [ ] 버전 히스토리 확인 (최근 변경사항)
- [ ] 미사용 태그/트리거/변수 식별
- [ ] 명명 규칙 준수 여부
- [ ] 폴더 구조 정리 상태
### 2. Tag Firing Validation
- [ ] 모든 P1 태그 정상 발화
- [ ] 트리거 조건 정확성
- [ ] 변수 값 정확성
- [ ] 차단 트리거 작동
### 3. Data Quality
- [ ] GA4 Realtime 데이터 확인
- [ ] 전환 데이터 정합성
- [ ] 파라미터 값 검증
- [ ] 이상치 탐지
### 4. Platform Sync
- [ ] GA4 ↔ GTM 동기화
- [ ] Google Ads 전환 데이터
- [ ] Meta Events Manager 상태
- [ ] Kakao Pixel 상태
## D.intelligence GTM Toolkit Integration
### Repository
```
https://github.com/ourdigital/dintel-gtm-toolkit
```
### Capabilities
| Feature | Description | Use Case |
|---------|-------------|----------|
| Container Analysis | JSON 파싱, 구조 분석 | 컨테이너 리뷰 |
| Dependency Mapping | 태그↔트리거↔변수 관계 | 영향도 분석 |
| Version Diff | 버전 간 변경사항 비교 | 변경 추적 |
| Tag Validation | 발화 상태 자동 검증 | 정기 감사 |
### Integration Workflow
```
1. GTM Container Export
└── JSON 파일 다운로드
2. D.intel Toolkit Analysis
├── python analyze_container.py container.json
├── Dependency graph 생성
└── Issue detection
3. Report Generation
└── Markdown/HTML 리포트
4. GTM Guardian Update
└── Notion에 리포트 저장
```
### Sample Toolkit Commands
```bash
# Container 분석
python analyze_container.py GTM-XXXXXX.json --output report.md
# 버전 비교
python diff_versions.py v1.json v2.json --output diff.md
# 태그 검증
python validate_tags.py container.json --events events.csv
# 미사용 요소 탐지
python find_unused.py container.json --type all
```
## Audit Report Template
```markdown
# GTM Audit Report
## Summary
- **Container**: GTM-XXXXXX
- **Audit Date**: YYYY-MM-DD
- **Version Reviewed**: XX
- **Overall Status**: ✅ Healthy / ⚠️ Needs Attention / ❌ Critical
## Findings
### ✅ Passing
- [항목]
### ⚠️ Warnings
| Issue | Impact | Recommendation |
|-------|--------|----------------|
### ❌ Critical
| Issue | Impact | Action Required |
|-------|--------|-----------------|
## Tag Firing Status
| Tag | Expected | Actual | Status |
|-----|----------|--------|--------|
| GA4 - Event - purchase | Thank You | Thank You | ✅ |
## Data Quality Check
| Metric | Expected | Actual | Variance |
|--------|----------|--------|----------|
| Daily Purchases | ~50 | 48 | -4% |
## Recommendations
1.
2.
## Next Steps
- [ ]
- [ ]
## Appendix
- Container JSON snapshot
- D.intel Toolkit output
```
## Update Procedures
### Minor Update (태그 수정)
```
1. 변경 필요 태그 식별
2. Preview 모드에서 수정
3. 테스트 완료
4. Publish with version note
5. Notion 문서 업데이트
```
### Major Update (신규 태그 추가)
```
1. Phase 3-4 문서 업데이트
2. DataLayer 요구사항 개발팀 전달
3. GTM 태그/트리거/변수 설정
4. QA 체크리스트 수행
5. 단계적 배포
6. Notion 문서 업데이트
```
### Emergency Fix
```
1. 이슈 원인 파악
2. 최소 변경으로 수정
3. Publish (emergency version note)
4. 근본 원인 분석
5. 영구 수정 계획
```
## Versioning Best Practices
### Version Naming
```
v[Major].[Minor] - [Description]
예: v12.1 - Added form_submit event
```
### Version Notes Template
```
## Changes
- Added: [새로 추가된 항목]
- Modified: [수정된 항목]
- Removed: [삭제된 항목]
## Reason
[변경 이유]
## Testing
- [테스트 항목 및 결과]
## Rollback Plan
[롤백 필요 시 절차]
```
## Monitoring Setup
### GA4 Alerts
- 일일 전환 수 급감 (>30%)
- 세션 수 급감 (>50%)
- 이벤트 수집 오류
### Custom Monitoring
- DataLayer 오류 로깅
- Tag Manager 오류 추적
- 서버 사이드 태그 상태 (sGTM 시)
## Next Phase
주기적 감사 완료 후 → Phase 7: Lookup App (필요 시)

View File

@@ -0,0 +1,283 @@
# Phase 7: Event Lookup & Parameter Library Web App
Google Apps Script를 활용한 Event Taxonomy Sheet 기반 업무 지원용 앱 배포.
## Objectives
1. Event Taxonomy 데이터 조회 앱
2. 실시간 파라미터 참조 도구
3. 비개발자용 Self-service 도구
4. 팀 간 일관된 이벤트 정보 공유
## App Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Google Sheets │────▶│ Apps Script │────▶│ Web App │
│ (Taxonomy DB) │ │ (Backend) │ │ (Frontend) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## Google Sheets Data Source
### Required Sheets
- Events Master
- Parameters Reference
- Custom Definitions
- Platform Mapping
### Column Requirements
→ Phase 4 참조: [phase4-taxonomy.md](phase4-taxonomy.md)
## Apps Script Setup
### 1. Project Creation
```
1. Google Sheets 열기
2. Extensions > Apps Script
3. 프로젝트 이름 설정
```
### 2. Core Functions
#### Data Retrieval
```javascript
function getEventsData() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Events Master');
const data = sheet.getDataRange().getValues();
const headers = data[0];
return data.slice(1).map(row => {
const obj = {};
headers.forEach((header, i) => {
obj[header] = row[i];
});
return obj;
});
}
function getParametersData() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Parameters Reference');
const data = sheet.getDataRange().getValues();
const headers = data[0];
return data.slice(1).map(row => {
const obj = {};
headers.forEach((header, i) => {
obj[header] = row[i];
});
return obj;
});
}
```
#### Search Function
```javascript
function searchEvents(query) {
const events = getEventsData();
const searchTerm = query.toLowerCase();
return events.filter(event =>
event.event_name.toLowerCase().includes(searchTerm) ||
event.event_category.toLowerCase().includes(searchTerm) ||
event.notes.toLowerCase().includes(searchTerm)
);
}
function getEventDetails(eventName) {
const events = getEventsData();
const params = getParametersData();
const event = events.find(e => e.event_name === eventName);
if (!event) return null;
const eventParams = event.parameters.split(',').map(p => p.trim());
const paramDetails = params.filter(p =>
eventParams.includes(p.parameter_name)
);
return {
event: event,
parameters: paramDetails
};
}
```
### 3. Web App Handler
```javascript
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('GTM Event Lookup')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function doPost(e) {
const action = e.parameter.action;
switch(action) {
case 'search':
return ContentService.createTextOutput(
JSON.stringify(searchEvents(e.parameter.query))
).setMimeType(ContentService.MimeType.JSON);
case 'details':
return ContentService.createTextOutput(
JSON.stringify(getEventDetails(e.parameter.eventName))
).setMimeType(ContentService.MimeType.JSON);
default:
return ContentService.createTextOutput(
JSON.stringify({error: 'Invalid action'})
).setMimeType(ContentService.MimeType.JSON);
}
}
```
### 4. HTML Frontend (index.html)
```html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
body { font-family: 'Roboto', sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; }
.search-box { width: 100%; padding: 12px; font-size: 16px; margin-bottom: 20px; }
.event-card { border: 1px solid #ddd; padding: 16px; margin: 10px 0; border-radius: 8px; }
.event-name { font-size: 18px; font-weight: bold; color: #1a73e8; }
.param-badge { background: #e8f0fe; color: #1967d2; padding: 4px 8px; border-radius: 4px; margin: 2px; display: inline-block; }
.category { color: #5f6368; font-size: 14px; }
.priority-p1 { border-left: 4px solid #ea4335; }
.priority-p2 { border-left: 4px solid #fbbc04; }
.priority-p3 { border-left: 4px solid #34a853; }
</style>
</head>
<body>
<h1>🏷️ GTM Event Lookup</h1>
<input type="text" class="search-box" id="searchInput" placeholder="이벤트명 또는 카테고리 검색...">
<div id="results"></div>
<script>
const searchInput = document.getElementById('searchInput');
const results = document.getElementById('results');
searchInput.addEventListener('input', debounce(function() {
const query = this.value;
if (query.length < 2) {
results.innerHTML = '';
return;
}
google.script.run
.withSuccessHandler(displayResults)
.searchEvents(query);
}, 300));
function displayResults(events) {
results.innerHTML = events.map(event => `
<div class="event-card priority-${event.priority.toLowerCase()}">
<div class="event-name">${event.event_name}</div>
<div class="category">${event.event_category} | ${event.priority}</div>
<div style="margin-top: 10px;">
${event.parameters.split(',').map(p =>
`<span class="param-badge">${p.trim()}</span>`
).join('')}
</div>
<div style="margin-top: 10px; color: #5f6368;">${event.notes}</div>
</div>
`).join('');
}
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
</script>
</body>
</html>
```
## Deployment
### 1. Deploy as Web App
```
1. Deploy > New deployment
2. Type: Web app
3. Execute as: Me
4. Access: Anyone within organization (또는 Anyone)
5. Deploy
```
### 2. Get Web App URL
```
배포 후 제공되는 URL 복사
https://script.google.com/macros/s/[ID]/exec
```
### 3. Share with Team
- URL을 Notion/Slack에 공유
- 북마크 권장
## Features Roadmap
### Phase 1 (MVP)
- [x] 이벤트 검색
- [x] 파라미터 조회
- [x] 우선순위 필터
### Phase 2
- [ ] DataLayer 코드 스니펫 복사
- [ ] 플랫폼별 코드 예시
- [ ] 최근 조회 히스토리
### Phase 3
- [ ] 이벤트 추가/수정 폼
- [ ] 변경 이력 추적
- [ ] Slack 알림 연동
## Maintenance
### Data Update
1. Google Sheets 원본 데이터 수정
2. Web App 자동 반영 (실시간)
### Code Update
1. Apps Script 수정
2. Deploy > Manage deployments
3. New version 배포
### Backup
- Google Sheets 자동 버전 히스토리
- 주기적 수동 백업 권장
## Access Control
| Role | Access Level |
|------|--------------|
| Admin | 시트 편집 + 스크립트 수정 |
| Editor | 시트 편집 |
| Viewer | Web App 조회만 |
## Troubleshooting
| Issue | Solution |
|-------|----------|
| 앱 로딩 느림 | 데이터 캐싱 구현 |
| 검색 결과 없음 | 검색어 확인, 데이터 존재 확인 |
| 권한 오류 | 배포 설정에서 접근 권한 확인 |
| 데이터 미반영 | 시트 새로고침, 캐시 클리어 |
## Integration with Notion
Web App URL을 Notion에 embed:
```
/embed [Web App URL]
```
또는 iframe으로 직접 삽입.

View File

@@ -0,0 +1,125 @@
# Platform Event Mapping Reference
GA4, Google Ads, Meta Pixel, Kakao Pixel 간 이벤트 매핑.
## E-commerce Events
| User Action | GA4 | Meta | Kakao | Google Ads |
|-------------|-----|------|-------|------------|
| 상품 목록 조회 | view_item_list | ViewContent | viewContent | - |
| 상품 상세 조회 | view_item | ViewContent | viewContent | - |
| 상품 검색 | search | Search | search | - |
| 장바구니 담기 | add_to_cart | AddToCart | addToCart | - |
| 위시리스트 | add_to_wishlist | AddToWishlist | addToWishlist | - |
| 결제 시작 | begin_checkout | InitiateCheckout | beginCheckout | - |
| 배송정보 입력 | add_shipping_info | - | - | - |
| 결제정보 입력 | add_payment_info | AddPaymentInfo | addPaymentInfo | - |
| 구매 완료 | purchase | Purchase | purchase | purchase |
## Lead Gen Events
| User Action | GA4 | Meta | Kakao | Google Ads |
|-------------|-----|------|-------|------------|
| 회원가입 | sign_up | CompleteRegistration | completeRegistration | sign_up |
| 로그인 | login | - | login | - |
| 리드 생성 | generate_lead | Lead | participation | submit_lead_form |
## Engagement Events
| User Action | GA4 | Meta | Kakao | Google Ads |
|-------------|-----|------|-------|------------|
| 페이지 조회 | page_view | PageView | pageView | page_view |
| 검색 | search | Search | search | - |
| 공유 | share | - | - | - |
## Parameter Transformation
### GA4 → Meta
```javascript
// GA4 items[] → Meta content_ids[]
const contentIds = items.map(item => item.item_id);
// Meta Purchase
fbq('track', 'Purchase', {
content_ids: contentIds,
content_type: 'product',
value: ecommerce.value,
currency: 'KRW',
num_items: items.length
});
```
### GA4 → Kakao
```javascript
// GA4 items[] → Kakao products[]
const products = items.map(item => ({
id: item.item_id,
name: item.item_name,
price: item.price,
quantity: item.quantity
}));
// Kakao purchase
kakaoPixel('PIXEL_ID').purchase({
total_price: ecommerce.value,
currency: 'KRW',
products: products
});
```
## GTM Variables
### CJS - Item IDs for Meta
```javascript
function() {
var items = {{DLV - ecommerce.items}} || [];
return items.map(function(item) {
return item.item_id;
});
}
```
### CJS - Products for Kakao
```javascript
function() {
var items = {{DLV - ecommerce.items}} || [];
return items.map(function(item) {
return {
id: item.item_id,
name: item.item_name,
price: item.price,
quantity: item.quantity
};
});
}
```
## Deduplication
### Event ID Pattern
```javascript
var eventId = 'evt_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
// Client-side
fbq('track', 'Purchase', {...}, {eventID: eventId});
// Server-side (CAPI)
// 동일한 eventId 사용 → Meta 자동 중복 제거
```
## Platform-specific Notes
### Meta Pixel
- content_type: 'product' (상품) / 'product_group' (변형)
- currency: ISO 4217 필수
- value: 숫자 (소수점 가능)
### Kakao Pixel
- Server-side 미지원 (Client-only)
- products[]: 최대 10개 권장
- total_price: 숫자
### Google Ads
- Enhanced Conversions 권장
- transaction_id 필수 (중복 제거용)
- value: KRW 정수

View File

@@ -0,0 +1,149 @@
# GTM Implementation QA Checklist
태깅 구현 품질 검증 체크리스트.
## 1. Pre-Implementation
### Documentation
- [ ] Tagging Plan 승인 완료
- [ ] DataLayer 스키마 개발팀 공유
- [ ] 이벤트 택소노미 합의 완료
### Access
- [ ] GTM 컨테이너 접근 권한
- [ ] GA4 속성 접근 권한
- [ ] 광고 플랫폼 접근 권한
### Tools
- [ ] GTM Preview 모드 정상
- [ ] GA4 DebugView 활성화
- [ ] Chrome DevTools 준비
## 2. DataLayer Validation
### Base Setup
- [ ] GTM 스니펫 이전 dataLayer 초기화
- [ ] 페이지 로드 시 기본 데이터 push
- [ ] pageType, userId 등 기본 변수 존재
### Data Types
- [ ] 숫자 값이 Number 타입
- [ ] 금액에 통화 코드 포함 (KRW)
- [ ] transaction_id 유니크
### E-commerce
- [ ] ecommerce: null 선행 push
- [ ] items[] 배열 구조 정확
- [ ] 필수 파라미터 완비
### Console Check
```javascript
console.log(window.dataLayer);
dataLayer.filter(e => e.event === 'purchase');
```
## 3. Tag Firing
### GA4
| Tag | Trigger | Status |
|-----|---------|--------|
| Config | All Pages | [ ] |
| view_item | Product page | [ ] |
| add_to_cart | Add button | [ ] |
| begin_checkout | Checkout start | [ ] |
| purchase | Thank you | [ ] |
### Google Ads
| Conversion | Trigger | Status |
|------------|---------|--------|
| Purchase | DL - purchase | [ ] |
| Lead | DL - generate_lead | [ ] |
### Meta Pixel
| Event | Trigger | Status |
|-------|---------|--------|
| PageView | All Pages | [ ] |
| ViewContent | Product | [ ] |
| AddToCart | Add | [ ] |
| Purchase | Thank you | [ ] |
### Kakao Pixel
| Event | Trigger | Status |
|-------|---------|--------|
| pageView | All Pages | [ ] |
| purchase | Thank you | [ ] |
## 4. Network Validation
### Endpoints
```
GA4: google-analytics.com/g/collect
GAds: googleads.g.doubleclick.net/pagead/conversion/
Meta: facebook.com/tr/
```
### Check Points
- [ ] 요청 전송됨
- [ ] 파라미터 정확
- [ ] 응답 성공 (200/204)
## 5. Cross-browser Testing
### Desktop
- [ ] Chrome
- [ ] Safari
- [ ] Firefox
- [ ] Edge
### Mobile
- [ ] iOS Safari
- [ ] iOS Chrome
- [ ] Android Chrome
## 6. Data Validation (Platform)
### GA4
- [ ] Realtime 보고서 이벤트 표시
- [ ] 파라미터 정확히 수집
- [ ] E-commerce 보고서 정확
### Google Ads
- [ ] 전환 액션 데이터 유입
- [ ] 전환 값 정확
### Meta
- [ ] Events Manager 수신 확인
- [ ] Event match quality 확인
## 7. Edge Cases
- [ ] 빈 장바구니 결제 시작 처리
- [ ] 0개 구매 처리
- [ ] 쿠폰 없는 구매
- [ ] 게스트 체크아웃
- [ ] 새로고침 시 중복 방지
- [ ] 뒤로가기 시 처리
## 8. Performance & Privacy
### Performance
- [ ] 태그 로딩이 렌더링 차단 안 함
- [ ] 비동기 로딩
### Privacy
- [ ] 동의 없이 태그 미발화 (CMP 시)
- [ ] PII 직접 수집 없음
## Sign-off
| Role | Name | Date | ✓ |
|------|------|------|---|
| QA Lead | | | |
| Analytics Lead | | | |
| Dev Lead | | | |
## Issues Log
| # | Issue | Severity | Status |
|---|-------|----------|--------|
| 1 | | High/Med/Low | Open/Resolved |