Understanding Event Schemas & Parameters
Understanding Event Schemas & Parameters
Section titled “Understanding Event Schemas & Parameters”The Attribution Bible
Section titled “The Attribution Bible”Parameters are how you see everything. If you don’t understand your event schema, you can’t read your data.
What is an Event Schema?
Section titled “What is an Event Schema?”Event Schema: The structure/format of data captured with each event
Every event in your system has:
- Event name (e.g.,
conv_landing_page_view,purchase_completed) - User identifier (e.g.,
user_id,distinct_id,email) - Timestamp
- Properties (event-specific data)
- Parameters (tracking/attribution data)
The parameters are the most important part for attribution.
Common Event Parameters
Section titled “Common Event Parameters”Standard UTM Parameters
Section titled “Standard UTM Parameters”Captured from URL when user lands:
{ "utm_source": "fb", // Traffic source (fb, google, email, etc.) "utm_medium": "cpc", // Medium (cpc, social, email, organic) "utm_campaign": "tirzepatide-q4", // Campaign name "utm_term": "weight-loss", // Keyword/targeting term "utm_content": "video-ad-v2" // Ad variation}Platform-Specific IDs
Section titled “Platform-Specific IDs”Facebook:
{ "campaign_id": "120236311971890504", "ad_id": "120233281654680682", "adset_id": "120233281060550682", "fbp": "fb.1.1764081009618.5799537734763449309", "fbc": "fb.1.1764081009618..."}Google Ads:
{ "gclid": "CjwKCAiA...", "campaign_id": "22740491004", "g_campaignid": "22740491004"}Custom Tracking Parameters
Section titled “Custom Tracking Parameters”Affiliate/Channel:
{ "affid": "1000", // Traffic source identifier "aff_sub": "fb", // Sub-affiliate "tid": "1" // Tracking ID}Email Tracking:
{ "source": "email_crm", "campaign": "direct-crm-ticket", "email_id": "msg_abc123", "email_campaign_id": "camp_xyz789"}SMS Tracking:
{ "sms_campaign": "sms_prospect_nov_20", "sms_message_id": "msg_sms_xyz", "sms_link_id": "link_123"}Session/Technical Parameters
Section titled “Session/Technical Parameters”{ "$referrer": "https://google.com/search?q=...", "$initial_referrer": "https://facebook.com", "landing_page": "/medication-tirzepatide-discount-01", "landing_page_source": "https://landing.fh.co/medication-tirzepatide-discount-01?utm_source=...", "$initial_host": "landing.fh.co", "viewport_width": 411, "viewport_height": 871}Reading Event Footprints
Section titled “Reading Event Footprints”Example 1: Facebook Ad Click
Section titled “Example 1: Facebook Ad Click”Event: Landing page view
Parameters captured:
{ "event": "conv_landing_page_view", "distinct_id": "019aa24361a57f03928122b309e186f6", "timestamp": "2025-11-20T14:23:45Z",
// The footprint "utm_source": "fb", "utm_medium": "cpc", "campaign_id": "120236311971890504", "ad_id": "120233281654680682", "adset_id": "120233281060550682", "affid": "1000", "fbp": "fb.1.1764081009618.5799537734763449309", "landing_page": "/medication-tirzepatide-discount-01"}Reading the footprint:
- ✅
utm_source: fb→ Facebook traffic - ✅
campaign_idpresent → Specific campaign - ✅
ad_idpresent → Can attribute to specific ad - ✅
affid: 1000→ Internal tracking shows this is our main Facebook channel - ✅
fbppresent → Facebook pixel tracking active
What this tells you: User came from Facebook campaign 120236311971890504, ad 120233281654680682, through affid 1000, landed on discount-01 page.
Example 2: SMS Retargeting (Disguised as Google)
Section titled “Example 2: SMS Retargeting (Disguised as Google)”Event: Purchase
Parameters captured:
{ "event": "purchase_completed", "distinct_id": "019a974d0bb877f19905e4e10c3d5892", "timestamp": "2025-11-20T16:52:33Z", "amount": 499,
// Surface-level label "source": "google ads", // MISLEADING
// The actual footprint "g_campaignid": "22740491004", // Original Google campaign "sms_campaign": "sms_prospect_nov_20", // Current SMS campaign "sms_message_id": "msg_sms_xyz", // SMS identifier "original_utm_source": "google", // First-touch "original_campaign_id": "22740491004" // First-touch campaign}Reading the footprint:
- ⚠️ Surface source says “google ads” BUT
- ✅
sms_campaignpresent → This is SMS retargeting - ✅
sms_message_idpresent → Confirms SMS click - ✅
original_utm_source: google→ User ORIGINALLY came from Google - ✅
original_campaign_id→ Preserve first-touch attribution
What this tells you: User originally came from Google Ads campaign 22740491004, was retargeted via SMS campaign “sms_prospect_nov_20”, clicked SMS link and purchased. Attribution goes to Google campaign (first-touch).
Without reading parameters: “This is a Google Ads sale” ✅ Correct attribution But without SMS parameters: You wouldn’t know SMS retargeting was involved
Example 3: Email from CRM
Section titled “Example 3: Email from CRM”Event: Purchase
Parameters captured:
{ "event": "purchase_completed", "distinct_id": "bceb8c64219a4188bb78bf144f20363c", "timestamp": "2025-11-20T18:15:22Z", "amount": 499,
// Current source "source": "email_crm", "campaign": "direct-crm-ticket", "email_id": "msg_abc123",
// Original source (preserved) "original_utm_source": "fb", "original_campaign_id": "120236311971890504", "original_ad_id": "120233281654680682", "first_seen": "2025-11-15T10:23:45Z"}Reading the footprint:
- ✅ Current source: email_crm (from CRM system)
- ✅ Campaign: direct-crm-ticket (specific email campaign)
- ✅ Original source: Facebook campaign 120236311971890504
- ✅ First seen: 5 days ago
What this tells you: User originally came from Facebook ad 5 days ago, was nurtured via CRM email, clicked email and purchased. Attribution goes to Facebook campaign.
The Schema in Different Systems
Section titled “The Schema in Different Systems”PostHog Event Schema
Section titled “PostHog Event Schema”{ "event": "purchase_completed", "distinct_id": "019aa24361a57f03928122b309e186f6", "timestamp": "2025-11-20T14:23:45.000Z", "properties": { "$current_url": "https://landing.fh.co/checkout/complete", "$referrer": "https://landing.fh.co/checkout", "amount": 499, "product": "Tirzepatide Subscription",
// Attribution parameters "utm_source": "fb", "utm_campaign": "tirzepatide-q4", "campaign_id": "120236311971890504", "affid": "1000" }, "$set": { "email": "user@example.com" }}Key fields:
distinct_id: User identifierproperties: All event data including parameters$set: User properties to store on profile
Moon Attribution Schema
Section titled “Moon Attribution Schema”{ "user_id": "019aa24361a57f03928122b309e186f6", "email": "user@example.com", "conversion": { "amount": 499, "timestamp": "2025-11-20T14:23:45Z", "transaction_id": "txn_abc123" }, "attribution": { "first_touch": { "source": "fb", "campaign_id": "120236311971890504", "ad_id": "120233281654680682", "timestamp": "2025-11-15T10:23:45Z" }, "last_touch": { "source": "email_crm", "campaign": "direct-crm-ticket", "timestamp": "2025-11-20T14:20:15Z" }, "touchpoints": [ { "source": "fb", "timestamp": "2025-11-15T10:23:45Z" }, { "source": "sms", "timestamp": "2025-11-18T16:30:12Z" }, { "source": "email_crm", "timestamp": "2025-11-20T14:20:15Z" } ] }}Key fields:
first_touch: Original attribution (most important)last_touch: Final touchpoint before conversiontouchpoints: All interactions in sequence
How to Learn Your Schema
Section titled “How to Learn Your Schema”Step 1: Export Sample Events
Section titled “Step 1: Export Sample Events”Pull 10-20 events from your system:
- Landing page views
- Lead captures
- Purchases
- Any key conversion events
Step 2: Observe the Fields
Section titled “Step 2: Observe the Fields”Look at what’s captured:
- User identifiers (user_id, distinct_id, email)
- UTM parameters (utm_source, utm_medium, etc.)
- Platform IDs (campaign_id, ad_id, gclid, fbp)
- Custom parameters (affid, tid, etc.)
- Session data (referrer, landing_page, device info)
Step 3: Document Common Patterns
Section titled “Step 3: Document Common Patterns”Example findings:
- “We capture
affid- values are 1000 (Facebook), 1001 (Google), 1002 (Organic)” - “We have
campaign_idfor all paid campaigns” - “Email campaigns have
source: email_crmandcampaignfield” - “SMS has
sms_campaignandsms_message_id”
Step 4: Create Your Attribution Mapping
Section titled “Step 4: Create Your Attribution Mapping”Footprint Recognition:
affid = 1000 + utm_source = fb → Facebook trafficaffid = 1001 + gclid present → Google Ads trafficsource = email_crm → Email retargetingsms_campaign present → SMS retargetingaffid = null + utm_source = null → Direct/organicStep 5: Use It
Section titled “Step 5: Use It”Now when you see data:
- Row with affid 1000 → “This is Facebook”
- Row with sms_campaign → “This is SMS retargeting”
- Row with email_crm → “This is email nurture”
No meetings needed. Just observe and apply.
Common Mistakes in Reading Footprints
Section titled “Common Mistakes in Reading Footprints”Mistake 1: Trusting Surface Labels
Section titled “Mistake 1: Trusting Surface Labels”❌ Wrong: “Source says ‘Google Ads’, so it’s a Google Ads sale”
✅ Right: “Source says ‘Google Ads’, but parameters show sms_campaign → It’s SMS retargeting from a user who originally came from Google”
Mistake 2: Ignoring Missing Parameters
Section titled “Mistake 2: Ignoring Missing Parameters”❌ Wrong: “This sale has no affid, so we don’t know where it came from”
✅ Right: “No affid, but has email_id parameter → It’s email retargeting. Check original UTM parameters to see first-touch.”
Mistake 3: Not Checking Multi-Touch
Section titled “Mistake 3: Not Checking Multi-Touch”❌ Wrong: “User converted from email, attribute to email”
✅ Right: “User converted from email, but email was sent to lead acquired from Facebook campaign X → Attribute to Facebook”
The Practical Workflow
Section titled “The Practical Workflow”When analyzing sales/conversions:
- Export data with all parameters
- Read the footprints (don’t trust source labels)
- Look for:
- Original UTM parameters (first-touch)
- Current source parameters (last-touch)
- Platform IDs (campaign_id, ad_id for granular attribution)
- Retargeting markers (sms_campaign, email_id)
- Attribute to first-touch (original acquisition source)
- Note multi-touch journey (SMS/email amplification)
Time required: 1-5 minutes once you understand your schema
Key Principle
Section titled “Key Principle”If you don’t understand your event footprints, you’re a bad hunter.
Every event leaves traces (parameters). These traces tell you:
- Where user came from
- How they navigated
- What campaigns drove them
- Full multi-touch journey
Learn to read the footprints once, then use them forever.
No advanced tools required. Just observation and application.
Working with Raw Event Data
Section titled “Working with Raw Event Data”The Reality: Data is Ugly
Section titled “The Reality: Data is Ugly”This is what real event data looks like:
{ "content_type": "product", "currency": "USD", "fromGTM": "true", "referrer": "", "session_id": "TmtSzXXE2P0YSdxW1rkmygHDmDMsiWKn", "timestamp": "2025-11-20T16:42:48.209Z", "url": "https://gtm-msr.appspot.com/render?id=GTM-MGBZ7NKD"}{ "_gl": "1*17a11gh*_gcl_au*MjExMDAxODM2NC4xNzYzNjU4OTE2", "ad_id": "120236311972130504", "adset_id": "120236311972120504", "aff_sub": "fb", "affid": "1000", "campaign_id": "120236311971890504", "content_ids": ["bundle-micro-ol-itirz-monthly-50off"], "content_type": "product", "currency": "USD", "email": "user@example.com", "fbclid": "IwZXh0bgNhZW0BMABhZGlkAasqbG8Xa4hzcnRjBmFwcF9pZAo2NjI4NTY4Mzc5AAEexJyKeui8f7l3JN25hswCDqja7L_nNmQyUL-0Qel1rBwPrcPg6JuhIXNzJJI_aem_xX2ZI4lIsfVcEUocCVYP9Q", "posthog_distinct_id": "019aa243-61a5-7f03-9281-22b309e186f6", "posthog_session_id": "019aa243-61a4-7d5e-99c9-593206fd056d", "transaction_id": "d9c26d5e-f19c-4f71-8712-21188b02aa42", "utm_campaign": "120236311971890504", "utm_medium": "cpc", "utm_source": "fb"}It’s messy. It’s ugly. It’s full of IDs and codes.
This is normal. This is the core of what you do.
The Core Principle: IDs, Affids, UTMs Are Everything
Section titled “The Core Principle: IDs, Affids, UTMs Are Everything”These ugly parameters ARE the core:
affid: 1000, 1001, 1002 → Traffic source identifiercampaign_id: 120236311971890504 → Specific campaignad_id: 120236311972130504 → Specific adutm_source: fb, google → Platformutm_campaign: Campaign nameposthog_distinct_id: User identifierfbclid: Facebook Click IDtransaction_id: Purchase identifier
Everything else (charts, dashboards, reports) is just a consequence of understanding these.
If you understand the parameters, you don’t need anything else.
Example Analysis: Reading Real Event Data
Section titled “Example Analysis: Reading Real Event Data”Event 1: Google Tag Manager Tracking
Section titled “Event 1: Google Tag Manager Tracking”{ "content_type": "product", "currency": "USD", "fromGTM": "true", "referrer": "", "session_id": "TmtSzXXE2P0YSdxW1rkmygHDmDMsiWKn", "timestamp": "2025-11-20T16:42:48.209Z", "url": "https://gtm-msr.appspot.com/render?id=GTM-MGBZ7NKD"}Reading the footprint:
fromGTM: true→ Tracked via Google Tag Managerurl: gtm-msr.appspot.com→ Google Tag Manager measurement server- Has session_id but not much else
- Minimal footprint
What to do: Google “gtm-msr.appspot.com” → Takes 1 minute → Learn this is Google’s way of checking traffic
Event 2: Facebook Sale with Full Attribution
Section titled “Event 2: Facebook Sale with Full Attribution”{ "_gl": "1*17a11gh*_gcl_au*MjExMDAxODM2NC4xNzYzNjU4OTE2", "ad_id": "120236311972130504", "adset_id": "120236311972120504", "aff_sub": "fb", "affid": "1000", "campaign_id": "120236311971890504", "content_ids": ["bundle-micro-ol-itirz-monthly-50off"], "content_type": "product", "currency": "USD", "email": "user@example.com", "fbclid": "IwZXh0bgNhZW0BMAAZG...", "posthog_distinct_id": "019aa243-61a5-7f03-9281-22b309e186f6", "posthog_session_id": "019aa243-61a4-7d5e-99c9-593206fd056d", "transaction_id": "d9c26d5e-f19c-4f71-8712-21188b02aa42", "utm_campaign": "120236311971890504", "utm_medium": "cpc", "utm_source": "fb"}Reading the footprint:
Attribution parameters:
affid: 1000→ Our Facebook channel identifieraff_sub: fb→ Confirms Facebookcampaign_id: 120236311971890504→ Specific campaignad_id: 120236311972130504→ Specific adadset_id: 120236311972120504→ Specific ad setutm_source: fb,utm_medium: cpc→ Paid Facebook traffic
Facebook parameters:
fbclid: IwZXh0bgNhZW0...→ Facebook Click ID (full tracking)_gl: 1*17a11gh...→ Google Linker parameter (cross-domain tracking)_gcl_au: MjExMDA...→ Google Ads User ID
Payment/Product parameters:
content_ids: ["bundle-micro-ol-itirz-monthly-50off"]→ Product purchasedcontent_type: product→ It’s a product salecurrency: USD→ US dollarstransaction_id: d9c26d5e...→ Unique transaction
User identification:
email: user@example.com→ PII (should probably be redacted in exports)posthog_distinct_id: 019aa243...→ PostHog user IDposthog_session_id: 019aa243...→ PostHog session ID
What this tells you:
- Facebook campaign 120236311971890504, ad 120236311972130504 drove this sale
- User purchased “bundle-micro-ol-itirz-monthly-50off” product
- Sale tracked in transaction d9c26d5e-f19c-4f71-8712-21188b02aa42
- Can attribute revenue to specific Facebook ad
- Can connect to PostHog user profile for full journey
Insight discovered: content_ids parameter came from payment system
- How do you know? Checked a few sales, this parameter appeared on all of them
- Format is obvious: “bundle-micro-ol-itirz-monthly-50off” = product name
- Now you know: content_ids = product purchased
The Critical Practice: Manual Event Checking
Section titled “The Critical Practice: Manual Event Checking”Never Trust Charts Without Checking Raw Events
Section titled “Never Trust Charts Without Checking Raw Events”Wrong workflow:
- Look at chart showing 100 conversions
- Trust the number
- Make decisions
Right workflow:
- Look at chart showing 100 conversions
- Export raw events that formed this number
- Check 5-10 events manually
- Understand: What parameters do they have? Are they consistent? Any anomalies?
- THEN trust the chart and make decisions
Why This Matters
Section titled “Why This Matters”Without checking raw events:
- You might be counting test transactions
- Events might be missing key parameters
- Duplicate events might inflate numbers
- Attribution might be broken
With checking raw events:
- You SEE that transaction IDs are unique
- You SEE that all have proper attribution parameters
- You SEE any test transactions (obvious from emails or IDs)
- You KNOW the data is clean
The Manual Funnel Walkthrough
Section titled “The Manual Funnel Walkthrough”Do this regularly:
-
Go through your own funnel
- Click your own ad
- Land on landing page
- Fill out forms
- Complete purchase (use test mode)
-
Watch events fire in real-time
- Open PostHog/analytics tool
- See events appear as you go through funnel
- Check parameters on each event
-
Verify the footprints
- Landing event has UTM parameters? ✓
- Lead event has email + UTM parameters? ✓
- Purchase event has transaction_id + UTM parameters? ✓
- All events linked by same user_id? ✓
Time required: 10-15 minutes
Value: Complete understanding of how data flows through your system
Understanding Parameter Evolution
Section titled “Understanding Parameter Evolution”Schema Changes Tell a Story
Section titled “Schema Changes Tell a Story”When you change something in your system, parameters change:
Example: Funnel Redesign
Before redesign (Old funnel):
{ "funnel_step": "landing", "page_variant": "A", "quiz_version": 1}After redesign (New funnel):
{ "funnel_version": "v2", "landing_variant": "discount-01", "quiz_enabled": true, "quiz_questions": 5}What changed:
funnel_step→funnel_version(renamed)page_variant→landing_variant(renamed)quiz_version→quiz_enabled+quiz_questions(split into two fields)
Why this matters: If you see events with old schema and new schema mixed, you know when the redesign launched.
Common Schema Evolution Patterns
Section titled “Common Schema Evolution Patterns”Payment system integration:
- Before: No
transaction_id, nocontent_ids - After:
transaction_id,content_ids,billing_addressappear
New traffic source:
- Before: Only
utm_source+utm_medium - After:
affid,aff_sub,tidappear for granular tracking
A/B test launch:
- Before: Just landing page path
- After:
ab_test_variant,ab_test_idparameters appear
Mobile app tracking added:
- Before: Only web events
- After:
platform: ios/android,app_version,device_idappear
Tracking Schema Evolution
Section titled “Tracking Schema Evolution”Keep a changelog:
2025-11-01: Added content_ids parameter to purchase events (payment system integration)2025-11-05: Changed quiz_version from number to boolean quiz_enabled2025-11-10: Added affid parameter for all traffic sources2025-11-15: Split landing_page into landing_page + landing_variantWhy: When analyzing historical data, you need to know when parameters changed
Practical Workflow with Raw Data
Section titled “Practical Workflow with Raw Data”Daily Analysis Routine
Section titled “Daily Analysis Routine”Step 1: Export raw events (1 minute)
- Sales from yesterday
- Or leads from last week
- Or landing page views from specific campaign
Step 2: Open in spreadsheet (ugly data, accept it)
- Columns: user_id, affid, utm_source, campaign_id, ad_id, parameters (JSON)
- Looks messy - this is normal
Step 3: Scan for patterns (2-3 minutes)
- Do all events have affid? (If not, tracking is broken)
- Do all sales have transaction_id? (If not, payment tracking is broken)
- Any test emails/IDs? (Filter these out)
- Any unknown parameters? (Research them)
Step 4: Research unknown parameters (1 minute per parameter)
- Copy parameter name + value
- Paste into ChatGPT: “What is this parameter in web analytics: _gl=1*17a11gh…”
- Get explanation
- Document it for future reference
Step 5: Build understanding (ongoing)
- Over time, you learn your schema intimately
- You recognize patterns instantly
- You spot anomalies immediately
- You become a better hunter
The “Better Hunter” Concept
Section titled “The “Better Hunter” Concept”Bad hunter:
- Only looks at dashboards
- Doesn’t understand raw data
- Can’t explain where numbers come from
- Trusts charts blindly
- Lost when data looks wrong
Good hunter:
- Checks raw events regularly
- Understands every parameter
- Can trace any number back to source
- Verifies data manually
- Spots issues immediately
Great hunter:
- Knows schema evolution history
- Recognizes patterns across systems
- Can debug attribution issues
- Understands how every system connects
- Owns the data, doesn’t delegate to developers
How to Become a Better Hunter
Section titled “How to Become a Better Hunter”- Look at raw data daily (not just dashboards)
- Research every unknown parameter (build vocabulary)
- Walk through funnel manually (see events fire)
- Track schema changes (document evolution)
- Check events before trusting charts (verify reality)
- Own the data (don’t treat it as “developer shit”)
This is not technical work. This is marketing analytics work.
Key Takeaways
Section titled “Key Takeaways”- Raw data is ugly - accept it: IDs, affids, UTMs, JSON blobs are the core
- Charts are consequences: Everything flows from understanding raw parameters
- Never trust charts without checking raw events: 5-10 events is enough to verify
- Walk through your own funnel: See how events actually fire
- Research unknown parameters: ChatGPT/Google, takes 1 minute
- Track schema evolution: Changes tell the story of system changes
- Better hunter = better marketer: The more you understand parameters, the better your analysis
- This is your job, not developer’s: Owning raw data is core marketing analytics work
Being comfortable with ugly data is not optional. It’s fundamental.