599 lines
15 KiB
Markdown
599 lines
15 KiB
Markdown
# 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'
|
|
});
|
|
```
|