feat: update GTM skills triad with field-tested improvements
gtm-audit (60): - Added Mode D rule: check elements for IDs before designing CSS triggers gtm-editor (61): - Added "Tagging Workflow: dataLayer First" section — always suggest dataLayer push code for developers before creating GTM triggers - Added multi-language snippets (JS, React, Vue, PHP) - Added "Trigger Design: IDs First" section — prefer element IDs, ask user to add IDs before falling back to CSS selectors - Added ID naming convention: [section]-[element]-[action] - Added decision tree for trigger selection gtm-validator (62): - Flag CSS-based triggers as fragility risk during QA - Recommend adding IDs instead of finding alternative CSS selectors Based on field testing with ourdigital.org GTM-N9TPJW container. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -136,5 +136,6 @@ One GA4 page_view fires to multiple endpoints — this is normal:
|
||||
- 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
|
||||
- **In Mode D (tag design), check elements for `id` attributes** — if missing, recommend adding IDs before designing CSS-based triggers. Suggest naming: `[section]-[element]-[action]`
|
||||
- Hand off tag creation work to `gtm-editor` skill
|
||||
- Hand off QA/validation work to `gtm-validator` skill
|
||||
|
||||
@@ -34,6 +34,89 @@ Create, modify, and deploy GTM configurations via API. Generates ES5-compliant C
|
||||
### Reporting (Notion MCP)
|
||||
- Write implementation plans and tag configurations to Notion
|
||||
|
||||
## Tagging Workflow: dataLayer First (MANDATORY)
|
||||
|
||||
**Always push complexity into the dataLayer, not GTM triggers.**
|
||||
|
||||
### Step 1: Design the dataLayer push FIRST
|
||||
|
||||
Before creating any GTM configuration, design the `dataLayer.push()` that the website should implement. Present this to the user as a code snippet matching their tech stack:
|
||||
|
||||
**For vanilla JS / static HTML (ES5):**
|
||||
```javascript
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.dataLayer.push({
|
||||
'event': 'generate_lead',
|
||||
'lead_type': document.getElementById('requestType').value,
|
||||
'form_id': 'contact-form'
|
||||
});
|
||||
```
|
||||
|
||||
**For React / Next.js / TypeScript:**
|
||||
```typescript
|
||||
declare global { interface Window { dataLayer: Record<string, any>[]; } }
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.dataLayer.push({
|
||||
event: 'generate_lead',
|
||||
lead_type: selectedType,
|
||||
form_id: 'contact-form',
|
||||
});
|
||||
```
|
||||
|
||||
**For Vue:**
|
||||
```javascript
|
||||
window.dataLayer?.push({
|
||||
event: 'generate_lead',
|
||||
lead_type: this.selectedType,
|
||||
form_id: 'contact-form',
|
||||
});
|
||||
```
|
||||
|
||||
**For PHP / WordPress:**
|
||||
```php
|
||||
add_action('wp_footer', function() { ?>
|
||||
<script>
|
||||
document.getElementById('contact-form').addEventListener('submit', function() {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.dataLayer.push({
|
||||
'event': 'generate_lead',
|
||||
'lead_type': document.getElementById('requestType').value
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php });
|
||||
```
|
||||
|
||||
**ASK the user:** "Here's the dataLayer code for your developers. Can they add this to the page? What's your tech stack?"
|
||||
|
||||
### Step 2: Create simple GTM config
|
||||
|
||||
Once dataLayer push is agreed:
|
||||
- **Trigger:** Custom Event `{{_event}}` equals `generate_lead` (simple, robust)
|
||||
- **Variables:** DataLayer Variable for each parameter (e.g., `dlv - lead_type`)
|
||||
- **Tag:** GA4 Event with `measurementIdOverride` + DLV parameters
|
||||
|
||||
### Step 3: cHTML fallback (LAST RESORT)
|
||||
|
||||
Only if user confirms they CANNOT modify the website code:
|
||||
1. Create a Custom HTML tag that listens for DOM events
|
||||
2. The cHTML pushes to dataLayer internally
|
||||
3. A Custom Event trigger picks it up (same clean pattern)
|
||||
|
||||
**All cHTML must be ES5-compatible** (see ES5 section below).
|
||||
|
||||
### Decision Tree
|
||||
```
|
||||
Track user action?
|
||||
├─ Can devs add dataLayer.push()? → YES → Simple CE trigger ✅
|
||||
├─ Can't modify code, element has ID? → Use Click ID trigger ✅
|
||||
├─ No ID? → Ask user to add one first
|
||||
└─ Nothing possible? → cHTML + CE trigger (last resort)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
### 1. Tag Creation via GTM API
|
||||
@@ -175,10 +258,35 @@ When creating tags that should trigger FB CAPI:
|
||||
4. **Verify**: Hand off to gtm-validator for QA
|
||||
5. **Document**: Write implementation details to Notion
|
||||
|
||||
## Trigger Design: IDs First (MANDATORY)
|
||||
|
||||
**Always prefer element `id` over CSS selectors.** IDs survive redesigns; CSS selectors break.
|
||||
|
||||
**Before creating ANY click/form trigger:**
|
||||
1. Check if the target element has an `id` attribute via Chrome DevTools `evaluate_script`
|
||||
2. **If it has an ID** → use `Click ID` or `Form ID` filter
|
||||
3. **If it does NOT have an ID** → **ASK the user** before falling back to CSS:
|
||||
> "This element doesn't have an ID. Can you add one to the website/app code?
|
||||
> Suggested: `id="[section]-[element]-[action]"` e.g., `id="hero-btn-consult"`"
|
||||
4. Only use CSS selectors when the user explicitly confirms they cannot modify the HTML
|
||||
|
||||
**Priority order:**
|
||||
1. Element ID (`Click ID equals "hero-btn-consult"`)
|
||||
2. Data attribute (`Click Element matches CSS [data-track="consult"]`)
|
||||
3. Form ID (`Form ID equals "contact-form"`)
|
||||
4. CSS selector (last resort — document which selectors are used)
|
||||
|
||||
**Suggested ID naming:** `[section]-[element]-[action]`
|
||||
- Navigation: `nav-about`, `nav-services`, `nav-insights`
|
||||
- CTAs: `hero-btn-consult`, `cta-btn-booking`
|
||||
- Forms: `contact-form`, `newsletter-form`
|
||||
- Footer: `footer-social-linkedin`, `footer-email`
|
||||
|
||||
## Rules
|
||||
|
||||
- Always use `dtm_status` first to verify auth and active container
|
||||
- Always use `measurementIdOverride` for GA4 event tags (NOT `measurementId`)
|
||||
- **Always prefer element IDs for triggers — ask user to add IDs before using CSS selectors**
|
||||
- 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
|
||||
|
||||
@@ -220,5 +220,6 @@ Compare tags between two container versions to identify changes.
|
||||
- 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
|
||||
- **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
|
||||
|
||||
Reference in New Issue
Block a user