# Google Ads Attribution Fixes - Implementation Summary

**Last Updated:** 2026-01-28  
**Status:** ✅ Fixes Implemented - Ready for Testing

## Quick Summary

Fixed Google Ads attribution issues where leads from `/gastro` and `/schichtbetriebe` landing pages were being misattributed as "Organic Search" or "Direct Traffic" instead of "Google".

## Root Causes Fixed

1. ✅ **gclid not prioritized** - `determineLeadSourceFromContext()` now checks `gclid` FIRST
2. ✅ **Detection order issue** - Google Ads detection happens BEFORE `determineLeadSourceFromContext()`
3. ✅ **Missing override logic** - Wrong leadSource values are now overridden when Google Ads indicators present
4. ✅ **Frontend mismatch** - Frontend now uses 'Google' instead of 'Paid Search'
5. ✅ **Missing hsa_src detection** - Added `hsa_src='g'` detection in `determineLeadSourceFromContext()`

## Files Modified

### Backend

- `v2/config/utm-validation.php` - Enhanced `determineLeadSourceFromContext()` to prioritize gclid
- `v2/api/lead-capture.php` - Improved Google Ads detection (Step 1 & Step 2)
- `v2/api/collect-lead.php` - Added Google Ads detection
- `html/form-hs.php` - Enhanced Google Ads override logic for demo booking modal (NEW)

### Frontend

- `v2/js/utm-tracking.js` - Changed 'Paid Search' to 'Google' for consistency

### Scripts Created

- `v2/scripts/hubspot/google-ads-attribution-audit.php` - Contact audit script
- `v2/scripts/hubspot/analyze-google-ads-attribution.php` - Analysis script
- `v2/scripts/hubspot/test-google-ads-attribution.php` - Test script (all tests passed ✓)
- `v2/scripts/hubspot/test-form-attribution-scenarios.php` - Form-specific test scenarios (NEW)
- `v2/scripts/hubspot/test-all-form-attribution.php` - Comprehensive test suite for all form types (NEW)
- `v2/scripts/hubspot/monitor-google-ads-attribution.php` - Monitoring script

## Testing Status

### ✅ Completed

- Unit tests: All 10 test cases passed
- Syntax validation: All PHP files validated
- Logic verification: Attribution logic verified
- Form-hs.php enhancement: Google Ads override logic added
- Test scripts: Created comprehensive test suites for all form types

### ⏳ Pending (Requires User Action)

- Browser testing: Test form submissions on `/gastro` and `/schichtbetriebe` with Google Ads parameters
- HubSpot verification: Verify attribution in HubSpot after form submission
- Production monitoring: Run monitoring script to verify fixes work in production

## Next Steps

1. **Deploy to Production** - Deploy code changes
2. **Test Form Submissions** - Test with real Google Ads parameters:
   - Visit `/gastro?gclid=test123`
   - Submit form
   - Verify leadSource = 'Google' in HubSpot
3. **Run Monitoring** - Run `php v2/scripts/hubspot/monitor-google-ads-attribution.php --days=7`
4. **Monitor Results** - Check for misattributed contacts weekly

## Key Changes

### determineLeadSourceFromContext() Enhancement

**Before:**

```php
// Only returned 'Google' if gclid AND utm_source='adwords'
if (!empty($gclid) && ($utm_source_lower === 'adwords' || $utm_source_lower === 'google')) {
    return 'Google';
}
```

**After:**

```php
// Prioritizes gclid - returns 'Google' immediately if gclid present
if (!empty($gclid)) {
    return 'Google'; // gclid is definitive proof
}

// Also checks hsa_src='g'
if ($hsa_src === 'g') {
    return 'Google';
}
```

### Google Ads Detection Order Fix

**Before:**

1. Extract UTM params
2. Call `determineLeadSourceFromContext()` (might return wrong value)
3. Google Ads detection (too late, wrong value already set)

**After:**

1. Extract UTM params
2. Google Ads detection FIRST (sets leadSource = 'Google' if indicators present)
3. Call `determineLeadSourceFromContext()` (refines but doesn't override correct Google Ads)

### Override Logic Addition

**Before:**

```php
if (empty($leadSource)) $leadSource = 'Google';
```

**After:**

```php
// Override wrong values when Google Ads indicators present
if (empty($leadSource) || !in_array($leadSource, ['Google', 'Paid Search'])) {
    $oldLeadSource = $leadSource;
    $leadSource = 'Google';
    if (!empty($oldLeadSource) && $oldLeadSource !== 'Google') {
        ordio_log('WARN', 'Overriding incorrect leadSource with Google Ads', [...]);
    }
}
```

## Monitoring

Run weekly monitoring:

```bash
php v2/scripts/hubspot/monitor-google-ads-attribution.php --days=7
```

This will:

- Check contacts from last 7 days
- Identify misattributed Google Ads leads
- Send alert email if issues found
- Generate JSON report

## Form Type Coverage

All form types now have consistent Google Ads attribution logic:

- ✅ **Main form on page** (`/v2/api/lead-capture.php`) - Fixed
- ✅ **Demo booking modal** (`html/form-hs.php`) - Enhanced with override logic
- ✅ **CTA buttons** (`lead-capture-popup` → `/v2/api/lead-capture.php`) - Fixed
- ⚠️ **HubSpot meeting booking widget** - Known limitation documented (see `MEETING_BOOKING_ATTRIBUTION.md`)

**Note**: CTA buttons open the lead-capture-popup modal, which uses `/v2/api/lead-capture.php`, so attribution works correctly for these flows. The meeting booking widget has iframe limitations that prevent automatic UTM parameter passing.

## Related Documentation

- `docs/systems/tracking/GOOGLE_ADS_ATTRIBUTION_AUDIT_2026-01.md` - Complete audit report
- `docs/systems/tracking/MEETING_BOOKING_ATTRIBUTION.md` - Meeting booking widget attribution guide
- `docs/development/ATTRIBUTION_DEBUGGING_GUIDE.md` - Troubleshooting guide
- `.cursor/rules/lead-capture.mdc` - Lead capture patterns
