# Attribution Prevention Fixes - Comprehensive Summary


**Last Updated:** 2025-11-20

**Date:** 2025-11-20  
**Purpose:** Document all fixes implemented to prevent direct traffic misattribution for new contacts

## Overview

This document summarizes all fixes implemented to prevent the 5 categories of direct traffic misattribution identified in the audit from occurring for new contacts.

## Category E: Internal Domain Referrer Misattribution (47% of issues)

### Problem
When users navigate internally (e.g., homepage → pricing page), the referrer becomes ordio.com. The attribution logic skipped internal referrers and defaulted to "Direct Traffic", losing the original attribution.

### Fixes Implemented

#### JavaScript Side (`v2/js/utm-tracking.js`)

1. **Enhanced Original Attribution Storage**
   - Modified `storeOriginalReferrer()` to store complete attribution data (referrer + UTM parameters) in localStorage
   - Stores attribution on first visit when referrer is NOT same-site
   - Expires after 90 days (matches cookie expiration)
   - Called AFTER UTM extraction and processing to ensure complete data

2. **Enhanced `getUTMDataForAPI()` Method**
   - When same-site referrer detected, retrieves original attribution from localStorage
   - Restores original UTM parameters if current ones look like direct traffic
   - Sends `original_attribution_used` flag to server-side
   - Sends empty string instead of 'direct' when no original attribution available (lets server-side handle)

3. **New Method: `getOriginalAttribution()`**
   - Retrieves complete original attribution data from localStorage
   - Handles expiration (90 days)
   - Returns null if expired or invalid

#### Server-Side (`v2/config/utm-validation.php`)

1. **Enhanced `ordio_resolve_attribution()` Function**
   - Added `original_attribution_used` parameter to detect when JavaScript restored original attribution
   - Added `$trustOriginalAttribution` flag to trust restored attribution
   - Enhanced internal referrer handling to use original attribution when available
   - Prevents overriding restored attribution with Direct Traffic

2. **Improved Direct Traffic Fallback Logic**
   - Only defaults to Direct Traffic if:
     - No UTM parameters AND
     - No gclid AND
     - No referrer (or internal referrer without original attribution)
   - Checks for original attribution before defaulting
   - Infers leadSource from UTM parameters when original attribution is present

## Category F: Search Engine Without UTM (2% of issues)

### Problem
Search engine referrers without UTM parameters were marked as Direct Traffic instead of Organic Search.

### Fixes Implemented

#### JavaScript Side (`v2/js/utm-tracking.js`)

1. **Enhanced `detectNonUTMTrafficSources()` Method**
   - Added explicit check for search engine referrers even when no UTM parameters present
   - Sets `utm_source` to search engine name, `utm_medium='organic'`, `leadSource='Organic Search'`
   - Prevents search engine traffic from being marked as Direct Traffic

#### Server-Side (`v2/config/utm-validation.php`)

1. **Enhanced Search Engine Referrer Detection**
   - Checks for search engine referrers BEFORE other referrer checks
   - Only checks if not already classified as organic or paid traffic
   - Sets `utm_source`, `utm_medium='organic'`, `leadSource='Organic Search'` when search engine detected
   - Prevents defaulting to Direct Traffic when search engine referrer is present

## Category C: Lost UTM Parameters During Navigation (14% of issues)

### Problem
UTM parameters were lost when users navigated between pages internally.

### Fixes Implemented

1. **Cookie Persistence**
   - Cookies already persist for 90 days with `.ordio.com` domain
   - localStorage fallback ensures UTM data survives cookie failures
   - Original attribution storage preserves UTM parameters separately

2. **Form Submission UTM Inclusion**
   - Forms use `getUTMDataForAPI()` which restores original attribution
   - Fallback chain: URL → cookies → localStorage → original attribution
   - All UTM parameters included in form submissions

## Category B: Dark Social (9% of issues)

### Status
Expected behavior - no fix needed. Dark social (shared links without referrer) is correctly classified as Direct Traffic.

## Category UNKNOWN: Edge Cases (28% of issues)

### Status
Reviewed and confirmed as true Direct Traffic - no fix needed.

## Technical Implementation Details

### JavaScript Attribution Flow

1. **Page Load**
   - Extract UTM parameters from URL
   - Detect non-UTM traffic sources
   - Correct Google Ads UTM
   - Validate UTM parameters
   - **Store original attribution** (if referrer is NOT same-site)
   - Save to cookies and localStorage

2. **Internal Navigation**
   - Current referrer becomes same-site
   - Original attribution preserved in localStorage
   - UTM parameters preserved in cookies

3. **Form Submission**
   - Call `getUTMDataForAPI()`
   - If same-site referrer detected:
     - Retrieve original attribution from localStorage
     - Restore original UTM parameters if current ones look like direct traffic
     - Send `original_attribution_used` flag
   - Include all UTM data in form submission

