data-gtm-datalayer
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:
- Read/parse the PRD
- Identify trackable interactions (buttons, forms, modals, etc.)
- Suggest tracking points with types:
- Impressions: modal displays, section visibility
- Clicks: buttons, links, interactive elements
- Include non-happy paths (close, dismiss, cancel)
- Ask user to confirm/modify suggestions
Mode B - Description Input: If text description of what to track:
- Parse the description
- Ask clarifying questions if needed
- 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?"
- click-html - HTML attributes (data-al-*) for simple clicks
- click-datalayer - dataLayer.push for flow-based clicks
- 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
────────────────────────────────────────
<button data-al-feature="{feature}" data-al-item="{item}">...</button>
────────────────────────────────────────
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
<element data-al-feature="{feature}" data-al-item="{item}">{element content}</element>
Example output:
<button data-al-feature="player" data-al-item="pause">Pause</button>
Type: click-datalayer
Without params:
dataLayer.push({
event: "al_tracker_custom",
al: {
feature: "{feature}",
item: "{item}",
action: "{action}"
},
_clear: true
});
With params (ES5 typed values):
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:
dataLayer.push({
event: "al_tracker_impression",
al: {
feature: "{feature}",
item: "{item}"
},
_clear: true
});
With params (ES5 typed values):
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:
-
eventkey 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: trueincluded 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:
- Source ID generator utility:
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/id-generator.sh"
- Generate sequential ID and output paths:
# 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"
- 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
- Create output folder:
mkdir -p "$OUTPUT_FOLDER"
- Write tracking code to main file using template:
# Use template from $JAAN_TEMPLATES_DIR/jaan-to-data-gtm-datalayer.template.md
cat > "$MAIN_FILE" <<'EOF'
{generated tracking documentation with Executive Summary}
EOF
- Update subdomain index:
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}"
- 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_DIRpath
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