# UTM Tracking Debugging Guide

**Last Updated:** 2026-01-29

Complete guide for debugging UTM parameter tracking issues on Ordio landing pages.

## Quick Start

### Enable Debug Mode

Add `?utm_debug=true` to any URL to enable detailed console logging:

```
https://www.ordio.com/schichtbetriebe?utm_source=test&utm_campaign=test&utm_debug=true
```

Debug mode enables:

- Console logging of all UTM tracking events
- Cookie setting/reading logs
- URL cleanup logs
- Form submission tracking logs

## Understanding the UTM Tracking Flow

### 1. Parameter Extraction (Page Load)

When a user visits a URL with UTM parameters:

1. **URL Parameters Read** → `extractUTMParameters()`
   - Reads `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`
   - Reads `hsa_*` parameters (Google Ads conversion tracking)
   - Reads `gclid` (Google Click ID)
   - Reads `gad_source`, `gbraid` (Google Ads additional tracking)

2. **Cookies Set** → `setUTMCookies()`
   - Stores all UTM parameters in cookies (90-day expiration)
   - Stores `hsa_*` parameters in cookies
   - Stores `gclid`, `leadSource`, `partner` in cookies
   - Also stores in `localStorage` as fallback

3. **URL Cleanup** → `cleanUTMParametersFromURL()` (after analytics ready)
   - IMPROVED: Waits for analytics scripts to be ready (GTM, HubSpot)
   - Removes UTM parameters from URL (prevents link sharing misattribution)
   - Removes `gclid` from URL
   - **Preserves `hsa_*` parameters** (needed for Google Ads conversion tracking)
   - **Preserves `gad_source`, `gbraid`** (Google Ads tracking)
   - Dispatches `utmCleanupComplete` event for monitoring
   - Sends events to dataLayer for analytics tracking

### 2. Form Submission

When a user submits a form:

1. **Form Reads from Cookies** → `getUTMCookies()`
   - Reads UTM parameters from cookies
   - Reads `hsa_*` parameters from cookies
   - Falls back to `localStorage` if cookies unavailable

2. **Data Sent to HubSpot** → Form submission includes:
   - All UTM parameters
   - All `hsa_*` parameters
   - `gclid` (if present)
   - `leadSource`, `partner`, `signuptype`

## Debugging Checklist

### Issue: UTMs Not Appearing in URL

**Expected Behavior:** UTMs are cleaned from URL after analytics scripts are ready (typically 1.5-3 seconds, intentional).

**Check:**

1. Open browser console with `?utm_debug=true`
2. Look for "UTM parameters cleaned from URL" log
3. Check for `utmCleanupComplete` event in console
4. Verify cookies are set: `document.cookie` in console
5. Check localStorage: `localStorage.getItem('ordio_utm_data')`
6. Monitor cleanup events: Check dataLayer for `utm_cleanup_complete` events

**Solution:** This is correct behavior. UTMs are stored in cookies/instance variables, not URL.

**Feature Flag:** Cleanup can be disabled for testing:
```javascript
localStorage.setItem('utmCleanupEnabled', 'false'); // Disable
localStorage.setItem('utmCleanupEnabled', 'true');  // Enable
```

### Issue: Cookies Not Set

**Check:**

1. Open browser console with `?utm_debug=true`
2. Look for cookie setting logs
3. Check browser cookie settings (third-party cookies blocked?)
4. Verify domain: Cookies should be set for `.ordio.com`
5. Check SameSite attribute (should be `None` for HTTPS, `Lax` otherwise)

**Common Causes:**

- Third-party cookies blocked
- Private/Incognito mode (may block cookies)
- Browser security settings
- Domain mismatch

**Solution:**

- Check `localStorage` fallback: `localStorage.getItem('ordio_utm_data')`
- Verify cookie domain is `.ordio.com`
- Check browser console for cookie errors

### Issue: Cleanup Works on Some Pages But Not Others

**Symptoms:**

- UTMs are cleaned from URL on some pages (e.g., `/gastro`, `/schichtbetriebe`)
- UTMs are NOT cleaned from URL on other pages (e.g., `/v3`)
- Tracking works on pages where cleanup fails, but fails on pages where cleanup works

**Root Cause:**
Cleanup was checking URL parameters at setup time but not re-checking when cleanup actually runs. If URL was modified between setup and cleanup, cleanup would fail silently.

**Check:**