### Server-Side Attribution Flow

1. **Receive Form Data**
   - Check for `original_attribution_used` flag
   - If flag present and UTM data exists, trust the attribution

2. **Internal Referrer Handling**
   - Detect if referrer is internal domain
   - If internal AND original attribution available:
     - Use original attribution (don't override)
   - If internal AND no original attribution:
     - Check other indicators before defaulting to Direct Traffic

3. **Search Engine Detection**
   - Check referrer for search engine domains
   - If search engine detected:
     - Set `utm_source` to search engine name
     - Set `utm_medium='organic'`
     - Set `leadSource='Organic Search'`

4. **Direct Traffic Fallback**
   - Only default to Direct Traffic if:
     - No UTM parameters AND
     - No gclid AND
     - No referrer (or internal referrer without original attribution)

## Testing Recommendations

### Test Scenarios

1. **Google Ads → Internal Navigation → Form Submission**
   - User lands from Google Ads with UTM parameters
   - Navigates internally to pricing page
   - Submits form
   - **Expected:** Attribution preserved (Google Ads, not Direct Traffic)

2. **Google Search → Internal Navigation → Form Submission**
   - User lands from Google Search (no UTM)
   - Navigates internally to pricing page
   - Submits form
   - **Expected:** Attribution preserved (Organic Search, not Direct Traffic)

3. **Referral → Internal Navigation → Form Submission**
   - User lands from referral site
   - Navigates internally to pricing page
   - Submits form
   - **Expected:** Attribution preserved (referral, not Direct Traffic)

4. **Direct → Internal Navigation → Form Submission**
   - User lands directly (no referrer, no UTM)
   - Navigates internally to pricing page
   - Submits form
   - **Expected:** Direct Traffic (correct)

5. **Search Engine Referrer Without UTM**
   - User lands from Google Search (no UTM parameters)
   - Submits form immediately
   - **Expected:** Organic Search (not Direct Traffic)

## Monitoring

### Key Metrics to Monitor

1. **Direct Traffic Percentage**
   - Should decrease after fixes
   - Monitor weekly to catch regressions

2. **Internal Referrer Attribution**
   - Monitor contacts with internal referrers
   - Verify original attribution is preserved

3. **Search Engine Attribution**
   - Monitor contacts with search engine referrers
   - Verify they're classified as Organic Search, not Direct Traffic

### Monitoring Script

Use `scripts/hubspot/monitor-direct-traffic.php` to:
- Flag contacts where attribution might be incorrect
- Identify patterns of misattribution
- Alert on unusual direct traffic patterns

## Prevention Checklist

### For New Form Implementations

- [ ] Forms use `getUTMDataForAPI()` or `getAllUTMData()`
- [ ] UTM data included in form submission
- [ ] Original attribution flag included if applicable
- [ ] Test with internal navigation scenarios

### For UTM Tracking Changes

- [ ] Original attribution storage still works
- [ ] Cookie persistence maintained
- [ ] localStorage fallback functional
- [ ] Test attribution preservation across pages

### For Attribution Logic Changes

- [ ] Internal referrer handling preserved
- [ ] Search engine detection still works
- [ ] Direct Traffic fallback logic correct
- [ ] Test all traffic types (paid, organic, referral, direct)

## Files Modified

1. `v2/js/utm-tracking.js`
   - Enhanced `storeOriginalReferrer()` method
   - Added `getOriginalAttribution()` method
   - Enhanced `getUTMDataForAPI()` method
   - Enhanced `detectNonUTMTrafficSources()` method
   - Fixed initialization order

2. `v2/config/utm-validation.php`
   - Enhanced `ordio_resolve_attribution()` function
   - Added internal referrer handling
   - Improved Direct Traffic fallback logic
   - Enhanced search engine detection

## Validation Steps

1. **Test Original Attribution Storage**
   - Open browser console
   - Check `localStorage.getItem('ordio_original_attribution')`
   - Verify data includes referrer and UTM parameters

2. **Test Internal Navigation**
   - Land from external site with UTM
   - Navigate internally
   - Submit form
   - Verify attribution preserved in HubSpot

3. **Test Search Engine Detection**
   - Land from Google Search (no UTM)
   - Submit form
   - Verify leadSource='Organic Search' in HubSpot

4. **Test Direct Traffic**
   - Land directly (no referrer, no UTM)
   - Submit form
   - Verify leadSource='Direct Traffic' in HubSpot

## Next Steps

1. Monitor direct traffic percentage weekly
2. Review contacts with internal referrers monthly
3. Update documentation as needed
4. Create automated tests for attribution scenarios

