---
name: data-gtm-datalayer
description: Generate production-ready GTM tracking code with dataLayer pushes and HTML attributes. Use when adding analytics tracking.
allowed-tools: Read, Glob, Grep, Write($JAAN_OUTPUTS_DIR/**), Edit(jaan-to/config/settings.yaml)
argument-hint: [prd-path | tracking-description | (interactive)]
disable-model-invocation: true
license: MIT
compatibility: Designed for Claude Code with jaan-to plugin. Requires jaan-init setup.
---
# data-gtm-datalayer
> Generate production-ready GTM tracking code with enforced naming conventions.
## Context Files
- `$JAAN_LEARN_DIR/jaan-to-data-gtm-datalayer.learn.md` - Past lessons (loaded in Pre-Execution)
- `$JAAN_TEMPLATES_DIR/jaan-to-data-gtm-datalayer.template.md` - Output template
- `${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md` - Language resolution protocol
## Input
**Tracking Request**: $ARGUMENTS
- If PRD path provided → Read and suggest tracking points
- If text description provided → Design tracking based on input
- If empty → Start interactive wizard
---
## Pre-Execution Protocol
**MANDATORY** — Read and execute ALL steps in: `${CLAUDE_PLUGIN_ROOT}/docs/extending/pre-execution-protocol.md`
Skill name: `data-gtm-datalayer`
Execute: Step 0 (Init Guard) → A (Load Lessons) → B (Resolve Template) → C (Offer Template Seeding)
### Language Settings
Read and apply language protocol: `${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md`
Override field for this skill: `language_data-gtm-datalayer`
---
# PHASE 1: Analysis (Read-Only)
## Step 1: Determine Input Mode
Check $ARGUMENTS:
**Mode A - PRD Input:**
If path to `$JAAN_OUTPUTS_DIR/` or PRD text provided:
1. Read/parse the PRD
2. Identify trackable interactions (buttons, forms, modals, etc.)
3. Suggest tracking points with types:
- Impressions: modal displays, section visibility
- Clicks: buttons, links, interactive elements
- Include non-happy paths (close, dismiss, cancel)
4. Ask user to confirm/modify suggestions
**Mode B - Description Input:**
If text description of what to track:
1. Parse the description
2. Ask clarifying questions if needed
3. Suggest tracking structure
**Mode C - Interactive Wizard:**
If no arguments, ask questions in order:
### Question 1: Tracking Type
> "What type of tracking do you need?"
> 1. **click-html** - HTML attributes (data-al-*) for simple clicks
> 2. **click-datalayer** - dataLayer.push for flow-based clicks
> 3. **impression** - dataLayer.push for visibility/exposure events
### Question 2: Feature Name
> "What is the feature name? (e.g., player, checkout, onboarding)"
Apply naming rules:
- Convert to lowercase-kebab-case: "Play Button" → "play-button"
- If unclear (e.g., "btn1", "x"), ask: "What does '{input}' represent?"
- Suggest better name if abbreviated: "nav" → suggest "navigation" or "navbar"
- Confirm conversion: "Feature 'Play Button' → 'play-button' - OK? [y/edit]"
### Question 3: Item Name
> "What is the item name? (e.g., play, pause, submit, modal-purchase)"
Apply same naming rules as feature.
### Question 4: Action (click-datalayer only)
> "What is the action? (default: Click)"
If user provides custom action, apply naming rules.
If empty/skipped, use "Click".
### Question 5: Additional Params (optional)
> "Any additional params? Enter as key=value, one per line. (or 'skip')"
Example:
```
source=modal
count=3
active=true
```
Parse into object with **ES5 type detection**:
- `true` / `false` → bool (no quotes): `true`
- Numeric values (e.g., `3`, `42`) → int (no quotes): `3`
- Everything else → string (with quotes): `"modal"`
If none provided, omit params entirely from output.
## Step 2: Confirm Values
Show full dataLayer preview before generating:
**For click-html:**
```
TRACKING SUMMARY
────────────────────────────────────────
────────────────────────────────────────
```
**For click-datalayer (without params):**
```
TRACKING SUMMARY
────────────────────────────────────────
dataLayer.push({
event: "al_tracker_custom",
al: {
feature: "{feature}",
item: "{item}",
action: "{action}"
},
_clear: true
});
────────────────────────────────────────
```
**For click-datalayer (with params):**
```
TRACKING SUMMARY
────────────────────────────────────────
dataLayer.push({
event: "al_tracker_custom",
al: {
feature: "{feature}",
item: "{item}",
action: "{action}",
params: {
source: "modal",
count: 3,
active: true,
}
},
_clear: true
});
────────────────────────────────────────
```
Values are typed: strings in `"quotes"`, ints/bools without quotes.
**For impression (without params):**
```
TRACKING SUMMARY
────────────────────────────────────────
dataLayer.push({
event: "al_tracker_impression",
al: {
feature: "{feature}",
item: "{item}"
},
_clear: true
});
────────────────────────────────────────
```
**For impression (with params):**
```
TRACKING SUMMARY
────────────────────────────────────────
dataLayer.push({
event: "al_tracker_impression",
al: {
feature: "{feature}",
item: "{item}",
params: {
variant: "A",
position: 1,
visible: true,
}
},
_clear: true
});
────────────────────────────────────────
```
> "Generate tracking code with these values? [y/edit]"
---
# HARD STOP - Human Review Check
Show the full dataLayer preview above (not just field summary).
> "Proceed with code generation? [y/n/edit]"
**Do NOT proceed to Phase 2 without explicit approval.**
---
# PHASE 2: Generation (Write Phase)
## Step 3: Generate Code
Based on tracking type, generate the appropriate code:
### Type: click-html
```html
{element content}
```
Example output:
```html
```
### Type: click-datalayer
Without params:
```javascript
dataLayer.push({
event: "al_tracker_custom",
al: {
feature: "{feature}",
item: "{item}",
action: "{action}"
},
_clear: true
});
```
With params (ES5 typed values):
```javascript
dataLayer.push({
event: "al_tracker_custom",
al: {
feature: "{feature}",
item: "{item}",
action: "{action}",
params: {
{key1}: {value1}, // string: "value", int: 3, bool: true
{key2}: {value2},
}
},
_clear: true
});
```
### Type: impression
Without params:
```javascript
dataLayer.push({
event: "al_tracker_impression",
al: {
feature: "{feature}",
item: "{item}"
},
_clear: true
});
```
With params (ES5 typed values):
```javascript
dataLayer.push({
event: "al_tracker_impression",
al: {
feature: "{feature}",
item: "{item}",
params: {
{key1}: {value1}, // string: "value", int: 3, bool: true
{key2}: {value2},
}
},
_clear: true
});
```
## Step 4: Quality Check
Before preview, verify:
- [ ] `event` key present in all dataLayer pushes
- [ ] Feature and item are non-empty strings
- [ ] Feature/item/action are lowercase-kebab-case
- [ ] No abbreviations without user clarification
- [ ] Names are descriptive and understandable
- [ ] User-provided strings preserved (after kebab conversion)
- [ ] `_clear: true` included in all dataLayer pushes
- [ ] No empty `params: {}` (omit entirely if no params)
- [ ] Param values use correct ES5 types (string in `"quotes"`, int/bool without)
- [ ] Output is deterministic (same input → same code)
If any check fails, fix before preview.
## Step 5: Preview & Approval
Display the generated code in conversation:
```
GENERATED TRACKING CODE
───────────────────────
{code block}
EXAMPLE WITH VALUES
───────────────────
{example showing real values based on user input}
```
> "Save tracking code to output? [y/n]"
## Step 5.5: Generate ID and Folder Structure
If approved, set up the output structure:
1. Source ID generator utility:
```bash
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/id-generator.sh"
```
2. Generate sequential ID and output paths:
```bash
# Define subdomain directory
SUBDOMAIN_DIR="$JAAN_OUTPUTS_DIR/data/gtm"
mkdir -p "$SUBDOMAIN_DIR"
# Generate next ID
NEXT_ID=$(generate_next_id "$SUBDOMAIN_DIR")
# Create folder and file paths (slug from feature-item, e.g., "player-pause")
slug="{lowercase-hyphenated-feature-item}"
OUTPUT_FOLDER="${SUBDOMAIN_DIR}/${NEXT_ID}-${slug}"
MAIN_FILE="${OUTPUT_FOLDER}/${NEXT_ID}-gtm-${slug}.md"
```
3. Preview output configuration:
> **Output Configuration**
> - ID: {NEXT_ID}
> - Folder: $JAAN_OUTPUTS_DIR/data/gtm/{NEXT_ID}-{slug}/
> - Main file: {NEXT_ID}-gtm-{slug}.md
## Step 6: Write Output
1. Create output folder:
```bash
mkdir -p "$OUTPUT_FOLDER"
```
2. Write tracking code to main file using template:
```bash
# Use template from $JAAN_TEMPLATES_DIR/jaan-to-data-gtm-datalayer.template.md
cat > "$MAIN_FILE" <<'EOF'
{generated tracking documentation with Executive Summary}
EOF
```
3. Update subdomain index:
```bash
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/index-updater.sh"
add_to_index \
"$SUBDOMAIN_DIR/README.md" \
"$NEXT_ID" \
"${NEXT_ID}-${slug}" \
"{Tracking Title}" \
"{1-2 sentence summary: feature-item tracking with event type}"
```
4. Confirm completion:
> ✓ Tracking code written to: $JAAN_OUTPUTS_DIR/data/gtm/{NEXT_ID}-{slug}/{NEXT_ID}-gtm-{slug}.md
> ✓ Index updated: $JAAN_OUTPUTS_DIR/data/gtm/README.md
## Step 7: Capture Feedback
> "Any feedback? [y/n]"
If yes:
> "[1] Fix now [2] Learn for future [3] Both"
- **Option 1**: Update output, re-preview, re-write
- **Option 2**: Run `/jaan-to:learn-add data-gtm-datalayer "{feedback}"`
- **Option 3**: Do both
---
## Skill Alignment
- Two-phase workflow with HARD STOP for human approval
- Template-driven output structure
- Generic and tech-stack agnostic
- Output to standardized `$JAAN_OUTPUTS_DIR` path
## Definition of Done
- [ ] User confirmed tracking values
- [ ] Code generated and displayed in conversation
- [ ] Markdown file written to `$JAAN_OUTPUTS_DIR/data/gtm/{slug}/`
- [ ] User can copy-paste and use immediately