Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:32:40 +08:00
commit 0ea8352871
72 changed files with 30043 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
---
name: ga4-custom-events
description: Expert guidance for creating business-specific custom events in GA4 beyond recommended events. Use when implementing custom tracking for unique business needs, creating industry-specific events (SaaS, education, media), defining custom event parameters, or tracking actions not covered by recommended events. Covers event naming conventions (snake_case, max 40 chars), parameter design, and implementation in gtag.js, GTM, and Measurement Protocol.
---
# GA4 Custom Events
## Overview
Create business-specific custom events in Google Analytics 4 for tracking user interactions beyond Google's recommended events. Custom events enable measurement of unique business goals, industry-specific actions, and contextual behaviors that directly impact business outcomes. Master event naming conventions, parameter design strategies, and implementation across gtag.js, Google Tag Manager, and Measurement Protocol.
## When to Use This Skill
Invoke this skill when:
- Creating custom event tracking for unique business actions
- Designing event structure for SaaS, education, media, or specialized industries
- Defining custom parameters and establishing naming conventions
- Implementing custom events in gtag.js, GTM, or server-side
- Registering custom parameters as custom dimensions
- Building comprehensive event tracking strategy for business goals
- Troubleshooting why custom events aren't appearing in GA4
## Core Capabilities
### Event Naming Conventions
Follow these principles for custom event names:
**Format & Constraints:**
- Use snake_case (lowercase with underscores): `video_tutorial_watched`, `demo_requested`
- Maximum 40 characters total length
- Action-oriented: start with verb when possible
- Descriptive and business-specific: avoid generic names like "event1", "click", "data"
- Consistent across implementation: same event name everywhere
**Naming Framework:**
```
[Action]_[Object]_[Context]
```
Examples:
- `product_comparison_viewed` (user compared products)
- `pricing_calculator_used` (engaged with pricing tool)
- `whitepaper_downloaded` (downloaded resource)
- `trial_signup_completed` (completed trial signup)
- `support_ticket_created` (created support issue)
**Anti-patterns (avoid):**
- Generic: `click`, `event`, `action`, `interaction`
- Numbered: `event1`, `event2`, `custom_event_123`
- Vague: `data_sent`, `tracking`, `user_action`
- Inconsistent: mixing `video_watched`, `videoWatched`, `VideoWatched`
### Event Parameter Design
**Parameter Strategy:**
Identify what context makes the event meaningful:
1. **Identify the action:** What user behavior are you measuring?
2. **Determine context:** What information would help analyze this action?
3. **Define parameters:** Which data points provide that context?
4. **Establish constraints:** Each parameter <100 characters
**Good Parameter Examples:**
For `course_enrollment`:
```
course_id: "COURSE_101"
course_name: "Advanced GA4"
instructor: "John Doe"
price: 99.99
currency: "USD"
level: "advanced"
```
For `support_ticket_created`:
```
ticket_type: "bug_report"
product: "mobile_app"
severity: "high"
resolution_time_expected: 24
department: "engineering"
```
**Parameter Limits:**
- Maximum 25 parameters per event
- Parameter names: 40 characters maximum
- Parameter values: 100 characters maximum (exceptions: page_location 1000)
- Use string, integer, or float types
### Industry-Specific Patterns
**SaaS Events:**
- `trial_started`, `trial_ended`, `upgrade_initiated`, `plan_downgraded`
- Include: plan_type, feature_count, estimated_value
**Education Events:**
- `lesson_completed`, `quiz_submitted`, `certificate_earned`
- Include: subject, difficulty_level, score_percentage
**E-commerce Events:**
- Beyond `purchase`: `product_compared`, `review_submitted`, `wishlist_added`
- Include: product_category, competitor_product, star_rating
**Media Events:**
- `article_shared`, `video_watched`, `podcast_episode_completed`
- Include: content_type, duration, engagement_percentage
### Implementation Across Platforms
**gtag.js Implementation:**
```javascript
gtag('event', 'demo_requested', {
'demo_type': 'product_walkthrough',
'industry': 'technology',
'company_size': 'enterprise',
'email_domain': 'company.com'
});
```
**GTM Data Layer Implementation:**
```javascript
dataLayer.push({
'event': 'demo_requested',
'demo_type': 'product_walkthrough',
'industry': 'technology'
});
```
**Measurement Protocol (Server-Side):**
```python
event_data = {
"client_id": "123.456",
"events": [{
"name": "demo_requested",
"params": {
"demo_type": "product_walkthrough",
"industry": "technology"
}
}]
}
```
### Registration as Custom Dimensions
Custom parameters won't appear in GA4 reports until registered:
1. Send parameter in event (any platform)
2. Admin → Data Display → Custom Definitions → Create Custom Dimension
3. Configure: Dimension Name, Scope (Event/User/Item), Event Parameter (exact name)
4. Save and wait 24-48 hours for data to populate
## References
- **references/naming-conventions-guide.md** - Complete naming conventions, patterns, and examples
- **references/event-design-framework.md** - Event architecture, parameter scoping, and design workflows
- **references/industry-patterns.md** - Industry-specific events for SaaS, education, media, ecommerce
- **references/parameter-strategy.md** - Parameter design, validation, and best practices
## Integration with Other Skills
- **ga4-events-fundamentals** - Understanding GA4 event architecture and scopes (prerequisite)
- **ga4-recommended-events** - Recommended events that complement custom events
- **ga4-gtag-implementation** - Implementing custom events via gtag.js
- **ga4-gtm-integration** - Implementing custom events via Google Tag Manager
- **ga4-measurement-protocol** - Server-side custom event implementation
- **ga4-custom-dimensions** - Registering custom parameters as reportable dimensions
- **ga4-debugview** - Testing and validating custom events before production

View File