1. Enable debug mode: Add `?utm_debug=true` to URL
2. Check console for cleanup logs:
   - "UTM parameters cleaned from URL" - cleanup succeeded
   - "Cleanup skipped - UTM parameters no longer in URL" - cleanup skipped (expected if params removed)
   - "Failed to update URL via replaceState" - cleanup failed due to browser security
   - No cleanup log - cleanup condition not met or script error
3. Verify `window.utmTracker` exists: `typeof window.utmTracker`
4. Check cleanup event: Listen for `utmCleanupComplete` event
5. Use test script: `v2/scripts/dev-helpers/test-cleanup-behavior.php`

**Solution:**

- Fixed in `v2/js/utm-tracking.js` - cleanup now re-checks URL parameters at execution time
- Enhanced error handling for `history.replaceState()` failures
- See `docs/development/UTM_CLEANUP_DISCREPANCY_FIX.md` for details

### Issue: Forms Not Reading UTM Data

**Check:**

1. Verify cookies exist: `document.cookie` in console
2. Check form JavaScript: Look for `window.utmTracker.getUTMDataForAPI()`
3. Verify form includes UTM hidden fields
4. Check Network tab: Form submission should include UTM parameters
5. **Important:** Forms should read from `window.utmTracker.getUTMDataForAPI()` which uses:
   - Instance variables (persist after URL cleanup)
   - Cookies (90-day expiration)
   - localStorage (fallback)
   - URL parameters (last resort, only if above fail)

**Common Causes:**

- Cookies expired (90-day expiration)
- Form JavaScript error
- UTM tracker not initialized

**Solution:**

- Enable debug mode: `?utm_debug=true`
- Check console for errors
- Verify `window.utmTracker` exists
- Test form submission and check Network tab

### Issue: hsa\_\* Parameters Missing

**Expected Behavior:** `hsa_*` parameters are preserved in URL (not cleaned).

**Check:**

1. Verify `hsa_*` parameters in original URL
2. Check cookies: `document.cookie` should include `hsa_*` cookies
3. Verify URL after cleanup: `hsa_*` should still be present

**Common Causes:**

- Parameters not in original URL
- Cookie setting failed
- Browser cleared cookies

**Solution:**

- Verify Google Ads Tracking Template includes `hsa_*` parameters
- Check cookies: `document.cookie.match(/hsa_/g)`
- Verify `localStorage`: `localStorage.getItem('ordio_utm_data')`

## Browser Console Commands

### Check UTM Tracker

```javascript
// Check if tracker exists
typeof window.utmTracker;

// Get all UTM data
window.utmTracker.getAllUTMData();

// Get cookies
window.utmTracker.getUTMCookies();

// Get specific cookie
window.utmTracker.getCookie("utm_source");
```

### Check Cookies

```javascript
// View all cookies
document.cookie;

// Get specific cookie
document.cookie.match(/utm_source=([^;]+)/);

// Check hsa_* cookies
document.cookie.match(/hsa_/g);

// Parse all cookies
document.cookie.split(";").reduce((acc, cookie) => {
  const [key, value] = cookie.trim().split("=");
  acc[key] = decodeURIComponent(value);
  return acc;
}, {});
```

### Check localStorage

```javascript
// Get UTM data from localStorage
JSON.parse(localStorage.getItem("ordio_utm_data"));

// Check data age
const data = JSON.parse(localStorage.getItem("ordio_utm_data"));
const age = Date.now() - (data.timestamp || 0);
const ageInDays = Math.floor(age / (24 * 60 * 60 * 1000));
console.log(`Data age: ${ageInDays} days`);
```

### Test Form Submission

```javascript
// Get UTM data for form
window.utmTracker.getUTMDataForAPI();

// Simulate form submission
const form = document.querySelector("form");
const formData = new FormData(form);
const utmData = window.utmTracker.getUTMDataForAPI();
Object.keys(utmData).forEach((key) => {
  formData.append(key, utmData[key]);
});
console.log("Form data with UTMs:", Object.fromEntries(formData));
```

## Testing Tools

### Test Scripts

1. **Basic Test:** `/v2/scripts/dev-helpers/test-utm-tracking.php`
   - Simple test page with URL parameter testing
   - Cookie verification
   - localStorage check

2. **Comprehensive Test:** `/v2/scripts/dev-helpers/test-utm-tracking-comprehensive.php`
   - Full test suite with 10+ test cases
   - Detailed results and summary
   - All aspects of UTM tracking

