Files
gh-henkisdabro-wookstar-cla…/skills/ga4-custom-events/references/parameter-strategy.md
2025-11-29 18:32:40 +08:00

15 KiB

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:

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:

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:

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:

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:

// ✅ 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

// 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:

// ❌ 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:

// ✅ 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:

## 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

// ❌ 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

// ❌ 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

// ❌ 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

// ❌ 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:

// 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:

// 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:

// 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:

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:

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:

// 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:
// ❌ 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 }
  ]
});
  1. Use Compound Values:
// ❌ 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'
});
  1. Move to User Properties:
// ❌ 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)

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'
});