@@ -0,0 +1,600 @@
/**
* GA4 Custom Event Templates
* Ready-to-use implementations for common business scenarios
* Modify event names and parameters to match your business logic
*/
// ============================================================================
// SAAS EVENT TEMPLATES
// ============================================================================
/**
* SaaS Free Trial Signup
* Track when user initiates a free trial
*/
function trackTrialSignup(planType, source) {
gtag('event', 'trial_signup', {
'trial_plan': planType, // 'professional', 'enterprise'
'trial_days': 30,
'source': source, // 'landing_page', 'email', 'ad'
'campaign': getUTMParameter('utm_campaign')
});
}
/**
* SaaS Trial to Paid Conversion
* Track when trial user converts to paid subscription
*/
function trackTrialConversion(trialPlan, paidPlan, conversionValue) {
gtag('event', 'trial_conversion', {
'trial_plan': trialPlan,
'paid_plan': paidPlan,
'conversion_value': conversionValue,
'trial_duration_days': calculateTrialDays(),
'most_used_feature': getMostUsedFeature()
});
// Also set as user property
gtag('set', {
'subscription_plan': paidPlan,
'subscription_status': 'active'
});
}
/**
* SaaS Feature Adoption
* Track when user enables/activates a premium feature
*/
function trackFeatureAdoption(featureName, featureCategory) {
gtag('event', 'feature_enable', {
'feature_name': featureName, // 'team_collaboration', 'api_access'
'feature_category': featureCategory, // 'premium', 'beta', 'advanced'
'user_plan': getCurrentUserPlan(),
'days_since_signup': calculateDaysSinceSignup(),
'discovery_method': 'settings' // 'settings', 'email', 'notification'
});
// Track as user property if persistent feature
gtag('set', {
'features_enabled': incrementFeatureCount()
});
}
/**
* SaaS Subscription Upgrade
* Track plan upgrades
*/
function trackSubscriptionUpgrade(fromPlan, toPlan) {
const priceIncrease = calculatePriceIncrease(fromPlan, toPlan);
gtag('event', 'subscription_upgrade', {
'from_plan': fromPlan,
'to_plan': toPlan,
'upgrade_value': priceIncrease,
'currency': 'USD',
'customer_tenure_months': getCustomerTenure()
});
// Update user property
gtag('set', {
'subscription_plan': toPlan,
'monthly_recurring_revenue': getPlanPrice(toPlan)
});
}
/**
* SaaS Subscription Cancellation
* Track when user cancels subscription
*/
function trackSubscriptionCancel(plan, reason) {
gtag('event', 'subscription_cancel', {
'plan': plan,
'reason': reason, // 'too_expensive', 'not_using', 'switching'
'tenure_months': getCustomerTenure(),
'mrr': getMRR(),
'ltv': getCustomerLTV()
});
// Update user property
gtag('set', {
'subscription_status': 'cancelled'
});
}
// ============================================================================
// E-COMMERCE EVENT TEMPLATES
// ============================================================================
/**
* Product View
* Track when user views product page
*/
function trackProductView(productId, productName, price, category) {
gtag('event', 'view_item', {
'items': [
{
'item_id': productId,
'item_name': productName,
'price': price,
'item_category': category,
'item_variant': getProductVariant(),
'item_brand': getProductBrand()
}
],
'value': price,
'currency': 'USD',
'source_page': getCurrentPage()
});
}
/**
* Add to Cart
* Track when user adds product to shopping cart
*/
function trackAddToCart(productId, productName, quantity, price) {
gtag('event', 'add_to_cart', {
'items': [
{
'item_id': productId,
'item_name': productName,
'quantity': quantity,
'price': price,
'item_category': getProductCategory(productId)
}
],
'value': price * quantity,
'currency': 'USD'
});
}
/**
* Begin Checkout
* Track when user starts checkout process
*/
function trackBeginCheckout(items, cartValue) {
gtag('event', 'begin_checkout', {
'items': items.map(item => ({
'item_id': item.id,
'item_name': item.name,
'quantity': item.quantity,
'price': item.price
})),
'value': cartValue,
'currency': 'USD',
'coupon_applied': hasCoupon()
});
}
/**
* Purchase Event
* Track completed purchase
*/
function trackPurchase(transactionId, items, total, tax, shipping, coupon) {
gtag('event', 'purchase', {
'transaction_id': transactionId,
'affiliation': getStoreName(),
'value': total,
'currency': 'USD',
'tax': tax,
'shipping': shipping,
'coupon': coupon,
'items': items.map(item => ({
'item_id': item.id,
'item_name': item.name,
'item_category': item.category,
'item_brand': item.brand,
'price': item.price,
'quantity': item.quantity
}))
});
// Update user properties
gtag('set', {
'purchase_count': incrementPurchaseCount(),
'customer_lifetime_value': updateLTV(),
'last_purchase_date': getCurrentDate()
});
}
/**
* Product Review Submission
* Track when user submits product review
*/
function trackProductReview(productId, rating, reviewLength) {
gtag('event', 'product_review_submit', {
'product_id': productId,
'rating': rating, // 1-5 stars
'review_length': reviewLength, // character count
'verified_purchase': isVerifiedPurchase()
});
}
// ============================================================================
// EDUCATION/LEARNING EVENT TEMPLATES
// ============================================================================
/**
* Course Enrollment
* Track when user enrolls in a course
*/
function trackCourseEnroll(courseId, courseName, price) {
gtag('event', 'course_enroll', {
'course_id': courseId,
'course_name': courseName,
'course_level': getCourseLevel(courseId),
'price': price,
'currency': 'USD',
'enrollment_method': 'direct' // 'direct', 'subscription', 'free'
});
// Update user property
gtag('set', {
'courses_enrolled': incrementEnrolledCount(),
'total_spent_on_courses': updateCoursesSpent(price)
});
}
/**
* Lesson Completion
* Track when user finishes a lesson
*/
function trackLessonComplete(courseId, lessonId, timeSpentMinutes, score) {
gtag('event', 'lesson_complete', {
'course_id': courseId,
'lesson_id': lessonId,
'lesson_title': getLessonTitle(lessonId),
'time_spent_minutes': timeSpentMinutes,
'completion_score': score, // percentage or points
'is_required': isRequiredLesson(lessonId)
});
}
/**
* Quiz Submission
* Track when user submits quiz
*/
function trackQuizSubmit(courseId, quizId, correctAnswers, totalQuestions, score) {
gtag('event', 'quiz_submit', {
'course_id': courseId,
'quiz_id': quizId,
'questions_correct': correctAnswers,
'questions_total': totalQuestions,
'score_percent': Math.round((correctAnswers / totalQuestions) * 100),
'attempts': getQuizAttemptCount(),
'passed': score >= getPassingScore()
});
}
/**
* Certificate Earned
* Track when user earns course certificate
*/
function trackCertificateEarn(courseId, certificateType, finalScore) {
gtag('event', 'certificate_earn', {
'course_id': courseId,
'certificate_type': certificateType, // 'completion', 'achievement'
'final_score': finalScore,
'days_to_completion': calculateDaysToCompletion(),
'shared_socially': false // will update if shared later
});
// Update user property
gtag('set', {
'certificates_earned': incrementCertificateCount(),
'total_learning_hours': updateTotalHours()
});
}
// ============================================================================
// CONTENT/MEDIA EVENT TEMPLATES
// ============================================================================
/**
* Article/Blog Post View
* Track when user reads article
*/
function trackArticleView(articleId, articleTitle, category, authorId) {
gtag('event', 'article_view', {
'article_id': articleId,
'article_title': articleTitle,
'article_category': category,
'author_id': authorId,
'article_word_count': getArticleWordCount(),
'publication_date': getArticleDate()
});
}
/**
* Article Read Complete
* Track when user reads entire article
*/
function trackArticleReadComplete(articleId, timeOnPageSeconds) {
gtag('event', 'article_read_complete', {
'article_id': articleId,
'time_on_page_seconds': timeOnPageSeconds,
'estimated_reading_time_seconds': getEstimatedReadingTime(articleId),
'reading_efficiency': calculateReadingEfficiency(timeOnPageSeconds)
});
}
/**
* Video Watch Start
* Track when user starts watching video
*/
function trackVideoStart(videoId, videoTitle, duration, category) {
gtag('event', 'video_start', {
'video_id': videoId,
'video_title': videoTitle,
'video_duration_seconds': duration,
'video_category': category
});
}
/**
* Video Complete
* Track when user completes video
*/
function trackVideoComplete(videoId, watchTimeSeconds, duration) {
const completionPercent = Math.round((watchTimeSeconds / duration) * 100);
gtag('event', 'video_complete', {
'video_id': videoId,
'watch_time_seconds': watchTimeSeconds,
'video_duration_seconds': duration,
'completion_percent': completionPercent,
'quality_watched': getPlaybackQuality(),
'watch_count': incrementVideoWatchCount()
});
}
/**
* Content Share
* Track when user shares content
*/
function trackContentShare(contentId, contentType, method) {
gtag('event', 'content_share', {
'content_id': contentId,
'content_type': contentType, // 'article', 'video', 'resource'
'share_method': method, // 'email', 'twitter', 'facebook', 'linkedin'
'timestamp': getCurrentTime()
});
}
/**
* Newsletter Signup
* Track when user subscribes to newsletter
*/
function trackNewsletterSignup(category, frequency) {
gtag('event', 'newsletter_subscribe', {
'newsletter_category': category, // 'weekly_digest', 'industry_news'
'frequency': frequency, // 'daily', 'weekly', 'monthly'
'email_validated': true,
'signup_source': getSignupSource() // 'exit_intent', 'footer', 'sidebar'
});
// Update user property
gtag('set', {
'newsletter_subscribed': true,
'newsletter_categories': category
});
}
// ============================================================================
// SUPPORT/HELP EVENT TEMPLATES
// ============================================================================
/**
* Support Ticket Created
* Track when user opens support ticket
*/
function trackSupportTicket(category, severity, userPlan) {
gtag('event', 'support_ticket_create', {
'ticket_category': category, // 'billing', 'technical', 'feature_request'
'severity': severity, // 'low', 'medium', 'high', 'critical'
'user_plan': userPlan,
'response_time_expectation': 'within_24_hours'
});
}
/**
* Help Article View
* Track when user searches for help
*/
function trackHelpSearch(searchTerm, resultsCount, articleClicked) {
gtag('event', 'help_search', {
'search_term': searchTerm,
'search_results_count': resultsCount,
'article_clicked': articleClicked,
'search_category': 'knowledge_base' // 'knowledge_base', 'faq', 'documentation'
});
}
/**
* Feature Request Submitted
* Track when user requests new feature
*/
function trackFeatureRequest(featureName, useCase) {
gtag('event', 'feature_request_submit', {
'requested_feature': featureName,
'use_case': useCase,
'upvote_count': 1
});
}
// ============================================================================
// SIGNUP/AUTHENTICATION EVENT TEMPLATES
// ============================================================================
/**
* User Signup
* Track account creation
*/
function trackUserSignup(signupMethod, source) {
gtag('event', 'user_signup', {
'signup_method': signupMethod, // 'email', 'google', 'facebook', 'github'
'signup_source': source, // 'landing_page', 'app', 'email'
'email_verified': false // Will update when verified
});
// Set user properties
gtag('set', {
'signup_date': getCurrentDate(),
'signup_method': signupMethod,
'email_verified': false
});
}
/**
* Email Verification
* Track when user verifies email
*/
function trackEmailVerified() {
gtag('event', 'email_verified', {
'verification_method': 'email_link', // 'email_link', 'sms_code', 'oauth'
'time_to_verify_minutes': calculateMinutesSinceSignup()
});
// Update user property
gtag('set', {
'email_verified': true
});
}
/**
* User Login
* Track when user logs in
*/
function trackUserLogin(loginMethod, isFirstLogin) {
gtag('event', 'user_login', {
'login_method': loginMethod, // 'password', 'sso', 'social'
'is_first_login': isFirstLogin,
'platform': getPlatform() // 'web', 'mobile', 'desktop'
});
}
// ============================================================================
// ACCOUNT MANAGEMENT EVENT TEMPLATES
// ============================================================================
/**
* Profile Completion
* Track user profile progress
*/
function trackProfileComplete(completionPercent, fieldsUpdated) {
gtag('event', 'profile_complete', {
'completion_percent': completionPercent,
'fields_updated': fieldsUpdated,
'has_profile_photo': hasProfilePhoto(),
'has_bio': hasBio()
});
if (completionPercent === 100) {
gtag('set', {
'profile_complete': true
});
}
}
/**
* Settings Changed
* Track when user changes account settings
*/
function trackSettingsChange(settingType, newValue) {
gtag('event', 'settings_change', {
'setting_type': settingType, // 'language', 'timezone', 'notifications'
'new_value': newValue,
'previous_value': getPreviousValue(settingType)
});
}
/**
* Payment Method Added
* Track when user adds payment method
*/
function trackPaymentMethodAdd(paymentType) {
gtag('event', 'payment_method_add', {
'payment_type': paymentType, // 'credit_card', 'paypal', 'bank_transfer'
'payment_methods_count': incrementPaymentMethodCount(),
'is_default': false
});
}
// ============================================================================
// HELPER FUNCTIONS (Replace with your actual implementation)
// ============================================================================
function getUTMParameter(param) {
const url = new URLSearchParams(window.location.search);
return url.get(param) || '';
}
function getCurrentUserPlan() {
// Get from your user data/API
return localStorage.getItem('userPlan') || 'free';
}
function calculateTrialDays() {
// Calculate days from trial start to now
const trialStart = new Date(localStorage.getItem('trialStartDate'));
return Math.floor((new Date() - trialStart) / (1000 * 60 * 60 * 24));
}
function getMostUsedFeature() {
// Get from your analytics/tracking
return 'reporting';
}
function getCustomerTenure() {
// Get from your database
return parseInt(localStorage.getItem('customerTenureMonths')) || 0;
}
function calculateDaysSinceSignup() {
const signupDate = new Date(localStorage.getItem('signupDate'));
return Math.floor((new Date() - signupDate) / (1000 * 60 * 60 * 24));
}
function getCurrentPage() {
return window.location.pathname;
}
function getProductCategory(productId) {
// Get from your product database
return 'electronics';
}
function getCurrentDate() {
return new Date().toISOString().split('T')[0];
}
function getCurrentTime() {
return new Date().toISOString();
}
function getPlatform() {
return /Mobile|Android|iPhone/.test(navigator.userAgent) ? 'mobile' : 'web';
}
// Export for use in other files
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
trackTrialSignup,
trackTrialConversion,
trackFeatureAdoption,
trackSubscriptionUpgrade,
trackSubscriptionCancel,
trackProductView,
trackAddToCart,
trackBeginCheckout,
trackPurchase,
trackCourseEnroll,
trackLessonComplete,
trackVideoStart,
trackVideoComplete,
trackNewsletterSignup,
trackUserSignup,
trackUserLogin,
trackProfileComplete,
trackSettingsChange
};
}

