Skip to content

Attribution & Tracking Implementation

Every sale must be attributable to its original traffic source.

This is not optional. This is not “nice to have.” This is fundamental to running a marketing operation.


Overview: From Anonymous Visitor to Paying Customer

Section titled “Overview: From Anonymous Visitor to Paying Customer”

Everyone starts at Stage 1. Each subsequent stage is a subset of the previous.

Stage 1: Landing (UTM Parameters)
├─ Have: UTM params, session data, page views
└─ Don't have: Contact information
↓ (Subset converts)
Stage 2: Lead (UTM + Contact)
├─ Have: UTM params + Email/Phone
└─ Don't have: Purchase/transaction
↓ (Subset converts)
Stage 3: Sale (UTM + Contact + Transaction)
├─ Have: UTM params + Email/Phone + Card + Billing + Invoice
└─ DEFINITIVE - Multiple system records

The Drop-off Groups:

  • Dropped at Stage 1: UTM parameters, NO contact → Anonymous bounces
  • Dropped at Stage 2: UTM parameters + Contact, NO sale → Leads who didn’t convert
  • Reached Stage 3: UTM parameters + Contact + Sale → Customers

The Key Insight: The difference between groups is simply whether they have contact and/or sale data. The UTM parameters persist through all stages.


User lands on your site with URL:

https://landing.fh.co/medication-tirzepatide-discount-01?
utm_source=fb&
utm_medium=cpc&
utm_campaign=tirzepatide-q4&
utm_term=weight-loss-medication&
utm_content=video-ad-v2&
campaign_id=120236311971890504&
ad_id=120233281654680682&
adset_id=120233281060550682&
affid=1000

Capture and persist:

  • All UTM parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content)
  • Campaign identifiers (campaign_id, ad_id, adset_id)
  • Affiliate/channel identifiers (affid, fbp, etc.)
  • Landing page URL
  • Referrer
  • Timestamp

Storage:

  • Browser cookies (first-party)
  • Local storage
  • Session storage
  • Server-side session
  • Analytics tool (PostHog, GA, etc.)

As user navigates through funnel:

  • Page 1: Landing page
  • Page 2: Quiz questions
  • Page 3: Qualify/achieve screen
  • Page 4: Contact form
  • Page 5: Payment/conversion

All UTM parameters persist across:

  • Page navigations
  • Form submissions
  • Redirects
  • Subdomain changes
  • Days/weeks (if user returns)

Technical implementation:

  • Pass parameters in hidden form fields
  • Maintain in session/cookies
  • Backend session persistence
  • User profile attributes

Step 3: Lead Capture - Connect Anonymous to Identified

Section titled “Step 3: Lead Capture - Connect Anonymous to Identified”

User provides PII (email/phone):

{
"email": "john@example.com",
"phone": "+1-555-0123",
"first_name": "John",
"last_name": "Doe",
// Attribution data (from Step 1)
"utm_source": "fb",
"utm_medium": "cpc",
"utm_campaign": "tirzepatide-q4",
"utm_term": "weight-loss-medication",
"utm_content": "video-ad-v2",
"campaign_id": "120236311971890504",
"ad_id": "120233281654680682",
"adset_id": "120233281060550682",
"affid": "1000",
"landing_page": "/medication-tirzepatide-discount-01",
"first_seen": "2025-11-25T14:34:25Z"
}

Now you have a Lead with full attribution.

When lead converts to customer/sale, you have MULTIPLE definitive records:

Sale Record (Billing System):

{
"transaction_id": "txn_xyz789",
"customer_id": "cust_abc123",
"email": "john@example.com",
"purchase_date": "2025-11-28T10:23:45Z",
"amount": "$499.00",
"product": "Tirzepatide Monthly Subscription",
"status": "completed"
}

Billing Details:

{
"card_last4": "4242",
"card_brand": "Visa",
"billing_address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102"
},
"billing_email": "john@example.com"
}

Invoice Record:

{
"invoice_number": "INV-2025-001234",
"invoice_date": "2025-11-28",
"amount": "$499.00",
"customer_email": "john@example.com",
"status": "paid"
}

Attribution Record (Connected via Email):

{
"email": "john@example.com", // THE CONNECTOR
// Original attribution (from Step 1, via Step 3)
"utm_source": "fb",
"utm_campaign": "tirzepatide-q4",
"campaign_id": "120236311971890504",
"ad_id": "120233281654680682",
"landing_page": "/medication-tirzepatide-discount-01",
"first_seen": "2025-11-25T14:34:25Z",
// Journey metrics
"days_to_convert": 3,
"touchpoints": 7,
"sessions": 4
}

The Connection is Trivial:

  1. Sale record has email: john@example.com
  2. Lead record has email: john@example.com + UTM parameters
  3. Match on email → Sale is attributed to original UTM parameters

