---
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
- **When a trigger uses CSS selectors instead of IDs, flag it as a fragility risk** — recommend adding `id` attributes to the HTML
- If a trigger selector doesn't match, suggest adding an ID to the element first (not a different CSS selector) and hand off to gtm-editor
- GTM questions, best practices, and architecture advice are also in scope