View File

@@ -0,0 +1,401 @@
# GA4 Event Design Framework
## Comprehensive Guide to Custom Event Architecture
### Event Design Philosophy
Custom events should answer business questions:
- **What action** is the user taking?
- **Why does it matter** to the business?
- **What context** makes it meaningful?
- **How will it be analyzed**?
Effective events provide actionable insights about user behavior, feature adoption, and business metrics.
---
## Event Discovery Process
### Step 1: Identify Business Goals
List objectives that matter to the business:
- User acquisition and activation
- Feature adoption and engagement
- Conversion and monetization
- Retention and churn prevention
- Support and satisfaction
### Step 2: Map User Actions to Goals
Connect specific user behaviors to each business goal:
| Business Goal | User Action | Event Needed |
|---------------|------------|--------------|
| Feature adoption | User explores premium feature | `feature_explore` |
| Conversion | User upgrades from trial | `upgrade_start` |
| Retention | User invites teammates | `user_invite_send` |
| Support | User opens help article | `help_article_view` |
| Churn prevention | User pauses subscription | `subscription_pause` |
### Step 3: Determine Required Context
For each action, identify what context makes analysis meaningful:
**Example: Feature Adoption**
```
Event: feature_explore
Context needed:
- feature_name: Which feature?
- feature_category: Premium, beta, experimental?
- source: Where did they find it? (help, notification, suggestion)
- result: Did they stay on feature?
```
### Step 4: Design Event Structure
Finalize event name and parameters:
```javascript
gtag('event', 'feature_explore', {
'feature_name': 'advanced_reporting',
'feature_category': 'premium',
'discovery_source': 'help_article',
'user_tier': 'free'
});
```
---
## Parameter Scoping Strategy
GA4 uses three scopes. Choose correctly:
### Event-Scoped Parameters (Single Event)
**Use When:** Data is specific to this event occurrence
Examples:
- `button_clicked` event: which button_name?
- `video_watched` event: which video_title?
- `form_submit` event: which form_name, form_destination?
```javascript
gtag('event', 'video_watched', {
'video_title': 'GA4 Fundamentals', // Event-scoped
'video_duration': 600, // Event-scoped
'completion_percent': 100 // Event-scoped
});
```
**Registration:** Event-Scoped Custom Dimension in Admin
### User-Scoped Parameters (User Properties)
**Use When:** Data applies to ALL events from user
Examples:
- subscription tier (free, pro, enterprise)
- company size (startup, mid-market, enterprise)
- customer segment (high-value, at-risk, churned)
- geographic region (EMEA, APAC, Americas)
```javascript
gtag('set', {
'subscription_tier': 'premium', // User-scoped
'customer_segment': 'high_value', // User-scoped
'onboarding_complete': true // User-scoped
});
```
**When to Use:** Set once, applies to all subsequent events
**Registration:** User-Scoped Custom Dimension in Admin
### Item-Scoped Parameters (Ecommerce Items)
**Use When:** Data applies to individual products in transaction
Only used with items array in ecommerce events.
```javascript
gtag('event', 'purchase', {
'items': [
{
'item_id': 'SKU_001',
'item_name': 'Premium Widget',
'item_color': 'blue', // Item-scoped
'supplier': 'Vendor A', // Item-scoped
'quantity': 2,
'price': 49.99
}
]
});
```
---
## Parameter Design Best Practices
### Rule 1: Keep Parameters Meaningful
```
✅ Good:
gtag('event', 'trial_start', {
'trial_days': 30,
'trial_plan': 'professional',
'source_utm': 'google_ads'
});
❌ Bad:
gtag('event', 'trial_start', {
'random_id': '12345',
'session_date': '2024-11-10',
'browser': 'Chrome' // These are auto-collected
});
```
### Rule 2: Use Consistent Values
```
✅ Good:
Always use 'free', 'pro', 'enterprise'
(case consistent, lowercase)
❌ Bad:
Mix of 'free', 'Free', 'FREE', 'standard'
(inconsistent capitalization)
```
### Rule 3: Avoid High-Cardinality Parameters
```
✅ Good:
'plan_type': 'pro' (5 possible values)
❌ Bad:
'user_email': 'user@example.com' (millions of values)
'session_id': '12345abc...' (unique per session)
```
### Rule 4: Store IDs as Parameters, Not in Event Name
```
✅ Good:
gtag('event', 'video_watched', {
'video_id': 'VID_12345',
'video_title': 'Learning GA4'
});
❌ Bad:
gtag('event', 'video_watched_VID_12345')
gtag('event', 'video_watched_learning_ga4')
```
### Rule 5: Use Numeric Types for Metrics
```
✅ Good:
'price': 99.99 (number)
'quantity': 5 (integer)
'duration_seconds': 1200 (integer)
❌ Bad:
'price': '$99.99' (string with currency)
'quantity': 'five' (string)
'duration': '20 minutes' (string)
```
---
## Event Documentation Template
Document every custom event:
```markdown
### Event: demo_request
**Description:** User requests product demonstration
**When Fired:**
- User clicks "Request Demo" button on pricing page
- User submits demo request form
**Parameters:**
| Parameter | Type | Values | Purpose |
|-----------|------|--------|---------|
| demo_type | string | walkthrough, personalized | Type of demo requested |
| industry | string | tech, finance, healthcare | User's industry |
| company_size | string | startup, mid-market, enterprise | Company size |
| source | string | pricing_page, landing_page, email | Where request originated |
**Implementation:**
- gtag.js: Yes
- GTM: Yes
- Measurement Protocol: Yes
**Custom Dimension:** Yes (demo_type, industry, company_size as event-scoped)
**Frequency:** ~50-100 per month (estimated)
**Related Events:** demo_attend, demo_skip, upgrade_after_demo
```
---
## Parameter Validation
### Type Validation
Ensure parameters use correct types:
```javascript
// ✅ Correct types
gtag('event', 'purchase', {
'value': 99.99, // Number
'currency': 'USD', // String
'quantity': 3, // Integer
'is_gift': true, // Boolean
'items': [...] // Array
});
// ❌ Wrong types
gtag('event', 'purchase', {
'value': '99.99', // String instead of number
'quantity': '3', // String instead of integer
'is_gift': 'true' // String instead of boolean
});
```
### Value Length Validation
```javascript
// ✅ Good (under limits)
gtag('event', 'form_submit', {
'form_name': 'Contact Form', // OK (14 chars)
'company_name': 'Acme Corp', // OK (9 chars)
'email_body': 'Long message...' // OK (100 chars max)
});
// ❌ Bad (too long)
gtag('event', 'form_submit', {
'form_description': '...[200 chars]...' // Exceeds 100 char limit
});
```
---
## Complex Event Examples
### Example 1: Video Engagement Tracking
```javascript
gtag('event', 'video_engagement', {
'video_id': 'VID_2024_001',
'video_title': 'GA4 Advanced Features',
'video_duration': 1200, // seconds
'time_watched': 845, // seconds
'completion_percent': 70,
'quality_selected': 'hd',
'interaction_type': 'pause', // pause, seek, quality_change, fullscreen
'engagement_score': 8 // 1-10 scale
});
```
### Example 2: SaaS Onboarding Tracking
```javascript
gtag('event', 'onboarding_step_complete', {
'step_number': 3,
'step_name': 'team_invite',
'total_steps': 5,
'time_on_step': 245, // seconds
'users_invited': 2,
'skip_attempted': false
});
// User-level context
gtag('set', {
'onboarding_progress': 'step_3_of_5',
'onboarding_started_date': '2024-11-10'
});
```
### Example 3: E-commerce Product Discovery
```javascript
gtag('event', 'product_discovery_complete', {
'discovery_method': 'search', // search, recommendation, browse, email
'search_term': 'running shoes',
'filters_applied': 3,
'results_viewed': 24,
'products_liked': 5,
'add_to_cart_from_discovery': 2
});
```
---
## Event Consolidation vs Proliferation
### When to Consolidate Events
**Use one event with parameters instead of multiple events:**
```
❌ Too many events:
- button_click_signin
- button_click_signup
- button_click_demo
- button_click_contact
✅ One consolidated event:
- button_click (with parameter: button_name)
```
### When to Separate Events
**Create separate events for distinct user journeys:**
```
✅ Separate events (correct):
- feature_explore (user discovered feature)
- feature_adopt (user started using feature)
- feature_abandon (user stopped using feature)
❌ One event (not enough context):
- feature_interaction (ambiguous: explore or use?)
```
### Decision Rule
- **Same event type + just different context**: Use parameters
- **Different action sequences or business flows**: Use separate events
- **Different analysis needs**: Consider separate events
---
## Event Limits and Quotas
### Standard GA4 Property Limits
- Maximum event names: 500 event types per property
- Maximum 25 parameters per event
- Parameter name: 40 characters max
- Parameter value: 100 characters max (with exceptions)
### Custom Dimension Limits
- Event-scoped: 50 per property
- User-scoped: 25 per property
- Item-scoped: 10 per property
### Planning for Scale
When designing events, consider:
1. How many unique custom events will be needed?
2. What parameters will each event require?
3. How many custom dimensions are needed?
4. What's the growth trajectory?
If approaching limits, prioritize:
- Events that directly impact business decisions
- Parameters that enable key analyses
- Dimensions needed for audience segmentation