Sales are SUPER DEFINITIVE because they have:

  • Transaction ID (unique identifier)
  • Card information (person paid real money)
  • Billing address (physical location)
  • Invoice number (accounting record)
  • Email/phone (contact identifier)
  • Multiple system records (billing system, CRM, invoicing, etc.)

This is not speculation. This is hard data across multiple systems.

Now you can answer:

  • Which campaigns drive sales? (campaign_id)
  • What’s the ROI of each ad? (ad_id → revenue)
  • Which landing pages convert to sales? (landing_page)
  • What’s the cost per acquisition? (ad spend ÷ conversions by campaign)
  • Which UTM terms have highest LTV? (utm_term → customer value)
  • What’s the complete customer journey? (UTM → Lead → Sale with timestamps)

Capturing UTM parameters: 10 lines of JavaScript

// Parse URL parameters
const urlParams = new URLSearchParams(window.location.search);
const utmData = {
utm_source: urlParams.get('utm_source'),
utm_medium: urlParams.get('utm_medium'),
utm_campaign: urlParams.get('utm_campaign'),
utm_term: urlParams.get('utm_term'),
utm_content: urlParams.get('utm_content'),
campaign_id: urlParams.get('campaign_id'),
ad_id: urlParams.get('ad_id')
};
// Store in localStorage/cookie
localStorage.setItem('attribution', JSON.stringify(utmData));

Persisting through funnel: Already done if using any modern analytics tool

Connecting to lead/customer: One database field per UTM parameter

Total implementation time: 1 day for a competent developer

  • Morning: Implement UTM capture
  • Afternoon: Add fields to lead/customer database
  • Done.

Every major tool has this built-in:

  • PostHog: Automatically captures UTM parameters, persists through session, connects to identified users
  • Google Analytics: GA4 does this natively with User-ID
  • Mixpanel: User profiles with UTM properties
  • Segment: Track page with context, identify user connects everything
  • HubSpot: Contact properties for UTM parameters
  • Salesforce: Campaign attribution fields

If your tool doesn’t do this, get a better tool.


Common Excuses (And Why They’re Invalid)

Section titled “Common Excuses (And Why They’re Invalid)”

❌ “Our funnel spans multiple domains/technologies”

Section titled “❌ “Our funnel spans multiple domains/technologies””

Reality: Doesn’t matter. Pass UTM parameters via:

  • URL query strings between domains
  • Server-side session with shared database
  • Third-party cookies (if same-party)
  • Server-to-server API calls

❌ “We use a third-party funnel builder”

Section titled “❌ “We use a third-party funnel builder””

Reality: Every funnel builder (ClickFunnels, Unbounce, Leadpages, etc.) supports:

  • Hidden form fields for UTM parameters
  • Webhook pass-through of data
  • Integration with CRM/analytics

❌ “Users come back days later, cookies expire”

Section titled “❌ “Users come back days later, cookies expire””

Reality:

  • First-party cookies can last 1-2 years
  • Once user provides email, store attribution in database permanently
  • Use server-side storage, not just cookies

Reality: No, it’s not. This is basic web development. If your team can’t do this, they’re incompetent.

❌ “Our analytics tool doesn’t support it”

Section titled “❌ “Our analytics tool doesn’t support it””

Reality: Get a better tool. This is 2025, not 2005.


Campaign: 120236311971890504
- Ad Spend: $10,000
- Clicks: 5,000
- Leads: 423
- Sales: 187
- Revenue: $93,313 (187 × $499)
- ROAS: 9.3x
- CPA: $53.48
- Decision: SCALE THIS

vs.

Campaign: 120236311971234567
- Ad Spend: $10,000
- Clicks: 8,000
- Leads: 150
- Sales: 15
- Revenue: $7,485 (15 × $499)
- ROAS: 0.75x
- CPA: $666.67
- Decision: PAUSE THIS
Landing Page: /medication-tirzepatide-discount-01
- Traffic: 33,804
- Sales: 1,960 (5.8% conversion)
- Revenue: $978,040
Landing Page: /medication-tirzepatide-pre-quiz-tt
- Traffic: 1,132
- Sales: 249 (22% conversion)
- Revenue: $124,251
- Insight: Lower traffic but 4x conversion - drive more traffic here

Every sale shows:

  • Which ad they clicked
  • Which landing page they saw
  • Which quiz answers they gave
  • How many days to convert
  • How many sessions/touchpoints
  • Complete customer journey

