gtm-implementation

安装量: 50
排名: #14794

安装

npx skills add https://github.com/aimonk2025/google-tag-manager-automation --skill gtm-implementation
GTM Implementation - DataLayer + GTM API
Implement complete GTM tracking by adding dataLayer events to your code AND creating GTM variables, triggers, and tags via API.
Core Mission
Transform analytics-ready DOM elements into fully tracked events with:
Code Implementation
Add dataLayer.push() calls to React/Next.js/Vue components
GTM Configuration
Create variables, triggers, and tags via GTM API
Workflow
Phase 0: Load Business Context (if available)
Check for
gtm-context.md
in the project root:
If found: read it silently and use the business context throughout this skill run
If not found: proceed normally - ask context questions as usual during the workflow
This file is created automatically by gtm-analytics-audit at the end of its first run.
Phase 1: Context & Prerequisites
Step 1.1: Load Tracking Plan
Check for gtm-tracking-plan.json (from gtm-strategy skill):
- If exists → Load events and parameters
- If missing → Ask user which events to implement OR suggest running gtm-strategy first
Check for gtm-config.json and gtm-token.json (from gtm-setup skill):
- If missing → Suggest running gtm-setup skill first
- If exists → Verify API connection
Step 1.2: Detect Framework
Check package.json:
- React version
- Next.js version and router type (App Router vs Pages Router)
- Vue version
- TypeScript vs JavaScript
This determines:
- Component file extensions (.tsx vs .jsx vs .vue)
- Import patterns
- Syntax for className vs class
- 'use client' directive for Next.js App Router
Step 1.3: Scan for Target Elements
Using Glob and Grep, find elements to instrument:
For CTA tracking:
- Search for: class=".js-cta." or id="cta_.*"
- Search for: <button, <Link components
For form tracking:
- Search for: class=".js-form." or id="form_.*"
- Search for: <form tags with onSubmit handlers
For navigation tracking:
- Search for: class=".js-nav." or id="nav_.*"
- Search for: <Link, <a tags
Match found elements against events in tracking plan.
Step 1.4: Resolve Active Workspace (Dynamic)
Before any GTM API operation, always resolve the current workspace dynamically:
// List all workspaces for this container
const
workspacesResponse
=
await
tagmanager
.
accounts
.
containers
.
workspaces
.
list
(
{
parent
:
`
accounts/
${
accountId
}
/containers/
${
containerId
}
`
}
)
const
workspaces
=
workspacesResponse
.
data
.
workspace
||
[
]
if
(
workspaces
.
length
===
0
)
{
throw
new
Error
(
'No workspaces found in this GTM container. Create one in the GTM UI first.'
)
}
// Always use the first available workspace
const
workspace
=
workspaces
[
0
]
const
workspaceId
=
workspace
.
workspaceId
console
.
log
(
`
✓ Active workspace: "
${
workspace
.
name
}
" (ID:
${
workspaceId
}
)
`
)
Why: GTM deletes a workspace after manual submission in the GTM UI and creates a new one with a new ID. The stored
workspaceId
in
gtm-config.json
becomes stale. Never assume a specific workspace ID exists.
Phase 2: DataLayer Implementation (Code Changes)
For each event in tracking plan, implement dataLayer.push() in actual code files.
Step 2.1: CTA Click Implementation
Find target
(example):
// File: app/page.tsx
<
button
className
=
"
btn primary js-track js-cta js-click js-hero
"
id
=
"
cta_hero_get_started
"
>
Get Started
</
button
>
Implement tracking
using Edit tool:
Before
:
<
button
className
=
"
btn primary js-track js-cta js-click js-hero
"
id
=
"
cta_hero_get_started
"
>
Get Started
</
button
>
After
:
<
button
className
=
"btn primary js-track js-cta js-click js-hero"
id
=
"cta_hero_get_started"
onClick
=
{
(
)
=>
{
if
(
typeof
window
!==
'undefined'
&&
window
.
dataLayer
)
{
window
.
dataLayer
.
push
(
{
event
:
'cta_click'
,
cta_location
:
'hero'
,
cta_type
:
'primary'
,
cta_text
:
'Get Started'
,
cta_destination
:
'/signup'
}
)
}
}
}
>
Get
Started
</
button
>
Framework-Specific Considerations
:
Next.js App Router
(requires 'use client'):
'use client'
import
{
useRouter
}
from
'next/navigation'
export
default
function
HeroCTA
(
)
{
const
router
=
useRouter
(
)
return
(
<
button
className
=
"btn primary js-track js-cta js-click js-hero"
id
=
"cta_hero_get_started"
onClick
=
{
(
)
=>
{
// Track event
if
(
typeof
window
!==
'undefined'
&&
window
.
dataLayer
)
{
window
.
dataLayer
.
push
(
{
event
:
'cta_click'
,
cta_location
:
'hero'
,
cta_type
:
'primary'
,
cta_text
:
'Get Started'
,
cta_destination
:
'/signup'
}
)
}
// Navigate
router
.
push
(
'/signup'
)
}
}
>
Get
Started
</
button
>
)
}
Step 2.2: Form Submit Implementation
Find target
:
<
form
className
=
"
contact-form js-track js-form js-submit js-hero
"
id
=
"
form_hero_contact
"
onSubmit
=
{
handleSubmit
}
>
Implement tracking
:
Before
:
<
form
className
=
"
contact-form js-track js-form js-submit js-hero
"
id
=
"
form_hero_contact
"
onSubmit
=
{
handleSubmit
}
>
After
:
<
form
className
=
"contact-form js-track js-form js-submit js-hero"
id
=
"form_hero_contact"
onSubmit
=
{
(
e
)
=>
{
// Track form submission
if
(
typeof
window
!==
'undefined'
&&
window
.
dataLayer
)
{
window
.
dataLayer
.
push
(
{
event
:
'form_submit'
,
form_name
:
'contact'
,
form_location
:
'hero'
,
form_type
:
'contact_request'
}
)
}
// Call original handler
handleSubmit
(
e
)
}
}
>
Step 2.3: Navigation Click Implementation
Find target
(Next.js Link):
<
Link
href
=
"
/pricing
"
>
Pricing
</
Link
>
Implement tracking
:
Before
:
<
Link
href
=
"
/pricing
"
className
=
"
nav-link js-track js-nav js-click js-header
"
id
=
"
nav_header_pricing
"
>
Pricing
</
Link
>
After
:
<
Link
href
=
"/pricing"
className
=
"nav-link js-track js-nav js-click js-header"
id
=
"nav_header_pricing"
onClick
=
{
(
)
=>
{
if
(
typeof
window
!==
'undefined'
&&
window
.
dataLayer
)
{
window
.
dataLayer
.
push
(
{
event
:
'navigation_click'
,
nav_location
:
'header'
,
nav_type
:
'menu_link'
,
nav_text
:
'Pricing'
,
nav_destination
:
'/pricing'
}
)
}
}
}
>
Pricing
</
Link
>
Step 2.4: Parameter Extraction Logic
Extract parameters from DOM elements intelligently:
cta_location
From ID attribute
// id="cta_hero_get_started" → location: "hero"
const
id
=
element
.
getAttribute
(
'id'
)
// "cta_hero_get_started"
const
location
=
id
.
split
(
'_'
)
[
1
]
// "hero"
cta_text
From button innerText
// → cta_text: "Get Started"
cta_text
:
'Get Started'
cta_destination
From href or programmatic navigation
// → cta_destination: "/signup"
// onClick={() => router.push('/pricing')} → cta_destination: "/pricing"
cta_type
From CSS classes
// className includes "btn-primary" → type: "primary"
// className includes "btn-secondary" → type: "secondary"
Phase 3: GTM Container Configuration (API Calls)
Create variables, triggers, and tags via GTM API to process the dataLayer events.
Step 3.1: Create Data Layer Variables
For each parameter in each event, create a GTM variable:
Example
cta_click event needs 4 variables
// Variable 1: CTA Location
{
name
:
"DLV - CTA Location"
,
type
:
"v"
,
parameter
:
[
{
type
:
"TEMPLATE"
,
key
:
"name"
,
value
:
"cta_location"
}
,
{
type
:
"INTEGER"
,
key
:
"dataLayerVersion"
,
value
:
"2"
}
]
}
// Variable 2: CTA Type
{
name
:
"DLV - CTA Type"
,
type
:
"v"
,
parameter
:
[
{
type
:
"TEMPLATE"
,
key
:
"name"
,
value
:
"cta_type"
}
,
{
type
:
"INTEGER"
,
key
:
"dataLayerVersion"
,
value
:
"2"
}
]
}
// Variable 3: CTA Text
{
name
:
"DLV - CTA Text"
,
type
:
"v"
,
parameter
:
[
{
type
:
"TEMPLATE"
,
key
:
"name"
,
value
:
"cta_text"
}
,
{
type
:
"INTEGER"
,
key
:
"dataLayerVersion"
,
value
:
"2"
}
]
}
// Variable 4: CTA Destination
{
name
:
"DLV - CTA Destination"
,
type
:
"v"
,
parameter
:
[
{
type
:
"TEMPLATE"
,
key
:
"name"
,
value
:
"cta_destination"
}
,
{
type
:
"INTEGER"
,
key
:
"dataLayerVersion"
,
value
:
"2"
}
]
}
Use GTM API to create:
tagmanager
.
accounts
.
containers
.
workspaces
.
variables
.
create
(
{
parent
:
`
accounts/
${
accountId
}
/containers/
${
containerId
}
/workspaces/
${
workspaceId
}
`
,
requestBody
:
variableConfig
}
)
Step 3.2: Create Custom Event Triggers
For each event, create a trigger that fires on that custom event:
Example
cta_click trigger
{
name
:
"CE - CTA Click"
,
type
:
"CUSTOM_EVENT"
,
customEventFilter
:
[
{
type
:
"EQUALS"
,
parameter
:
[
{
type
:
"TEMPLATE"
,
key
:
"arg0"
,
value
:
"{{_event}}"
}
,
{
type
:
"TEMPLATE"
,
key
:
"arg1"
,
value
:
"cta_click"
}
]
}
]
}
Use GTM API to create:
tagmanager
.
accounts
.
containers
.
workspaces
.
triggers
.
create
(
{
parent
:
`
accounts/
${
accountId
}
/containers/
${
containerId
}
/workspaces/
${
workspaceId
}
`
,
requestBody
:
triggerConfig
}
)
Step 3.3: Create GA4 Event Tags
For each event, create a GA4 event tag that fires on the trigger:
Example
CTA Click tag { name : "GA4 - CTA Click" , type : "gaawe" , // GA4 Event tag type parameter : [ { type : "TEMPLATE" , key : "eventName" , value : "cta_click" } , { type : "LIST" , key : "eventParameters" , list : [ { type : "MAP" , map : [ { type : "TEMPLATE" , key : "name" , value : "cta_location" } , { type : "TEMPLATE" , key : "value" , value : "{{DLV - CTA Location}}" } ] } , { type : "MAP" , map : [ { type : "TEMPLATE" , key : "name" , value : "cta_type" } , { type : "TEMPLATE" , key : "value" , value : "{{DLV - CTA Type}}" } ] } , { type : "MAP" , map : [ { type : "TEMPLATE" , key : "name" , value : "cta_text" } , { type : "TEMPLATE" , key : "value" , value : "{{DLV - CTA Text}}" } ] } , { type : "MAP" , map : [ { type : "TEMPLATE" , key : "name" , value : "cta_destination" } , { type : "TEMPLATE" , key : "value" , value : "{{DLV - CTA Destination}}" } ] } ] } , { type : "TAG_REFERENCE" , key : "measurementId" , value : "{{GA4 Configuration Tag}}" // Reference to GA4 config tag } ] , firingTriggerId : [ "{{CE - CTA Click trigger ID}}" ] } Use GTM API to create: tagmanager . accounts . containers . workspaces . tags . create ( { parent : accounts/ ${ accountId } /containers/ ${ containerId } /workspaces/ ${ workspaceId } , requestBody : tagConfig } ) Step 3.4: Handle Incremental Updates Check for existing variables/triggers/tags before creating: // List existing variables const existingVariables = await tagmanager . accounts . containers . workspaces . variables . list ( { parent : accounts/ ${ accountId } /containers/ ${ containerId } /workspaces/ ${ workspaceId } } ) // Check if "DLV - CTA Location" already exists const exists = existingVariables . data . variable ?. find ( v => v . name === "DLV - CTA Location" ) if ( exists ) { // Update existing variable tagmanager . accounts . containers . workspaces . variables . update ( { path : exists . path , requestBody : variableConfig } ) } else { // Create new variable tagmanager . accounts . containers . workspaces . variables . create ( { ... } ) } Phase 4: Container Version Creation After all variables/triggers/tags are created, create a new container version: const version = await tagmanager . accounts . containers . workspaces . create_version ( { path : accounts/ ${ accountId } /containers/ ${ containerId } /workspaces/ ${ workspaceId } , requestBody : { name : GTM Automation - ${ new Date ( ) . toISOString ( ) } , notes : Automated implementation via gtm-implementation skill Events implemented: - cta_click (12 elements) - form_submit (3 elements) - navigation_click (8 elements) Variables created: 12 Triggers created: 3 Tags created: 3 } } ) console . log ( ✓ Container version created: ${ version . data . containerVersionId } ) console . log ( → Preview in GTM: ${ version . data . containerVersion . tagManagerUrl } ) Phase 5: Summary Report Generate comprehensive implementation summary: === GTM Implementation Complete === --- Code Changes --- Files modified: 8 app/page.tsx: ✓ Added CTA click tracking (3 buttons) ✓ Added form submit tracking (1 form) components/Navbar.tsx: ✓ Added navigation click tracking (5 links) components/Footer.tsx: ✓ Added navigation click tracking (3 links) ✓ Added form submit tracking (1 newsletter form) ... (4 more files) --- DataLayer Events Implemented --- ✓ cta_click (12 elements tracked) ✓ form_submit (3 elements tracked) ✓ navigation_click (8 elements tracked) Total events: 23 --- GTM Container Configuration --- Account: 1234567890 Container: GTM-ABC1234 Workspace: [dynamically resolved name] (ID: [resolved ID]) Created via API: ✓ 12 Data Layer Variables ✓ 3 Custom Event Triggers ✓ 3 GA4 Event Tags Container version created: 42 Preview URL: https://tagmanager.google.com/#/versions/accounts/123/containers/456/versions/42 --- Next Steps --- 1. Test tracking in GTM Preview mode → Invoke gtm-testing skill for guided testing 2. Review container version in GTM: → Open GTM → Versions → Version 42 → Check variables, triggers, tags 3. Publish when ready: → GTM → Submit → Publish Ready to test tracking? Invoke gtm-testing skill. Important Guidelines Code Implementation Best Practices 1. Preserve Existing Functionality NEVER remove existing onClick handlers Call original handlers AFTER tracking Use wrapper functions when needed 2. Type Safety (TypeScript) // Add proper typing onClick = { ( e : React . MouseEvent < HTMLButtonElement

) => { // Track window . dataLayer ?. push ( { ... } ) // Original handler originalHandler ( e ) } } 3. Framework-Specific Patterns Next.js App Router : Add 'use client' directive to files with onClick Use useRouter from 'next/navigation' React : Use functional components with hooks Maintain existing state management Vue : Use @click syntax Maintain reactivity 4. Avoid Redundant Tracking If element already has dataLayer.push, UPDATE it (don't duplicate) Check for existing tracking code before adding new GTM API Best Practices 1. Naming Conventions Variables: "DLV - {Parameter Name}" (DLV = Data Layer Variable) Triggers: "CE - {Event Name}" (CE = Custom Event) Tags: "GA4 - {Event Name}" 2. Error Handling try { await tagmanager . accounts . containers . workspaces . variables . create ( { ... } ) } catch ( error ) { if ( error . code === 409 ) { // Variable already exists - update instead } else if ( error . code === 403 ) { // Permission denied } else { throw error } } 3. Batch Operations Create all variables first Then create triggers (which may reference variables) Finally create tags (which reference both) 4. Always Resolve Workspace Dynamically Never use a hardcoded or cached workspaceId. Before any operation, call: const workspaces = await tagmanager . accounts . containers . workspaces . list ( { parent : accounts/ ${ accountId } /containers/ ${ containerId } } ) const workspaceId = workspaces . data . workspace [ 0 ] . workspaceId GTM deletes and recreates workspaces on each publish, so stored IDs become stale. Parameter Extraction Intelligence Be smart about extracting parameters: From ID attributes : // id="cta_hero_get_started" const [ category , location , ... action ] = id . split ( '_' ) // category: "cta", location: "hero", action: ["get", "started"] From class names : // className="btn btn-primary" const isPrimary = className . includes ( 'primary' ) const type = isPrimary ? 'primary' : 'secondary' From content : // const text = element . innerText // "Get Started" From href/destination : // const destination = href // "/pricing" // onClick={() => router.push('/signup')} // Parse from handler → destination: "/signup" Scripts scripts/gtm-api-client.js Core GTM API wrapper for creating variables/triggers/tags (extracted from gtm-setup-auto.js logic) scripts/create-variables.js Variable creation logic with duplicate detection scripts/create-triggers.js Trigger creation logic for custom events scripts/create-tags.js GA4 event tag creation with parameter mapping scripts/implement-datalayer.js Analyzes tracking plan and implements dataLayer.push() in code using Edit tool References references/datalayer-patterns.md Framework-specific dataLayer implementation patterns: Next.js App Router ('use client' directive) Next.js Pages Router React (hooks, class components) Vue (composition API, options API) Vanilla JavaScript references/gtm-ui-guide.md Manual GTM UI instructions as fallback if API fails references/event-taxonomies.md Common event naming patterns (object_action vs action_object) Assets assets/templates/saas.json Pre-built GTM config for SaaS product tracking: trial_start, feature_usage, upgrade_click account_created, plan_selected assets/templates/ecommerce.json Pre-built GTM config for e-commerce tracking: product_view, add_to_cart, checkout_start purchase_complete, product_search Supporting Files template.md - Framework-specific dataLayer push code patterns and GTM API payload templates examples/sample.md - Example implementation output showing before/after code changes and console output assets/templates/lead-generation.json Pre-built GTM config for lead-gen tracking: form_start, form_submit, content_download demo_request, newsletter_signup Execution Checklist Tracking plan loaded or events specified GTM API credentials validated Framework detected Target elements identified DataLayer events implemented in code Variables created via GTM API Triggers created via GTM API Tags created via GTM API Container version created Implementation summary generated Testing instructions provided Common Questions Q: What if I don't have a tracking plan? A: Run gtm-strategy skill first to create one, OR specify events manually and we'll implement them. Q: Can I implement tracking without using the GTM API? A: Yes. We'll implement dataLayer events in code and provide manual GTM UI instructions. Q: Will this overwrite existing GTM configuration? A: No. We check for existing variables/triggers/tags and update them. New configs are added, not replaced. Q: Can I implement tracking for only specific events? A: Yes. Specify which events to implement (e.g., "only implement cta_click tracking"). Q: What if my framework isn't supported? A: The dataLayer.push pattern works in any JavaScript environment. We'll provide vanilla JS implementation. Q: My workspace ID changed after publishing in GTM. Will the skill break? A: No. The skill always lists available workspaces via the API and uses the first one found, regardless of its ID. You never need to update gtm-config.json after publishing.

返回排行榜