View File

@@ -0,0 +1,676 @@
# GA4 Custom Events: Industry-Specific Patterns
## Complete Industry Event Catalogs
### SaaS (Software as a Service)
#### Core SaaS Events
**Free Trial & Conversion:**
```javascript
// User initiates free trial
gtag('event', 'trial_start', {
'trial_plan': 'professional',
'trial_days': 30,
'utm_source': 'landing_page',
'utm_medium': 'organic'
});
// User converts trial to paid
gtag('event', 'trial_conversion', {
'trial_plan': 'professional',
'paid_plan': 'professional_annual',
'trial_duration_days': 28,
'feature_used': 'advanced_reporting',
'conversion_value': 999
});
// User lets trial expire
gtag('event', 'trial_expired', {
'trial_plan': 'professional',
'trial_days_used': 15,
'reason_not_converted': 'price_too_high'
});
```
**Feature Adoption & Usage:**
```javascript
// User discovers premium feature
gtag('event', 'feature_discover', {
'feature_name': 'team_collaboration',
'feature_category': 'premium',
'discovery_source': 'help_article'
});
// User activates premium feature
gtag('event', 'feature_enable', {
'feature_name': 'team_collaboration',
'feature_category': 'premium',
'current_plan': 'professional'
});
// User first uses premium feature
gtag('event', 'feature_first_use', {
'feature_name': 'team_collaboration',
'success': true,
'time_to_first_use_hours': 3
});
```
**Account & Subscription Management:**
```javascript
// User upgrades subscription
gtag('event', 'subscription_upgrade', {
'from_plan': 'starter',
'to_plan': 'professional',
'upgrade_value': 50,
'reason': 'more_users_needed'
});
// User downgrades subscription
gtag('event', 'subscription_downgrade', {
'from_plan': 'professional',
'to_plan': 'starter',
'refund_amount': 50,
'reason': 'reduced_usage'
});
// User pauses/cancels subscription
gtag('event', 'subscription_cancel', {
'plan': 'professional',
'tenure_months': 12,
'reason': 'switching_competitor'
});
// User adds team member/seat
gtag('event', 'seat_add', {
'current_seats': 5,
'new_seats': 6,
'cost_per_seat': 10
});
```
**Engagement & Activation:**
```javascript
// User invites teammate
gtag('event', 'team_invite_send', {
'invitees_count': 2,
'email_domains': 'acme.com',
'invite_source': 'onboarding'
});
// User completes onboarding
gtag('event', 'onboarding_complete', {
'onboarding_duration_minutes': 45,
'steps_completed': 8,
'data_imported': true
});
// User creates first report
gtag('event', 'first_report_created', {
'report_type': 'marketing_dashboard',
'days_to_first_report': 2
});
```
**Integration & Extensions:**
```javascript
// User connects third-party integration
gtag('event', 'integration_connect', {
'integration_name': 'slack',
'integration_category': 'communication',
'reason': 'team_notifications'
});
// User uses API
gtag('event', 'api_first_call', {
'api_endpoint': 'reports_v4',
'api_auth_type': 'oauth',
'user_type': 'developer'
});
```
**Support & Feedback:**
```javascript
// User opens support ticket
gtag('event', 'support_ticket_open', {
'ticket_category': 'billing',
'severity': 'medium',
'user_plan': 'professional'
});
// User submits feature request
gtag('event', 'feature_request_submit', {
'requested_feature': 'custom_branding',
'use_case': 'white_label_solution'
});
```
#### SaaS Event User Properties
Set these user-level properties:
```javascript
gtag('set', {
'subscription_plan': 'professional',
'subscription_status': 'active',
'monthly_recurring_revenue': 99,
'subscription_created_date': '2023-11-10',
'user_role': 'admin',
'company_size': 'mid-market',
'use_case': 'marketing_analytics',
'feature_tier': 'professional',
'integration_count': 3,
'onboarding_complete': true
});
```
---
### E-commerce / Retail
#### Product Discovery Events
```javascript
// User performs product search
gtag('event', 'product_search', {
'search_term': 'running shoes',
'search_results_count': 45,
'filters_applied': ['size', 'brand', 'price']
});
// User applies product filter
gtag('event', 'product_filter_apply', {
'filter_type': 'price',
'filter_value': '50-100',
'filtered_results_count': 12
});
// User views product list
gtag('event', 'product_list_view', {
'list_name': 'summer_sale',
'list_category': 'apparel',
'products_visible': 20
});
// User reads product review
gtag('event', 'product_review_view', {
'product_id': 'SHOE_001',
'review_rating': 4,
'review_helpful_count': 15,
'reviewer_verified_buyer': true
});
// User submits product review
gtag('event', 'product_review_submit', {
'product_id': 'SHOE_001',
'review_rating': 5,
'review_length': 250,
'includes_photo': true
});
```
#### Purchase Journey Events
```javascript
// User views shopping cart
gtag('event', 'cart_view', {
'items_count': 3,
'cart_value': 150,
'last_modified_minutes_ago': 5
});
// User updates cart
gtag('event', 'cart_update', {
'action': 'quantity_increase',
'product_id': 'SHOE_001',
'quantity_before': 1,
'quantity_after': 2
});
// User starts checkout
gtag('event', 'checkout_start', {
'items_count': 2,
'cart_value': 99.98,
'estimated_shipping': 10,
'coupon_applied': false
});
// User selects shipping method
gtag('event', 'shipping_select', {
'shipping_method': 'express',
'shipping_cost': 25,
'delivery_days': 2
});
// User enters payment information
gtag('event', 'payment_info_enter', {
'payment_method': 'credit_card',
'billing_same_as_shipping': true,
'save_payment_method': true
});
// User completes purchase
gtag('event', 'purchase', {
'transaction_id': 'TXN_12345',
'value': 134.98,
'currency': 'USD',
'tax': 10.00,
'shipping': 10.00,
'coupon': 'SAVE10',
'items': [
{
'item_id': 'SHOE_001',
'item_name': 'Running Shoe Pro',
'item_category': 'Apparel/Shoes',
'item_brand': 'SportBrand',
'item_variant': 'Blue/Size 10',
'price': 119.99,
'quantity': 1
}
]
});
```
#### Post-Purchase Events
```javascript
// User initiates return
gtag('event', 'return_initiate', {
'transaction_id': 'TXN_12345',
'return_item_count': 1,
'return_reason': 'wrong_size'
});
// User requests refund
gtag('event', 'refund_request', {
'transaction_id': 'TXN_12345',
'refund_amount': 119.99,
'refund_reason': 'product_quality'
});
// User views order tracking
gtag('event', 'order_tracking_view', {
'transaction_id': 'TXN_12345',
'days_since_order': 2,
'current_status': 'in_transit'
});
// User receives order
gtag('event', 'order_delivered', {
'transaction_id': 'TXN_12345',
'delivery_time_days': 3
});
```
#### Loyalty & Engagement
```javascript
// User joins loyalty program
gtag('event', 'loyalty_join', {
'program_name': 'VIP Rewards',
'tier': 'silver',
'referral_code': 'REF_ABC123'
});
// User adds to wishlist
gtag('event', 'wishlist_add', {
'product_id': 'SHOE_002',
'wishlist_size': 8,
'item_in_stock': true
});
// User receives and opens email
gtag('event', 'email_campaign_open', {
'campaign_name': 'summer_sale_2024',
'email_type': 'promotional',
'click_count': 2
});
// User makes repeat purchase
gtag('event', 'repeat_purchase', {
'repeat_purchase_number': 3,
'days_since_last_purchase': 45,
'customer_lifetime_value': 450
});
```
#### E-commerce User Properties
```javascript
gtag('set', {
'customer_value': 'high',
'purchase_frequency': 'monthly',
'average_order_value': 150,
'customer_lifetime_value': 3000,
'loyalty_tier': 'gold',
'preferred_category': 'shoes',
'total_purchases': 15,
'last_purchase_days_ago': 30
});
```
---
### Education / EdTech
#### Enrollment & Course Events
```javascript
// User enrolls in course
gtag('event', 'course_enroll', {
'course_id': 'PYTHON_101',
'course_name': 'Python Fundamentals',
'instructor_id': 'INSTR_001',
'course_price': 99,
'course_level': 'beginner',
'payment_method': 'credit_card'
});
// User starts course
gtag('event', 'course_start', {
'course_id': 'PYTHON_101',
'enrollment_to_start_days': 2
});
// User completes course
gtag('event', 'course_complete', {
'course_id': 'PYTHON_101',
'course_completion_percent': 100,
'days_to_completion': 30,
'final_score': 92
});
// User drops course
gtag('event', 'course_drop', {
'course_id': 'PYTHON_101',
'completion_percent': 45,
'reason': 'time_constraints'
});
```
#### Learning Activities
```javascript
// User completes lesson
gtag('event', 'lesson_complete', {
'course_id': 'PYTHON_101',
'lesson_id': 'LESSON_005',
'lesson_title': 'Functions and Loops',
'time_spent_minutes': 45,
'lesson_completion_percent': 100
});
// User takes quiz
gtag('event', 'quiz_submit', {
'course_id': 'PYTHON_101',
'quiz_id': 'QUIZ_003',
'quiz_title': 'Module 3 Assessment',
'questions_correct': 8,
'questions_total': 10,
'quiz_score_percent': 80,
'attempts': 2
});
// User watches video lesson
gtag('event', 'video_watch', {
'course_id': 'PYTHON_101',
'video_id': 'VID_001',
'video_title': 'Introduction to Functions',
'video_duration_minutes': 12,
'watch_time_minutes': 11,
'playback_speed': '1.0x',
'replays': 1
});
// User downloads resource
gtag('event', 'course_resource_download', {
'course_id': 'PYTHON_101',
'resource_type': 'code_files',
'resource_size_mb': 25
});
// User accesses discussion forum
gtag('event', 'forum_post_create', {
'course_id': 'PYTHON_101',
'post_category': 'technical_question',
'post_upvotes_received': 3
});
```
#### Progress & Achievements
```javascript
// User earns certificate
gtag('event', 'certificate_earn', {
'course_id': 'PYTHON_101',
'certificate_type': 'completion',
'final_grade': 'A',
'certificate_sharable': true
});
// User earns badge
gtag('event', 'badge_unlock', {
'badge_name': 'Quick Learner',
'badge_type': 'achievement',
'criteria_met': 'complete_3_courses_in_month'
});
// User reaches learning milestone
gtag('event', 'learning_milestone_reach', {
'milestone_name': 'proficiency_level_2',
'courses_completed': 3,
'total_learning_hours': 50
});
```
#### Education User Properties
```javascript
gtag('set', {
'student_tier': 'premium',
'total_courses_enrolled': 5,
'total_courses_completed': 3,
'average_course_rating': 4.5,
'total_learning_hours': 50,
'specialization': 'python_development',
'progress_percent': 60
});
```
---
### Media & Publishing
#### Content Consumption
```javascript
// User views article
gtag('event', 'article_view', {
'article_id': 'ART_001',
'article_title': 'GA4 Complete Guide',
'article_category': 'analytics',
'article_author': 'John Doe',
'publication_date': '2024-11-01',
'article_word_count': 5000
});
// User reaches scroll depth
gtag('event', 'article_scroll_depth', {
'article_id': 'ART_001',
'scroll_depth_percent': 75,
'time_on_page_seconds': 300
});
// User reads entire article
gtag('event', 'article_read_complete', {
'article_id': 'ART_001',
'reading_time_seconds': 1200,
'estimated_reading_time_seconds': 1500
});
// User watches video
gtag('event', 'video_watch_start', {
'video_id': 'VID_001',
'video_title': 'GA4 Tutorial',
'video_duration_minutes': 15,
'video_category': 'tutorial'
});
// User listens to podcast
gtag('event', 'podcast_listen', {
'episode_id': 'EP_123',
'episode_title': 'Analytics Trends 2024',
'listen_time_minutes': 45,
'listened_to_end': true
});
```
#### Engagement & Interaction
```javascript
// User shares content
gtag('event', 'content_share', {
'content_id': 'ART_001',
'content_type': 'article',
'share_method': 'email'
});
// User comments on content
gtag('event', 'content_comment', {
'content_id': 'ART_001',
'comment_length': 250,
'comment_helpful_votes': 5
});
// User likes/claps content
gtag('event', 'content_engage', {
'content_id': 'ART_001',
'engagement_type': 'like',
'engagement_value': 1
});
// User bookmarks content
gtag('event', 'content_bookmark', {
'content_id': 'ART_001',
'content_type': 'article',
'bookmark_folder': 'analytics'
});
```
#### Subscription & Monetization
```javascript
// User subscribes to newsletter
gtag('event', 'newsletter_subscribe', {
'newsletter_name': 'Weekly Analytics',
'subscription_frequency': 'weekly',
'email_validated': true
});
// User upgrades to premium
gtag('event', 'paywall_cross', {
'article_id': 'ART_001',
'paywall_type': 'subscription',
'conversion_value': 99
});
// User purchases single article
gtag('event', 'article_purchase', {
'article_id': 'ART_001',
'purchase_price': 4.99,
'currency': 'USD'
});
// User renews subscription
gtag('event', 'subscription_renew', {
'subscription_plan': 'annual',
'renewal_value': 99,
'tenure_years': 2
});
```
#### Media User Properties
```javascript
gtag('set', {
'subscriber_status': 'premium',
'subscription_plan': 'annual',
'favorite_categories': 'analytics,marketing',
'total_articles_read': 45,
'average_article_completion': 0.75,
'engagement_level': 'high'
});
```
---
## Cross-Industry Event Patterns
### Common to All Industries
**User Registration & Authentication:**
```javascript
gtag('event', 'user_signup', {
'signup_method': 'email',
'email_verified': true,
'signup_source': 'landing_page'
});
gtag('event', 'user_login', {
'login_method': 'password',
'login_platform': 'web'
});
```
**Account Management:**
```javascript
gtag('event', 'profile_update', {
'fields_updated': 3,
'completion_percent': 100
});
gtag('event', 'preference_change', {
'preference_type': 'language',
'new_value': 'spanish'
});
```
**Help & Support:**
```javascript
gtag('event', 'help_search', {
'search_query': 'how to export data',
'results_count': 5
});
gtag('event', 'live_chat_start', {
'chat_topic': 'billing',
'wait_time_seconds': 30
});
```
---
## Custom Event Templates by Use Case
### Sign-Up Funnel Tracking
```javascript
gtag('event', 'signup_step_1_view'); // Email input
gtag('event', 'signup_step_2_view'); // Password
gtag('event', 'signup_complete'); // Confirmation
```
### Feature Adoption Funnel
```javascript
gtag('event', 'feature_discover'); // See feature
gtag('event', 'feature_enable'); // Turn on
gtag('event', 'feature_use'); // Actually use
gtag('event', 'feature_value_realize'); // Sees benefit
```
### Conversion Value Path
```javascript
gtag('event', 'awareness_content_view'); // Top of funnel
gtag('event', 'consideration_comparison'); // Middle
gtag('event', 'decision_contact'); // Bottom
gtag('event', 'purchase'); // Conversion
```