This is what “sales are not mysterious” means.


  • Capture all UTM parameters on landing
  • Capture campaign_id, ad_id, adset_id
  • Capture landing page URL and referrer
  • Store in cookies/localStorage
  • Send to analytics tool (PostHog, GA, etc.)
  • Maintain UTM data across page navigations
  • Pass UTM data through form submissions
  • Store in hidden form fields if needed
  • Configure analytics tool to persist user properties
  • When user provides email/phone, connect to UTM data
  • Save attribution fields in CRM/database
  • Create lead record with full attribution
  • Set up PostHog user identification
  • Create attribution report: leads by campaign
  • Create attribution report: sales by campaign
  • Calculate ROAS/CPA by campaign
  • Build dashboard showing end-to-end funnel

Even if your system is:

  • Multiple components
  • Different technologies for landing pages, forms, billing
  • Complex multi-step funnel
  • Third-party payment processor
  • Separate CRM and billing systems

It’s still 1 day.

The connection is simple:

  1. Capture UTM on landing → Store with session
  2. Capture email on lead form → Connect UTM to email
  3. Sale happens with email → Match sale to lead → Get UTM attribution

Snap. Finger snap. Done.

No excuses.



Who: Everyone who clicks your ad/link Data captured:

  • UTM parameters (source, medium, campaign, term, content)
  • Campaign/Ad IDs
  • Landing page URL
  • Session data
  • Device/browser info
  • Timestamp

No PII yet - These are anonymous visitors

Count: 55,775 people in your example


Who: Visitors who provided contact information Data captured:

  • Everything from Stage 1 (UTM parameters)
  • PLUS: Email and/or phone number
  • Name
  • Any form fields they filled

Now you have PII - Anonymous visitor becomes identified lead

Count: 5,509 people in your example (9.88% of Stage 1)

The difference: Stage 2 has contact, Stage 1 doesn’t. That’s it.


Who: Leads who purchased Data captured:

  • Everything from Stage 1 (UTM parameters)
  • Everything from Stage 2 (Email/phone)
  • PLUS: Transaction data:
    • Transaction ID
    • Card information
    • Billing address
    • Purchase amount
    • Invoice number
    • Payment status
    • Product purchased

Super definitive - Multiple system records (billing, invoicing, CRM, payment processor)

Count: 187 people in your example (3.37% of Stage 2, 0.34% of Stage 1)

The difference: Stage 3 has transaction records, Stage 2 doesn’t.


Group A: Dropped at Landing (Stage 1 only)

Section titled “Group A: Dropped at Landing (Stage 1 only)”
  • Count: 50,266 people (55,775 - 5,509)
  • Have: UTM parameters, session data
  • Don’t have: Contact information
  • Analysis: Never engaged enough to provide email
  • Attribution: Can’t attribute individual sales, but can see which campaigns drive more engagement
  • Count: 5,322 people (5,509 - 187)
  • Have: UTM parameters + email/phone
  • Don’t have: Transaction/purchase
  • Analysis: Provided contact but didn’t convert to customer
  • Attribution: Know which campaigns generate leads (even if not sales yet)
  • Action: Can nurture via email/SMS since you have contact info
  • Count: 187 people
  • Have: UTM parameters + email/phone + transaction data
  • Don’t have: Nothing - this is complete data
  • Analysis: Full attribution from ad click → landing → lead → sale
  • Attribution: Definitive ROI per campaign/ad/landing page

Sales have multiple definitive records across multiple systems:

  1. Billing System: Transaction ID, amount, card info, billing address
  2. Payment Processor: Payment confirmation, receipt, transaction log
  3. CRM/Database: Customer record with email/phone
  4. Invoicing System: Invoice number, invoice PDF, accounting record
  5. Analytics: Conversion event with UTM parameters

All connected by email/phone.

When you see:

  • Transaction txn_xyz789 for john@example.com
  • Lead record for john@example.com with campaign_id: 120236311971890504

You instantly know: This $499 sale came from Facebook campaign 120236311971890504.

It’s not rocket science. It’s basic data matching.


Sales are not mysterious. Every sale traces back to a specific user who landed with specific UTM parameters.

  • Stage 1: UTM parameters (everyone who lands)
  • Stage 2: UTM + Contact (subset who become leads)
  • Stage 3: UTM + Contact + Transaction (subset who become customers)

The connection is trivial: Match on email/phone.

You must capture this. It’s not optional. It’s not hard. Just do it.


The Reality: Users Don’t Convert in a Straight Line

Section titled “The Reality: Users Don’t Convert in a Straight Line”

Initial Traffic SourceRetargeting ChannelsFinal Conversion

Day 1: Initial Landing

  • User clicks Facebook ad (campaign 120236311971890504, affid 1000)
  • Lands on /medication-tirzepatide-discount-01
  • Provides email: sarah@example.com
  • Doesn’t purchase (becomes Lead, not Sale)
  • System stores: email + UTM parameters + campaign ID + affid

Day 3: SMS Retargeting

  • Marketing sends SMS to sarah@example.com (actually phone number)
  • User clicks SMS link → visits site
  • New session, but SAME person (same email/phone)