### Test URLs

Use these test URLs to verify tracking:

```
# UTMs Only
/test-utm-tracking.php?utm_source=google&utm_medium=ppc&utm_campaign=test

# hsa_* Only
/test-utm-tracking.php?hsa_acc=1887350035&hsa_cam=20035390960&hsa_src=g

# Full Google Ads URL
/test-utm-tracking.php?utm_source=adwords&utm_medium=ppc&utm_campaign=test&hsa_acc=1887350035&hsa_cam=20035390960&gclid=test123&utm_debug=true
```

## Common Issues & Solutions

### Issue: URL Cleaned Too Early

**Symptom:** UTMs disappear from URL before tracking scripts can read them.

**Solution:** Cleanup delay increased to 1.5 seconds (was 1 second). This ensures:

- All tracking scripts have loaded
- Cookies are set
- Analytics pixels have fired

### Issue: Cookies Not Persisting

**Symptom:** Cookies disappear after page reload or session ends.

**Check:**

- Cookie expiration: Should be 90 days
- Domain attribute: Should be `.ordio.com`
- SameSite attribute: Should be `None` for HTTPS
- Secure flag: Should be present for HTTPS

**Solution:**

- Verify cookie attributes in browser DevTools → Application → Cookies
- Check `localStorage` fallback
- Test cross-subdomain cookie sharing

### Issue: Forms Not Sending UTM Data

**Symptom:** Form submissions don't include UTM parameters in HubSpot.

**Check:**

1. Form JavaScript includes UTM reading code
2. Cookies exist when form is submitted
3. Network request includes UTM parameters
4. HubSpot contact record has UTM fields populated

**Solution:**

- Enable debug mode: `?utm_debug=true`
- Check form submission in Network tab
- Verify HubSpot form configuration
- Test with test form submission

### Issue: hsa\_\* Parameters Not Preserved

**Symptom:** `hsa_*` parameters disappear from URL.

**Expected:** `hsa_*` parameters should be preserved in URL (not cleaned).

**Check:**

1. Verify `hsa_*` in original URL
2. Check URL after cleanup (should still have `hsa_*`)
3. Verify cookies include `hsa_*` values

**Solution:**

- `hsa_*` parameters are intentionally preserved
- If missing, check Google Ads Tracking Template
- Verify cookies are set correctly

## Monitoring & Logging

### Debug Mode Logging

When `?utm_debug=true` is enabled, console logs include:

- `UTM Tracker initialized` - Tracker setup complete
- `UTM parameters extracted` - Parameters read from URL
- `UTM cookies set` - Cookies stored
- `UTM parameters cleaned from URL` - Cleanup executed
- `Form submission with UTM data` - Form includes UTMs

### Event Listeners

Listen for UTM tracking events:

```javascript
// Cleanup complete event
window.addEventListener("utmCleanupComplete", (e) => {
  console.log("Cleanup completed:", e.detail);
});

// Form submission event (if implemented)
window.addEventListener("utmFormSubmit", (e) => {
  console.log("Form submitted with UTMs:", e.detail);
});
```

## Best Practices

1. **Always Test with Debug Mode**
   - Add `?utm_debug=true` to test URLs
   - Check console for detailed logs
   - Verify each step of the tracking flow

2. **Verify Cookies Before Form Submission**
   - Check cookies exist: `document.cookie`
   - Verify cookie expiration (90 days)
   - Test localStorage fallback

3. **Test Cross-Page Tracking**
   - Visit page with UTMs
   - Navigate to another page
   - Verify cookies persist
   - Submit form on second page

4. **Monitor HubSpot Contact Records**
   - Submit test form
   - Check HubSpot contact record
   - Verify UTM fields populated
   - Verify `hsa_*` parameters present

## Related Documentation

- [UTM Tracking System](../../systems/shared-components/UTM_TRACKING_SYSTEM.md)
- [Canonical Tags & Tracking Preservation](../../seo/CANONICAL_TAGS_TRACKING_PRESERVATION.md)
- [Google Ads UTM Fix](../google-ads/UTM_PARAMETER_FIX_SCHICHTBETRIEBE.md)

## Support

If issues persist:

1. Enable debug mode: `?utm_debug=true`
2. Collect console logs
3. Check cookies and localStorage
4. Test with comprehensive test script
5. Review HubSpot contact records
6. Contact development team with findings