View File

@@ -0,0 +1,291 @@
# GA4 Custom Event Naming Conventions Guide
## Complete Reference for Event Naming Strategy
### Core Naming Rules
**Rule 1: Use snake_case**
```
✅ Correct: video_tutorial_watched
❌ Wrong: VideoTutorialWatched, video-tutorial-watched
```
**Rule 2: Maximum 40 Characters**
```
✅ Correct: product_demo_request_submitted (34 chars)
❌ Wrong: product_demo_request_submitted_by_enterprise_user (57 chars)
```
**Rule 3: Start with Action Verb When Possible**
```
✅ Correct: file_downloaded, calculator_used, video_started
❌ Wrong: download_file, use_calculator, start_video
```
**Rule 4: Be Descriptive to Business Context**
```
✅ Correct: api_key_generated, subscription_upgraded, refund_requested
❌ Wrong: action, event, click, data
```
**Rule 5: Maintain Consistency**
```
✅ Correct: Always "video_completed" (never video_done, video_finished)
❌ Wrong: Mixing "cart_abandoned", "cartAbandoned", "cart_left"
```
---
## Naming Framework: [Action]_[Object]_[Context]
### Pattern Breakdown
**Action:** What the user is doing
- `view`, `create`, `update`, `delete`, `submit`, `download`, `watch`, `listen`
- `click`, `scroll`, `hover`, `focus`, `select`, `open`, `close`
- `start`, `complete`, `pause`, `resume`, `skip`, `error`
- `upgrade`, `downgrade`, `cancel`, `refund`, `return`
**Object:** What entity is being acted upon
- `video`, `article`, `product`, `course`, `trial`, `subscription`
- `button`, `form`, `popup`, `modal`, `notification`
- `cart`, `order`, `invoice`, `receipt`, `account`
- `dashboard`, `report`, `export`, `import`, `setting`
**Context:** Qualifier or category (optional)
- `_free`, `_premium`, `_enterprise`, `_trial`
- `_mobile`, `_desktop`, `_tablet`
- `_email`, `_social`, `_referral`
- `_failed`, `_success`, `_error`, `_retry`
### Framework Examples
**E-commerce Context:**
- `product_view` (user viewed product)
- `product_compare_viewed` (comparison page opened)
- `add_to_cart` (item added to shopping cart)
- `wishlist_add` (item added to saved list)
- `review_submit` (product review posted)
- `add_to_cart_mobile` (mobile-specific cart action)
**SaaS Context:**
- `trial_start` (free trial activated)
- `trial_end` (trial period ended)
- `feature_unlock` (premium feature accessed)
- `api_key_create` (authentication token generated)
- `integration_connect` (third-party service linked)
- `upgrade_click` (upgrade button clicked)
**Content Context:**
- `video_start` (video playback began)
- `video_complete` (video finished)
- `article_read` (article fully read)
- `podcast_skip` (podcast episode skipped)
- `download_start` (resource download initiated)
- `whitepaper_request` (lead magnet requested)
**SaaS Trial Context:**
- `trial_signup` (trial account created)
- `trial_feature_use` (premium feature tested during trial)
- `trial_extend` (trial period extended)
- `trial_convert` (trial upgraded to paid)
- `trial_abandon` (trial left unused)
---
## Industry Naming Patterns
### SaaS Specific
**Onboarding & Activation:**
- `onboarding_start`, `onboarding_step_completed`, `onboarding_complete`
- `welcome_tour_start`, `tutorial_lesson_completed`
- `first_data_entry`, `first_report_generated`
**Feature Engagement:**
- `feature_discover`, `feature_explore`, `feature_adopt`
- `integration_setup`, `integration_test`, `integration_activate`
- `api_call_success`, `api_error_encountered`
**Monetization:**
- `upgrade_modal_view`, `upgrade_click`, `upgrade_complete`
- `plan_comparison_view`, `pricing_page_visit`
- `subscription_pause`, `subscription_resume`, `subscription_cancel`
**Support & Help:**
- `help_article_search`, `help_article_view`, `help_article_helpful`
- `support_ticket_open`, `support_chat_start`
- `feature_request_submit`, `bug_report_submit`
### Education Specific
**Course Engagement:**
- `course_enroll`, `course_start`, `course_complete`
- `lesson_view`, `lesson_complete`, `lesson_retry`
- `quiz_attempt`, `quiz_submit`, `quiz_pass`
**Learning Progress:**
- `certificate_earn`, `badge_unlock`, `milestone_reach`
- `study_streak_start`, `study_streak_end`
- `resource_download`, `note_create`, `bookmark_add`
**Social & Collaboration:**
- `discussion_post_create`, `discussion_reply`, `discussion_helpful_vote`
- `peer_review_submit`, `study_group_join`
### Media/Publishing Specific
**Content Consumption:**
- `article_read_start`, `article_read_complete`, `article_scroll_depth_100`
- `video_play`, `video_pause`, `video_quality_change`
- `podcast_episode_start`, `podcast_episode_complete`
**Engagement:**
- `content_share`, `content_comment`, `content_like`
- `newsletter_signup`, `newsletter_open`, `newsletter_click`
- `bookmark_save`, `bookmark_view`, `bookmark_share`
**Creator Features:**
- `draft_create`, `article_publish`, `video_upload`
- `monetization_enable`, `subscriber_only_content_publish`
### E-commerce Specific
**Product Discovery:**
- `search_submit`, `filter_apply`, `sort_change`
- `category_view`, `subcategory_view`
- `product_review_read`, `product_rating_view`
**Purchase Journey:**
- `product_add_to_cart`, `cart_view`, `cart_update_quantity`
- `checkout_start`, `shipping_option_select`, `payment_method_select`
- `apply_coupon`, `coupon_remove`, `gift_card_apply`
**Post-Purchase:**
- `order_confirmation_view`, `order_tracking_click`
- `product_return_initiate`, `refund_request_submit`
---
## Naming Checklist
Before finalizing custom event names:
- [ ] Event name is snake_case (lowercase, underscores)
- [ ] Event name is under 40 characters
- [ ] Event name is action-oriented (verb first when possible)
- [ ] Event name is specific to business domain
- [ ] Event name is consistent with existing naming scheme
- [ ] Event name doesn't duplicate a recommended event
- [ ] Event name would be understandable to business stakeholders
- [ ] Event name could be documented without parameters
- [ ] Event is documented in team's event dictionary
- [ ] Event follows organization's naming standards
---
## Anti-Pattern Examples to Avoid
### Generic Names
```
❌ Bad: click, event, action, user_action, interaction
✅ Good: button_click, demo_button_click, video_play_click
```
### Vague Names
```
❌ Bad: data, info, tracking, send, request
✅ Good: customer_data_export, form_submit_request, contact_email_send
```
### Inconsistent Names
```
❌ Bad: "user_signup", "registerUser", "SignUp", "sign_up_completed"
✅ Good: Always "user_signup" (consistent)
```
### Over-specific Names
```
❌ Bad: "user_clicked_blue_button_in_hero_section_on_homepage_on_mobile"
✅ Good: "hero_cta_click" or "homepage_cta_click"
```
### Parameters in Event Names
```
❌ Bad: "video_watched_hd", "trial_signup_30day", "user_from_google"
✅ Good: "video_watched" with parameter video_quality="hd"
```
---
## Implementation Examples
### Example 1: Complete Naming Decision
**Business Goal:** Track when users request product demo
**Naming Process:**
1. Action: request, submit
2. Object: demo, product_demo
3. Context: (none needed, already specific)
**Decision:** `demo_request` or `demo_request_submit`?
- `demo_request` (28 chars) - Better: action is implied in "request"
- Final name: `demo_request`
### Example 2: SaaS Feature Adoption
**Business Goal:** Track when users enable an integration
**Naming Process:**
1. Action: enable, activate, setup, connect
2. Object: integration
3. Context: integration type
**Decision:** `integration_enabled` or `integration_setup_complete`?
- `integration_enabled` (21 chars) - Clean and action-oriented
- Final name: `integration_enabled`
- Parameter: `integration_type` (e.g., "slack", "zapier")
### Example 3: Educational Progress
**Business Goal:** Track when students complete quiz
**Naming Process:**
1. Action: submit, complete, finish
2. Object: quiz
3. Context: (optional: pass/fail)
**Decision:** `quiz_submit` or `quiz_complete`?
- `quiz_submit` (11 chars) - User action
- Final name: `quiz_submit`
- Parameter: `quiz_result` (e.g., "pass", "fail"), `score` (numeric)
---
## Team Naming Standards (Template)
Document your organization's naming conventions:
```
Event Naming Standard
====================
Format: [action]_[object]_[context]
Actions Used: create, update, delete, view, submit, download, upload, upload, share
Objects: product, course, video, article, user, team, workspace, settings
Context: Optional qualifiers like _mobile, _free, _premium, _failed
Examples Approved:
- product_view
- course_enroll
- quiz_submit
- integration_enabled
- support_ticket_create
Examples Not Approved:
- user_action
- click_event
- data_send
```