Day 5: Email Retargeting

  • Marketing sends email to sarah@example.com
  • User clicks email link → visits site again
  • Still doesn’t purchase

Day 7: Direct Visit → Purchase

  • User remembers site, visits directly (no UTM parameters in URL)
  • Makes purchase: $499
  • Sale record: Transaction ID, card info, email: sarah@example.com

Which channel gets credit for the sale?

Wrong Answer: “Direct visit” or “SMS” or “Email”

  • This ignores how the user originally found you

Correct Answer: Facebook campaign 120236311971890504

  • This was the FIRST TOUCH that brought them in
  • Without that initial ad, they never would have existed in your system

When you query sales attribution:

SELECT
sales.email,
sales.amount,
sales.purchase_date,
leads.utm_source,
leads.utm_campaign,
leads.campaign_id,
leads.affid,
leads.first_seen_date
FROM sales
JOIN leads ON sales.email = leads.email

Result:

email: sarah@example.com
amount: $499
purchase_date: 2025-11-28
utm_source: fb
utm_campaign: tirzepatide-q4
campaign_id: 120236311971890504
affid: 1000
first_seen: 2025-11-21
days_to_convert: 7

The sale is attributed to the original Facebook campaign, even though the final session came from direct visit after SMS and email touches.

With proper system setup, you can see:

  1. First Touch: Facebook ad (Day 1)
  2. Middle Touches: SMS (Day 3), Email (Day 5)
  3. Last Touch: Direct visit (Day 7)
  4. Full Journey: FB → SMS → Email → Direct → Purchase

Attribution models you can use:

  • First-Touch: Credit Facebook (most common for acquisition)
  • Last-Touch: Credit Direct visit (less useful)
  • Multi-Touch: Split credit across FB, SMS, Email
  • Data-Driven: Algorithm determines contribution of each touch

For marketing analysis, first-touch is usually most important because:

  • It shows which campaigns ACQUIRE customers
  • SMS/Email retargeting works on already-acquired leads
  • You need to know which paid ads are worth the investment

The system had the initial data stored from when user first landed (Day 1):

  • Email captured with form submission
  • UTM parameters persisted to database
  • Lead record created with full attribution

When sale happens 7 days later:

  • Sale record has email: sarah@example.com
  • Lead record has email: sarah@example.com + original UTM data
  • Match on email → Sale attributed to original source

It doesn’t matter that they came back via SMS/email/direct - the original attribution is preserved.

Scenario: You check sales attribution in your system (Moon, PostHog, etc.)

What you see:

  • Sales attributed to specific campaigns
  • Sales attributed to specific affids (traffic sources)
  • Sales attributed to original landing pages

Some sales show:

  • Original source: Facebook campaign X, affid 1000
  • Final touchpoint: SMS or Email retargeting
  • Attribution: Facebook campaign X (because that’s first touch)

Why you can see this instantly:

  • Not “magical tools”
  • The data was stored from Day 1 when they first landed
  • You just need to query: sales → leads (via email) → UTM parameters
  • The connections are already in the system

Campaign Performance (Full Funnel):

Campaign 120236311971890504:
├─ Landings: 33,804
├─ Leads: 3,429 (10.1%)
└─ Sales: 187 (5.5% of leads, 0.55% of landings)
├─ Direct conversion: 45 sales (24%)
├─ Via SMS retargeting: 82 sales (44%)
├─ Via Email retargeting: 48 sales (26%)
└─ Via other touchpoints: 12 sales (6%)

Key insights:

  • Campaign drove 3,429 leads
  • 187 became customers (even if took 7+ days and retargeting)
  • Most sales (70%) required retargeting via SMS/email
  • But ALL sales attributed back to original campaign

Traffic Source Performance:

Affid 1000 (Facebook):
- Leads: 5,200
- Sales: 420
- Revenue: $209,580
- ROAS: 10.5x
- Most sales came via retargeting, but all originated from FB

Original attribution is sacred. Retargeting is amplification, not replacement.

  • User finds you via paid ad → First-touch attribution
  • You retarget via SMS/email → Conversion optimization
  • User converts via any channel → Credit goes to first touch

Without the original ad, they wouldn’t exist in your retargeting list.

To enable multi-touch attribution:

  1. Capture first-touch data (UTM parameters at landing)
  2. Store with PII (email/phone when captured)
  3. Persist forever (never overwrite original attribution)
  4. Track all touchpoints (SMS clicks, email clicks, direct visits)
  5. Connect via identifier (email/phone matches across systems)

With PostHog, Moon, or similar tools: This is automatic

  • First-touch stored on user profile
  • All sessions/events tagged with user ID
  • Sale event connected to user → Gets original attribution

Not magical. Just proper data architecture.