Expert guidance for implementing the GTM data layer including structure, events, e-commerce tracking, SPA patterns, and best practices. Use when designing data layer architecture, implementing tracking events, setting up e-commerce data, debugging data layer issues, migrating to GA4 data layer patterns, working with dataLayer.push syntax, implementing data layers in React, Vue, Angular, or Next.js applications, or working with .js, .jsx, or .tsx files containing ecommerce objects.
/plugin marketplace add henkisdabro/wookstar-claude-code-plugins/plugin install gtm-suite@wookstar-claude-code-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/datalayer-best-practices.mdreferences/datalayer-fundamentals.mdreferences/ecommerce-datalayer.mdreferences/spa-datalayer.mdThis skill provides comprehensive expertise for implementing and managing the Google Tag Manager data layer, the foundational data structure that powers GTM implementations. Use this skill for data layer architecture, event tracking patterns, e-commerce implementation, single-page application (SPA) strategies, and data layer best practices.
Invoke this skill when:
The data layer is a JavaScript object that temporarily stores data before passing it to GTM. It acts as a structured data repository that separates your website's data from your tag management implementation.
Basic Structure:
window.dataLayer = window.dataLayer || [];
Always initialize the data layer BEFORE the GTM container snippet:
<!-- Data Layer -->
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'page_type': 'homepage',
'user_logged_in': true,
'user_id': 'user123'
});
</script>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){...GTM snippet...})</script>
Use dataLayer.push() to add data:
// Basic push
dataLayer.push({
'event': 'custom_event',
'event_category': 'engagement',
'event_label': 'button_click'
});
// E-commerce push
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T12345',
'value': 99.99,
'currency': 'USD',
'items': [
{
'item_id': 'SKU123',
'item_name': 'Product Name',
'price': 99.99,
'quantity': 1
}
]
}
});
dataLayer.push({
'page_type': 'product',
'page_category': 'electronics',
'page_language': 'en',
'page_region': 'US'
});
dataLayer.push({
'user_id': 'hashed_user_id', // Never use PII!
'user_logged_in': true,
'user_type': 'premium',
'user_ltv_segment': 'high'
});
// Form submission
dataLayer.push({
'event': 'form_submission',
'form_id': 'contact_form',
'form_name': 'Contact Us'
});
// Video interaction
dataLayer.push({
'event': 'video_progress',
'video_title': 'Product Demo',
'video_percent': 50
});
// Search
dataLayer.push({
'event': 'search',
'search_term': 'running shoes',
'search_results': 42
});
dataLayer.push({
'event': 'error',
'error_type': '404',
'error_message': 'Page not found',
'error_url': window.location.href
});
View Item List:
dataLayer.push({
'event': 'view_item_list',
'ecommerce': {
'items': [
{
'item_id': 'SKU123',
'item_name': 'Product Name',
'item_brand': 'Brand',
'item_category': 'Category',
'price': 29.99,
'quantity': 1
}
]
}
});
Add to Cart:
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'currency': 'USD',
'value': 29.99,
'items': [
{
'item_id': 'SKU123',
'item_name': 'Product Name',
'price': 29.99,
'quantity': 1
}
]
}
});
Purchase:
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T12345',
'value': 99.99,
'tax': 8.00,
'shipping': 5.00,
'currency': 'USD',
'items': [
{
'item_id': 'SKU123',
'item_name': 'Product Name',
'item_brand': 'Brand',
'item_category': 'Electronics',
'price': 29.99,
'quantity': 3
}
]
}
});
view_item_list with all visible productsselect_item when user clicks productview_item for the viewed productadd_to_cart when item addedbegin_checkout, add_shipping_info, add_payment_infopurchase on order confirmation page// On route change in React/Vue/Angular
function trackVirtualPageview(pageData) {
// Clear previous page data
dataLayer.push({
page_title: undefined,
page_type: undefined,
page_category: undefined
});
// Push new page data
dataLayer.push({
'event': 'virtual_pageview',
'page_title': pageData.title,
'page_location': pageData.url,
'page_type': pageData.type
});
}
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function usePageTracking() {
const location = useLocation();
useEffect(() => {
dataLayer.push({
'event': 'virtual_pageview',
'page_path': location.pathname,
'page_title': document.title
});
}, [location]);
}
// pages/_app.js
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export default function App({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
const handleRouteChange = (url) => {
dataLayer.push({
'event': 'virtual_pageview',
'page_path': url,
'page_title': document.title
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
return <Component {...pageProps} />;
}
✅ Good:
dataLayer.push({
'event': 'form_submit',
'form_id': 'contact_form',
'user_logged_in': true
});
❌ Bad:
dataLayer.push({
'event': 'formSubmit', // Inconsistent casing
'FormID': 'contact_form', // PascalCase
'logged in': true // Spaces
});
Conventions:
Flat structure for simple data:
dataLayer.push({
'event': 'custom_event',
'event_category': 'engagement',
'event_action': 'click',
'event_label': 'cta_button'
});
Nested structure for complex data:
dataLayer.push({
'event': 'product_view',
'product': {
'id': 'SKU123',
'name': 'Product Name',
'price': 29.99,
'category': 'Electronics'
}
});
❌ NEVER include PII in data layer:
// BAD - Do not do this!
dataLayer.push({
'user_email': 'user@example.com',
'user_name': 'John Doe',
'credit_card': '1234-5678-9012-3456'
});
✅ Use hashed or anonymized IDs:
// GOOD
dataLayer.push({
'user_id': 'hashed_user_id_123abc',
'user_segment': 'premium'
});
// View entire data layer
console.log(window.dataLayer);
// View specific push
dataLayer.push({
'event': 'test_event',
'test_data': 'value'
});
console.log(dataLayer[dataLayer.length - 1]);
// Watch for pushes
const originalPush = dataLayer.push;
dataLayer.push = function() {
console.log('DataLayer push:', arguments[0]);
return originalPush.apply(dataLayer, arguments);
};
Undefined Variable:
Data Not Persisting:
Timing Issues:
This skill includes comprehensive reference documentation:
Search reference files for specific patterns:
grep -r "purchase" references/
grep -r "React" references/
grep -r "consent" references/
Initialize: window.dataLayer = window.dataLayer || [];
Push Event: dataLayer.push({'event': 'event_name', 'key': 'value'});
Clear Variable: dataLayer.push({'variable_name': undefined});
E-commerce: Always use GA4 schema with ecommerce object
SPAs: Clear previous data and push virtual pageviews
Security: Never push PII - use hashed IDs only
Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.