View File

@@ -0,0 +1,598 @@
# GA4 Custom Event Parameters: Strategy & Best Practices
## Complete Parameter Planning Guide
### Parameter Selection Framework
#### Step 1: Identify Business Question
Define what the event reveals about user behavior:
```
Event: demo_request
Business Question: Which customer segments are interested in enterprise features?
Questions Answered:
- Is the user currently a customer? (customer_status)
- Which industry are they in? (industry)
- What size is their company? (company_size)
- How did they discover the demo? (discovery_source)
```
#### Step 2: Determine Required Context
List parameters that answer each question:
| Question | Parameter | Values |
|----------|-----------|--------|
| Customer status? | customer_status | lead, current, competitor |
| Industry? | industry | tech, finance, healthcare |
| Company size? | company_size | startup, mid-market, enterprise |
| Discovery source? | discovery_source | content, ad, partner, email |
#### Step 3: Validate Against Constraints
- Are there <25 parameters total?
- Is each parameter <100 characters?
- Can you analyze/segment by these parameters?
- Will these parameters have <100,000 unique values?
#### Step 4: Implement & Register
Send parameters in event, then register as custom dimensions in GA4 Admin.
---
## Parameter Types & Guidelines
### String Parameters
Use for categorical data with limited unique values:
```javascript
gtag('event', 'feature_adopt', {
'feature_name': 'advanced_reporting', // Good: ~10-50 unique
'user_tier': 'professional', // Good: 5 options max
'source': 'in_app_suggestion', // Good: ~10-20 options
'user_email': 'john@example.com' // BAD: millions of unique
});
```
**String Parameter Best Practices:**
- Keep values consistent (always lowercase: "free", not "Free")
- Use labels, not IDs when possible
- Avoid high-cardinality values (emails, URLs, timestamps)
- Maximum 100 characters per value
### Numeric Parameters
Use for quantifiable measurements:
```javascript
gtag('event', 'video_watched', {
'video_duration': 1200, // Seconds (integer)
'watch_time': 900, // Seconds (integer)
'completion_percent': 75, // Percentage (0-100)
'playback_speed': 1.25, // Decimal (float)
'rewatch_count': 2 // Count (integer)
});
```
**Numeric Parameter Best Practices:**
- Use appropriate units (seconds, percentages, counts)
- Store as numbers, not strings ("120", not "2 minutes")
- Use integers for counts, floats for measurements
- Document units clearly
### Boolean Parameters
Use for binary on/off state:
```javascript
gtag('event', 'signup_complete', {
'email_verified': true,
'payment_method_saved': false,
'opted_to_newsletter': true
});
```
**Boolean Parameter Best Practices:**
- Limited to true/false (or 0/1)
- Clear naming (is_*, has_*, enabled_)
- Only use when genuinely binary (not if 3+ states)
### Array/Object Parameters
Limited use - primarily for ecommerce items:
```javascript
gtag('event', 'purchase', {
'items': [
{
'item_id': 'SKU_001',
'item_name': 'Shoe Pro',
'price': 99.99,
'quantity': 1
}
]
});
```
**Array Parameter Best Practices:**
- Only for items in ecommerce context
- Each item = one product in transaction
- Maximum 27 items per event
---
## Parameter Naming Strategy
### Naming Convention
Use lowercase snake_case, descriptive names:
```javascript
// ✅ Good
gtag('event', 'feature_adopt', {
'feature_name': 'advanced_reporting',
'adoption_reason': 'team_request',
'time_to_adopt_days': 3
});
// ❌ Bad
gtag('event', 'feature_adopt', {
'fn': 'advanced_reporting', // Too abbreviated
'reason': 'team_request', // Too generic
'ttad': 3 // Unclear abbreviation
});
```
### Common Parameter Names
Establish naming standards:
| Concept | Parameter Name | Type |
|---------|----------------|------|
| User identifier | user_id, customer_id | string |
| Product identifier | product_id, item_id | string |
| Product name | product_name, item_name | string |
| Category | category, item_category | string |
| Price | price, unit_price | number |
| Quantity | quantity | integer |
| Status | status, account_status | string |
| Type | type, event_type | string |
| Method | method, payment_method | string |
| Result | result, completion_status | string |
| Reason | reason, error_reason | string |
| Source | source, utm_source | string |
| Duration | duration_minutes, duration_seconds | integer |
| Percentage | percent_complete, completion_percent | integer |
### Avoid These Naming Patterns
```
❌ Avoid abbreviations: ttc → time_to_convert
❌ Avoid capitalization: ProductName → product_name
❌ Avoid spaces: "product name" → product_name
❌ Avoid special chars: product-name → product_name
❌ Avoid encoding IDs: user_123 → user_id with value "123"
❌ Avoid mixed naming: user_name + customerEmail → user_name + user_email
```
---
## Parameter Value Standards
### Categorical Values
```javascript
// Plan types (be consistent)
'plan': 'free' // ✅
'plan': 'Free' // ❌ Inconsistent case
'plan': 'starter' // ✅
'plan': 'pro' // ✅
'plan': 'PRO' // ❌ Inconsistent case
// Status values
'status': 'active'
'status': 'inactive'
'status': 'pending'
'status': 'suspended'
```
### Time-Based Values
Never use timestamp parameters - use GA4 date automatically:
```javascript
// ❌ Wrong: timestamp parameters
gtag('event', 'purchase', {
'purchase_date': '2024-11-10', // NO - GA4 auto-collects
'purchase_time': '14:30:00', // NO - Use event timestamp
'user_since': 1728518400 // NO - Use user property registration
});
// ✅ Right: relative time parameters
gtag('event', 'purchase', {
'customer_tenure_months': 12, // How long customer
'time_to_purchase_days': 45, // Days from signup to purchase
'session_duration_minutes': 15 // Duration in this session
});
```
### Numeric Value Ranges
Standardize ranges for analysis:
```javascript
// ✅ Good: Consistent ranges
'company_size': 'startup', // <50 people
'company_size': 'mid-market', // 50-500 people
'company_size': 'enterprise', // 500+ people
// ✅ Good: Specific numbers
'team_size': 5,
'message_length': 250,
'files_uploaded': 3
// ❌ Bad: Vague or inconsistent
'company_size': 'big', // Too vague
'team_size': 'small', // Should be number
```
---
## Parameter Documentation Template
Document parameters for team reference:
```markdown
## Event: demo_request
### Parameters
| Name | Type | Values | Purpose | Scoping |
|------|------|--------|---------|---------|
| demo_type | string | walkthrough, technical, sales | Type of demo | Event |
| industry | string | tech, finance, healthcare, etc. | User's industry | Event |
| company_size | string | startup, mid-market, enterprise | Company size | Event |
| current_customer | boolean | true, false | If already customer | Event |
| utm_source | string | landing_page, email, referral | Traffic source | Event |
### Rules
- demo_type is required
- company_size defaults to "unknown" if not provided
- Only send actual values, never null
```
---
## Common Parameter Mistakes & Solutions
### Mistake 1: High-Cardinality Parameters
```javascript
// ❌ Bad: Too many unique values
gtag('event', 'lead_create', {
'email': 'john@example.com', // Millions of values
'company_domain': 'acme.com', // Thousands of values
'full_name': 'John Smith', // Millions of values
'phone': '555-1234' // Millions of values
});
// ✅ Good: Categorical values
gtag('event', 'lead_create', {
'email_domain_category': 'company', // Few: company, gmail, other
'company_size': 'enterprise', // Few: startup, mid, enterprise
'lead_source': 'webinar', // Few: webinar, form, trial
'country': 'US' // Manageable: country codes
});
```
### Mistake 2: Data That Belongs in Custom Dimensions, Not Parameters
```javascript
// ❌ Bad: Event-specific data sent as parameter
gtag('event', 'page_view', {
'subscription_tier': 'premium' // This is user property
});
// ✅ Good: Send as user property
gtag('set', {
'subscription_tier': 'premium'
});
gtag('event', 'page_view');
// subscription_tier automatically included
```
### Mistake 3: Redundant Parameters
```javascript
// ❌ Bad: Redundant - one is enough
gtag('event', 'purchase', {
'product_id': 'SHOE_001',
'product_id_sku': 'SHOE_001',
'sku': 'SHOE_001'
});
// ✅ Good: Single consistent parameter
gtag('event', 'purchase', {
'product_id': 'SHOE_001'
});
```
### Mistake 4: Forgetting to Register Custom Dimensions
```javascript
// ❌ Problem: Parameter sent but not registered
gtag('event', 'video_watched', {
'video_quality': 'hd' // Sent but not registered
});
// ✅ Solution: Register in GA4 Admin
// Admin > Data Display > Custom Definitions > Create Custom Dimension
// Dimension Name: Video Quality
// Scope: Event
// Event Parameter: video_quality
```
---
## Parameter Implementation Patterns
### Pattern 1: Optional Parameters
Some parameters only relevant in certain conditions:
```javascript
// Always sent
gtag('event', 'purchase', {
'value': 99.99,
'currency': 'USD'
});
// Only if coupon applied
if (coupon_applied) {
gtag('event', 'purchase', {
'coupon': 'SAVE10',
'discount_percent': 10
});
}
// Only for high-value orders
if (value > 500) {
gtag('event', 'purchase', {
'high_value': true,
'account_manager': 'jane_doe'
});
}
```
### Pattern 2: Conditional Parameter Values
Parameter value depends on other data:
```javascript
// Determine user segment based on multiple factors
let customer_segment;
if (annual_spend > 50000) {
customer_segment = 'vip';
} else if (annual_spend > 10000) {
customer_segment = 'high_value';
} else if (annual_spend > 1000) {
customer_segment = 'regular';
} else {
customer_segment = 'free';
}
gtag('event', 'purchase', {
'customer_segment': customer_segment,
'annual_spend': annual_spend
});
```
### Pattern 3: Enriched Parameters
Add context by combining data sources:
```javascript
// Combine internal + external data
let utm_source = getURLParameter('utm_source');
let internal_campaign = getCampaignIdFromDB();
let marketing_channel = mapToChannel(utm_source);
gtag('event', 'signup_complete', {
'utm_source': utm_source, // Raw UTM param
'internal_campaign': internal_campaign, // From DB
'marketing_channel': marketing_channel // Derived/mapped
});
```
---
## Advanced Parameter Strategies
### Strategy 1: Parameter Hierarchies
Use structured parameter naming for related data:
```javascript
gtag('event', 'course_complete', {
// Hierarchical structure
'course_type': 'technical', // Top level
'course_subtype': 'python', // Sub-category
'course_level': 'advanced', // Difficulty
// Alternative: use compound parameter
'course_id': 'PYTHON_ADV_101' // ID encodes all info
});
```
### Strategy 2: Derived Parameters
Calculate parameters from other data:
```javascript
let time_to_purchase_days = (purchase_date - signup_date) / 86400000;
let engagement_score = calculate_engagement(activity_log);
let ltv_segment = classify_ltv(revenue_history);
gtag('event', 'first_purchase', {
'time_to_purchase_days': Math.round(time_to_purchase_days),
'engagement_score': engagement_score, // 1-10
'ltv_segment': ltv_segment // low, medium, high
});
```
### Strategy 3: Lookup Table Parameters
Map internal IDs to user-friendly values:
```javascript
// Define mapping
const feature_lookup = {
'feat_001': 'team_collaboration',
'feat_002': 'advanced_reporting',
'feat_003': 'api_access'
};
let feature_id = getUserFeature();
gtag('event', 'feature_enable', {
'feature_name': feature_lookup[feature_id], // User-friendly
'feature_id': feature_id // Internal ID
});
```
---
## Parameter Limits & Optimization
### GA4 Parameter Limits
| Limit | Value |
|-------|-------|
| Parameters per event | 25 maximum |
| Parameter name length | 40 characters maximum |
| Parameter value length | 100 characters maximum* |
| Custom dimension parameters | 50 event-scoped, 25 user-scoped |
*Exceptions: page_title (300), page_referrer (420), page_location (1000)
### Optimization Strategies
**When at Parameter Limit:**
1. **Consolidate Related Parameters:**
```javascript
// ❌ Many parameters
gtag('event', 'purchase', {
'item_1_name': 'Shoe',
'item_1_price': 99.99,
'item_2_name': 'Shirt',
'item_2_price': 29.99
});
// ✅ Use items array
gtag('event', 'purchase', {
'items': [
{ 'item_name': 'Shoe', 'price': 99.99 },
{ 'item_name': 'Shirt', 'price': 29.99 }
]
});
```
2. **Use Compound Values:**
```javascript
// ❌ Many parameters
gtag('event', 'feature_adopt', {
'feature_category': 'reporting',
'feature_type': 'advanced',
'feature_difficulty': 'high'
});
// ✅ Compound value
gtag('event', 'feature_adopt', {
'feature_class': 'reporting_advanced_high'
});
```
3. **Move to User Properties:**
```javascript
// ❌ Repeat in every event
gtag('event', 'purchase', {
'company_size': 'enterprise',
'industry': 'finance'
});
// ✅ Set as user property
gtag('set', {
'company_size': 'enterprise',
'industry': 'finance'
});
gtag('event', 'purchase', {
// user properties automatically included
});
```
---
## Parameter Testing & Validation
### Test Checklist
Before production deployment:
- [ ] All parameters sent are documented
- [ ] Parameter values are consistent (same values always)
- [ ] High-cardinality parameters removed or consolidated
- [ ] No PII (personally identifiable information) in parameters
- [ ] Parameter values don't exceed 100 characters
- [ ] Total parameters per event ≤25
- [ ] Custom dimensions registered in GA4 Admin
- [ ] DebugView shows correct parameter values
- [ ] 24-48 hours passed - data appears in reports
- [ ] Custom dimension values appear in report breakdowns
### Validation Script (JavaScript)
```javascript
function validateEventParameters(eventName, params) {
// Check parameter count
if (Object.keys(params).length > 25) {
console.warn(`Event ${eventName} has >25 parameters`);
}
// Check parameter name length
Object.keys(params).forEach(key => {
if (key.length > 40) {
console.warn(`Parameter name "${key}" exceeds 40 chars`);
}
// Check parameter value length
const value = params[key];
if (typeof value === 'string' && value.length > 100) {
console.warn(`Parameter "${key}" value exceeds 100 chars`);
}
// Check for PII patterns
if (value && typeof value === 'string') {
if (value.includes('@') && value.includes('.')) {
console.warn(`Parameter "${key}" may contain email`);
}
if (/\b\d{3}-\d{2}-\d{4}\b/.test(value)) {
console.warn(`Parameter "${key}" may contain SSN`);
}
}
});
return true;
}
// Usage
validateEventParameters('purchase', {
'value': 99.99,
'currency': 'USD'
});
```