# lead-capture Full Instructions

## Attribution Validation Requirements

**CRITICAL**: All lead capture submissions must have consistent attribution between `leadSource` and UTM parameters.

**Note**: This rule applies to all form types:

- Lead capture popup (`v2/api/lead-capture.php`)
- Demo booking modal (`html/form-hs.php`)
- Tools/calculator forms (`v2/api/collect-lead.php`)
- All other form endpoints

### Ordio Loop Affiliate Capture

**CRITICAL**: All forms MUST capture the `affiliate` param and send `affiliate_partner_id` to HubSpot for Ordio Loop commission attribution.

- **Extraction priority:** POST (affiliate_modal/affiliate) → cookie → page_url query param
- **HubSpot fields:** `affiliate_partner_id`, `affiliate_referral_date` (when affiliate present)
- **See:** `.cursor/rules/ordio-loop-forms.mdc`, `docs/systems/affiliate/FORM_REFERRAL_CAPTURE_AUDIT.md`

### Attribution Consistency Rules

1. **Direct Traffic**: When `utm_source='direct'` AND `utm_medium='direct'` with no referrer:
   - `leadSource` MUST be "Direct Traffic"
   - `source__c` MUST be "direct"
   - `utm_medium__c` MUST be "direct"

2. **Organic Search**: When `utm_medium='organic'` or `hs_analytics_source='ORGANIC_SEARCH'`:
   - `leadSource` MUST be "Organic Search"
   - `source__c` MUST be search engine domain (google, bing, etc.)
   - `utm_medium__c` MUST be "organic"

3. **Paid Search (Google Ads)**: When `gclid__c` is present or `utm_source='adwords'` or `hsa_src='g'`:
   - `leadSource` MUST be "Google" (NOT "Paid Search" - backend expects "Google")
   - `source__c` MUST be "adwords"
   - `utm_medium__c` MUST be "ppc" or "cpc"
   - `utm_campaign__c` SHOULD be populated with campaign name from URL if available
   - Campaign names with underscores/hyphens (e.g., "DE_Search_B_Brand_Kombi") are valid and should NOT be filtered
   - Campaign name extraction priority: form submission URL > first URL > last URL
   - `utm_content__c` is optional and may remain empty if not tracking ad variations
   - **CRITICAL**: `gclid` detection MUST be prioritized - if `gclid` is present, leadSource MUST be "Google" regardless of other parameters
   - **CRITICAL**: `hsa_src='g'` parameter also indicates Google Ads - should set leadSource to "Google"
   - **CRITICAL**: Google Ads detection MUST happen BEFORE `determineLeadSourceFromContext()` to prevent wrong values from persisting
   - **CRITICAL**: Wrong leadSource values (Direct Traffic, Organic Search) MUST be overridden when Google Ads indicators present

4. **Referral**: When `utm_medium='referral'` or external referrer:
   - `leadSource` MUST be "referral"
   - `source__c` MUST be referrer domain (sanitized)
   - `utm_medium__c` MUST be "referral"

### Validation Checklist

Before deploying lead capture changes:

- [ ] Test attribution logic with `php v2/scripts/hubspot/test-google-ads-attribution.php`
- [ ] Verify `determineLeadSourceFromContext()` prioritizes `gclid` detection
- [ ] Verify Google Ads detection happens BEFORE `determineLeadSourceFromContext()` in form endpoints
- [ ] Test that `gclid` extraction from pageUrl works correctly
- [ ] Test that `hsa_src='g'` detection works correctly
- [ ] Verify wrong leadSource values are overridden when Google Ads indicators present
- [ ] Verify `ordio_resolve_attribution()` handles all traffic types correctly
- [ ] Check that UTM sanitization works for edge cases (Android intents, package IDs)
- [ ] Verify campaign name filtering allows underscores/hyphens (e.g., "DE_Search_B_Brand_Kombi")
- [ ] Ensure retro fix script can correct attribution mismatches and extract campaign names from URLs
- [ ] Test that Google Ads campaign names are preserved (not filtered as technical IDs)
- [ ] Verify retro fix script checks form submission URLs as fallback to first URL
- [ ] Test UTM parameter extraction from multiple URL sources (form URL > first URL > last URL)
- [ ] Verify frontend uses 'Google' (not 'Paid Search') for Google Ads attribution
- [ ] Test form-hs.php attribution logic with `php v2/scripts/hubspot/test-form-attribution-scenarios.php`
- [ ] Verify form-hs.php overrides incorrect leadSource values when Google Ads indicators present
- [ ] Verify form-hs.php extracts hsa_src from page_url_modal parameter correctly
- [ ] Test all form types with `php v2/scripts/hubspot/test-all-form-attribution.php`
- [ ] Document any new attribution patterns in `docs/development/ATTRIBUTION_DEBUGGING_GUIDE.md`

### Direct Traffic Attribution

**CRITICAL:** Prevention fixes implemented November 17, 2025. See `docs/ATTRIBUTION_PREVENTION_FIXES.md` for details.

### Original Attribution Preservation

- JavaScript stores original attribution (referrer + UTM) in localStorage on first visit
- Original attribution preserved during internal navigation
- Forms restore original attribution when submitting after internal navigation
- Server-side trusts original attribution when `original_attribution_used` flag is present

### Internal Domain Referrer Handling

- Internal referrers no longer default to Direct Traffic
- Original attribution used when available
- Only defaults to Direct Traffic if truly no attribution data exists

**Internal Domain Referrers:**

- When referrer is from ordio.com/subdomain, check `hs_analytics_source` for original attribution
- Don't default to Direct Traffic if analytics source shows ORGANIC_SEARCH, REFERRALS, etc.
- Retro fix script handles this automatically

**Monitoring:**

- Run `php scripts/hubspot/monitor-direct-traffic.php [days]` to check for misattribution
- Audit direct traffic contacts monthly to catch misattribution early
- Flag contacts where `hs_analytics_source` != DIRECT_TRAFFIC but leadSource = Direct Traffic

### Google Ads Attribution Requirements

**CRITICAL**: Google Ads attribution must be prioritized and cannot be overridden by other logic.

**Detection Priority:**

1. **gclid parameter** - Most reliable indicator, MUST set leadSource to "Google" if present
2. **hsa_src='g' parameter** - Google Ads indicator, MUST set leadSource to "Google" if present
3. **utm_source='adwords' with utm_medium='ppc'/'cpc'** - Google Ads indicator

**Implementation Requirements:**

- `determineLeadSourceFromContext()` MUST check `gclid` FIRST, before any other checks
- Google Ads detection MUST happen BEFORE `determineLeadSourceFromContext()` in form endpoints
- Wrong leadSource values (Direct Traffic, Organic Search) MUST be overridden when Google Ads indicators present
- `gclid` MUST be extracted from pageUrl if not in cookies/parameters
- `hsa_src='g'` MUST be extracted from pageUrl if not in cookies/parameters
- Frontend MUST use 'Google' (not 'Paid Search') for Google Ads attribution
- Enhanced logging MUST warn when overriding incorrect leadSource values

**Files:**

- `v2/config/utm-validation.php` - `determineLeadSourceFromContext()` function
- `v2/api/lead-capture.php` - Google Ads detection (Step 1 & Step 2)
- `v2/api/collect-lead.php` - Google Ads detection
- `v2/js/utm-tracking.js` - Frontend UTM tracking

**Testing:**

- Run `php v2/scripts/hubspot/test-google-ads-attribution.php` to verify attribution logic
- Test form submissions on `/gastro` and `/schichtbetriebe` with Google Ads parameters
- Verify attribution in HubSpot after submission

**See Also:**

- `docs/systems/tracking/GOOGLE_ADS_ATTRIBUTION_AUDIT_2026-01.md` - Complete audit report
- `docs/development/ATTRIBUTION_DEBUGGING_GUIDE.md` - Troubleshooting guide

### Debugging Attribution Issues

1. Run audit: `php v2/scripts/hubspot/google-ads-attribution-audit.php <contact_id>`
2. Analyze: `php v2/scripts/hubspot/analyze-google-ads-attribution.php <audit-json>`
3. Test logic: `php v2/scripts/hubspot/test-google-ads-attribution.php`
4. Apply fix: `php v2/scripts/hubspot/patch-leadsource-from-audit.php --input=signed-off.csv` then `--apply` (see `docs/systems/hubspot/HUBSPOT_LEADSOURCE_ATTRIBUTION_POLICY.md`)
5. Verify: Re-run audit to confirm attribution is consistent

See `docs/development/ATTRIBUTION_DEBUGGING_GUIDE.md` for detailed troubleshooting steps.

## Partner Attribution

### Partner Value Mapping

**CRITICAL**: Partner slugs from URL parameters must be mapped to HubSpot-accepted values before sending to HubSpot.

**Requirements:**

- Partner `partner__c` field in HubSpot is an enumeration (dropdown) with specific accepted values
- Partner slugs (e.g., `gastroberatung`) must be mapped to HubSpot values (e.g., `Gastro Beratung`)
- Mapping is handled by `v2/config/partner-hubspot-mapping.php`
- All API endpoints that send `partner__c` must use `mapPartnerToHubSpotValue()` function

**Implementation Pattern:**

```php
// Include mapping helper
require_once __DIR__ . '/../config/partner-hubspot-mapping.php';

// Extract partner slug
$partnerSlug = $input['partner'] ?? ($_COOKIE['partner'] ?? '');

// Map to HubSpot value
$partner = mapPartnerToHubSpotValue($partnerSlug);

// Log mapping transformation
if (!empty($partnerSlug) && empty($partner)) {
    ordio_log('WARN', 'Partner slug has no HubSpot mapping', [
        'partner_slug' => $partnerSlug,
        'endpoint' => 'endpoint-name'
    ]);
} elseif (!empty($partnerSlug) && $partnerSlug !== $partner) {
    ordio_log('INFO', 'Partner slug mapped to HubSpot value', [
        'partner_slug' => $partnerSlug,
        'hubspot_value' => $partner,
        'endpoint' => 'endpoint-name'
    ]);
}

// Send mapped value to HubSpot
[
    "name" => "partner__c",
    "value" => $partner  // Use mapped value, not slug
]
```

**Testing:**

- Run test script: `php v2/scripts/hubspot/test-partner-attribution.php [partner-slug]`
- Run sync script: `php v2/scripts/hubspot/sync-partner-values.php --dry-run`
- Verify HubSpot contact has correct `partner__c` value after form submission

**See Also:**

- `docs/systems/partner-pages/HUBSPOT_INTEGRATION.md` - Complete HubSpot integration guide
- `docs/development/ATTRIBUTION_DEBUGGING_GUIDE.md` - Partner attribution troubleshooting

### Modal Field Handling (`_modal` Fields)

**CRITICAL**: `_modal` fields (e.g., `utm_source_modal`, `partner_modal`, `page_url_modal`) are for PHP extraction only and MUST NOT be sent to HubSpot as Contact properties.

**Architecture:**

1. **Hidden Inputs** (`v2/base/include_form-hs.php` lines 389-399)
   - JavaScript populates `_modal` fields with UTM/partner data
   - These fields are needed for PHP extraction

2. **PHP Extraction** (`html/form-hs.php` lines 322-332)
   - PHP extracts values from `_modal` fields
   - Values are processed and mapped to correct Contact properties

3. **HubSpot Submission** (`html/form-hs.php` fields array)
   - **DO NOT** send `_modal` fields to HubSpot (they're not Contact properties)
   - **DO** send correct Contact properties (`source__c`, `utm_medium__c`, `partner__c`, etc.)
   - **DO** send context fields (`pageUri`, `pageName`, `hutk`, `ipAddress`)

**Invalid Fields (DO NOT SEND):**

- `utm_source_modal`, `utm_medium_modal`, `utm_campaign_modal`, `utm_term_modal`, `utm_content_modal`
- `gclid_modal`, `leadSource_modal`, `signuptype_modal`
- `page_url_modal`, `referrer_modal`, `partner_modal`

**Correct Contact Properties (DO SEND):**

- `source__c` (from `utm_source_modal`)
- `utm_medium__c` (from `utm_medium_modal`)
- `utm_campaign__c` (from `utm_campaign_modal`)
- `utm_term__c` (from `utm_term_modal`)
- `content__c` (from `utm_content_modal`)
- `gclid__c` (from `gclid_modal`)
- `sign_up_type__c` (from `signuptype_modal`)
- `partner__c` (mapped from `partner_modal` using `mapPartnerToHubSpotValue()`)
- `leadsource` (from `leadSource_modal`)

**Context Fields (DO SEND):**

- `pageUri` (from `page_url_modal`)
- `pageName` (derived from `page_url_modal`)
- `hutk` (from cookie or input)
- `ipAddress` (from `$_SERVER['REMOTE_ADDR']`)

**Implementation Pattern:**

```php
// Extract from _modal fields (for PHP processing)
$utm_source = trim($_POST['utm_source_modal'] ?? '');
$partnerSlug = trim($_POST['partner_modal'] ?? '');

// Map to correct Contact properties
$partner = mapPartnerToHubSpotValue($partnerSlug);

// Send correct Contact properties to HubSpot (NOT _modal fields)
[
    "name" => "source__c",
    "value" => $utm_source
],
[
    "name" => "partner__c",
    "value" => $partner  // Mapped value, not slug
]
```

## HubSpot API Integration

### Standardized API Helpers

**All HubSpot API endpoints now use standardized helper functions** (migrated 2025-11-17):

- `v2/config/hubspot-api-helpers.php` provides:
  - `makeHubSpotAPICall()` - Standardized API calls with retry logic and rate limit handling
  - `createHubSpotSuccessResponse()` - Standardized success responses
  - `createHubSpotErrorResponse()` - Standardized error responses

**Benefits:**

- Automatic retry logic with exponential backoff (3 attempts: 1s → 2s → 4s)
- Rate limit handling with `Retry-After` header parsing (429 responses)
- Consistent error handling and logging across all endpoints
- Backward compatibility maintained (old response fields preserved)

**Migration Status:**

- ✅ `lead-capture.php` - All 4 functions migrated (Forms API, CRM API, Events API)
- ✅ All 9 HubSpot API endpoints migrated

**When modifying HubSpot API calls:**

- Always use `makeHubSpotAPICall()` instead of manual cURL
- Use `createHubSpotSuccessResponse()` and `createHubSpotErrorResponse()` for responses
- Maintain backward compatibility by including old response fields
- See `scripts/hubspot/STANDARDIZED_API_HELPERS.md` for usage examples

## GA4/GTM Tracking

Lead capture popup form submissions use `GTMFormTracker.trackAPIForm('lead-capture.php', { conversionType: 'lead_capture_popup', ... })`. See `analytics-tracking.mdc` and `docs/systems/analytics/GA4_EVENT_NAMING.md` for conversion_type requirements.

## Lead Capture System Overview

The lead capture system is a two-step progressive form popup that collects lead information and syncs to HubSpot CRM and Google Sheets. It consists of five main components:

1. **Popup Component** (`v2/components/lead-capture-popup.php`) - User-facing popup with two-step form
2. **API Endpoint** (`v2/api/lead-capture.php`) - Backend processing for form submissions
3. **Trigger System** (`v2/js/lead-capture-triggers.js`) - Controls when popup appears
4. **Copy Management** (`v2/components/lead-capture-copy-detector.php` + `v2/data/lead_capture_copy.php`) - Dynamic copy based on page type
5. **Page Integration** - Include statements across 100+ pages

**Blocking overlays:** `v2/js/ordio-lead-capture-blocking-registry.js` (in `head.php`) coordinates automatic trigger pausing when other modals are open, sets `body[data-ordio-blocking-overlay]`, and (with CSS in `head.php`) hides the HubSpot chat container while any registered overlay is active. See `docs/systems/lead-capture/TRIGGER_CONFIGURATION.md` (Blocking overlays, HubSpot chat) and `.cursor/rules/lead-gen-forms-ux.mdc`.

## Adding Popup to New Page

### Required Includes

Always include both component and trigger script:

```php
<?php include '../components/lead-capture-popup.php'; ?>
<script src="/v2/js/lead-capture-triggers.js"></script>
```

**Path Notes:**

- From `v2/pages/`: Use `../components/lead-capture-popup.php`
- From `v2/start.php`: Use `./components/lead-capture-popup.php`
- From root: Use `v2/components/lead-capture-popup.php`

### Manual Triggers

Add manual trigger buttons for specific CTAs:

```html
<button
  onclick="if(window.leadCapturePopup) { window.leadCapturePopup.show('manual-callback'); }"
>
  Rückruf anfordern
</button>
```

**Trigger Types:**

- `'manual-callback'`: Bypasses submission restrictions (allows resubmission)
- `'manual'`: Standard manual trigger (respects submission restrictions)

## Copy Management

**Step 1 primary CTA** (button text) is **global** in `v2/components/lead-capture-popup.php`. `lead_capture_copy.php` supplies only **headline** and **description** for Step 1. **Fast callback / Fonio:** see [FONIO_CALLBACK_COPY.md](../../docs/systems/lead-capture/FONIO_CALLBACK_COPY.md). **Descriptions** stay benefit-led (no timing stack); **headline** / global **CTA** may carry immediacy.

### Adding New Copy Pattern

1. Edit `v2/data/lead_capture_copy.php`:

```php
'my_page' => [
    'urls' => ['/my-page', 'my_page.php'],
    'headline' => 'Hast du Fragen zu [Topic]?',
    'description' => 'Wir helfen dir gerne, die beste Lösung zu finden – kostenlos und unverbindlich.',
    'funnel_stage' => 'MOF' // TOF, MOF, or BOF
],
```

2. (Optional) Add to quick lookup in `lead-capture-copy-detector.php`:

```php
'/my-page' => 'my_page',
```

### Copy Best Practices

**Headlines:**

- Keep it short (5-10 words)
- Use question format: "Hast du Fragen zu...?"
  See `.cursor/rules/shared-patterns.mdc` for universal copy guidelines (du tone, benefit-driven copy).

**Lead Capture-Specific:**

- Include benefit in copy

**Descriptions:**

- Keep it concise (1-2 sentences)
- Lead with benefit
- Include CTA: "kostenlos und unverbindlich"
- Use du tone

**Funnel Stages:**

- **TOF:** Tools pages, blog posts
- **MOF:** Industry pages, templates, downloads
- **BOF:** Pricing, comparison, product pages

**Copy Quality (Blog Posts):** For blog post lead capture copy, see `lead-capture-copy.mdc` and [LEAD_CAPTURE_COPY_BEST_PRACTICES.md](../../docs/systems/lead-capture/LEAD_CAPTURE_COPY_BEST_PRACTICES.md). Never use "dir bei diesem Thema hilft"; use topic-specific, benefit-led copy. **Callback framing:** Every description must indicate callback (Rückruf, zurückrufen, anrufen, Beratung). **Grammar:** Use main-clause word order; no verb-at-end.

## Trigger Configuration

### Default Triggers

The system automatically configures triggers based on page priority:

- **High Priority:** 30s delay, 25-40% scroll, 5s exit intent
- **Medium Priority:** 30s delay, 40% scroll, 8s exit intent
- **Low Priority:** 60s delay, 40% scroll, 10s exit intent (scheduled only where standard triggers run)
- **Blog Posts:** 30s delay, 35% scroll, 15s exit intent
- **`/tools` paths:** No automatic time/scroll/exit-intent — `isToolsPath()` in `lead-capture-triggers.js` (`/^\/tools(\/|$)/`) returns early from `setupTriggers()`. Popup still loads; use `manual-callback` / footer CTA. Canonical doc: `docs/systems/lead-capture/TRIGGER_CONFIGURATION.md` (Page Exclusions).

### Custom Trigger Configuration

```javascript
// After page load
if (window.leadCaptureTriggers) {
  // Remove default trigger
  window.leadCaptureTriggers.triggers.delete("time");

  // Add custom trigger
  window.leadCaptureTriggers.addTrigger("time", {
    condition: () => !window.leadCaptureTriggers.hasShown,
    delay: 45000, // 45 seconds
    once: true,
  });
}
```

## API Endpoint Patterns

### Two-Step Flow

**Step 1:** Creates lead in HubSpot (with temporary email) → Creates row in Google Sheets
**Step 2:** Updates HubSpot contact (replaces temp email with real email) → Updates Google Sheets row

### HubSpot Integration

**Forms API v3 (Preferred):**

- Used for Step 1 (preserves activity history)
- Uses `hubspotutk` cookie (hutk) for contact identification
- Form GUID: `9f9d4e35-d8d9-4283-93b6-1a789e0a1281`

**CRM API v3 (Fallback/Update):**

- Fallback for Step 1 if Forms API fails
- Required for Step 2 (updates existing contact)

**Temporary Email Pattern:**

- Step 1: `lead-{leadId}@temp.ordio.com`
- Step 2: Replaced with real email via CRM API

**CRITICAL - Step 2 Contact Lookup:**

- Step 2 must find the contact created in Step 1, NOT a pre-existing contact with the same phone
- Step 2 may auto-merge duplicates when same phone is detected (Step 1 contact + pre-existing contact); see DUPLICATE_CONTACT_PREVENTION.md
- Lookup order: `findContactByTempEmail()` first (unambiguous), then `findContactByPhonePreferringTempEmail()` as fallback
- Never use `checkExistingContact($phone, $tempEmail)` for Step 2 – it uses OR logic and returns `results[0]`, which can be the wrong contact when multiple share the same phone
- See `docs/systems/lead-capture/DUPLICATE_CONTACT_PREVENTION.md` for details

### Google Sheets Integration

**Spreadsheet ID:** `1gHzf0CcCACPPLo3Xb4aBcO9cguraVa7eeLyYZvqCBAk`

**Column Structure:**

- A: Timestamp
- B: Name
- C: Phone
- D: Email
- E: Notes
- F: Call Preference
- G: Status
- H: Source Page
- I: Lead Source
- J: Lead ID
- K: Trigger Type
- L: Source Page Label
- M: Page Context

**Authentication:** JWT via service account (`ordio-webinar-sheets@ordio-472310.iam.gserviceaccount.com`)

## Error Handling

### Frontend Errors

- **Validation:** Real-time phone validation, email format check
- **Network:** 15s timeout, retry logic, user-friendly error messages
- **API Errors:** Display error from API response

### Backend Errors

- **Validation:** Return 400 with specific error message
- **HubSpot Failures:** Log error, continue with Sheets (fallback)
- **Sheets Failures:** Log error, continue with HubSpot (fallback)
- **Both Failures:** Send email notification, log to file

### Logging

- **Frontend:** Console warnings for UTM tracker issues
- **Backend:** `error_log()` for all operations
- **Log Files:** `v2/logs/lead-capture.log`, `v2/logs/lead-capture-debug.log`

## Session Management

### Submission Tracking

- `sessionStorage`: `lead_capture_submitted`, `lead_capture_permanent`
- `localStorage`: `lead_capture_submitted`, `lead_capture_submitted_expires` (30 days)
- Prevents form resubmission for 30 days

### Page State

- `sessionStorage`: `lead_capture_shown`, `lead_capture_page`
- Prevents multiple popups per page
- Resets on page navigation

## UTM Tracking

### Frontend

- Uses `window.utmTracker.getAllUTMData()` (centralized tracker)
- Fallback to `window.utmTracking` or URL params
- Validates current UTM data (prevents stale cookie submission)

### Backend

- Receives full UTM data from frontend
- Prioritizes frontend data over cookies
- Tracks: utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid

### Lead Source Detection

- Paid Search (gclid or cpc/ppc medium)
- Organic Search (organic medium or search referrer)
- Meta (fb/facebook/instagram source)
- LinkedIn (linkedin source/medium)
- Social (tiktok/twitter/youtube/x source)
- Email Marketing (email medium)
- Referral (referral medium or external referrer)
- Direct Traffic (default)

## Validation Requirements

### Step 1

- Name: Required, non-empty
- Phone: Required, valid format (`/^\+?[0-9]{3,20}$/`)

### Step 2

- Lead ID: Required (from Step 1)
- Email: Optional, valid format if provided
- Notes: Optional
- Call Preference: Optional

### Phone Normalization

- Normalize to E.164 format
- Handle German numbers (0 prefix → +49)
- Handle international format (00 prefix → +)
- Prevent duplicate contacts

## Testing Requirements

### Pre-Deployment Checklist

- [ ] Popup component included
- [ ] Trigger script included
- [ ] Copy detection works
- [ ] Triggers work (time, scroll, exit-intent)
- [ ] Form submission works (Step 1 → Step 2 → Success)
- [ ] HubSpot sync verified
- [ ] Google Sheets sync verified
- [ ] Mobile responsiveness tested
- [ ] Accessibility tested

### Debugging Commands

```javascript
// Browser console
window.leadCapturePopup?.show("manual");
window.resetLeadCapture();
console.log(window.leadCaptureTriggers?.hasShown);
```

```bash
# Server logs
tail -f v2/logs/lead-capture-debug.log
grep -i "error" v2/logs/lead-capture-debug.log
```

## Common Pitfalls

### Missing Includes

❌ **BAD:** Only including popup component without trigger script

✅ **GOOD:** Include both component and trigger script

### Wrong Copy Pattern

❌ **BAD:** Copy doesn't match page type

✅ **GOOD:** Add custom copy pattern or verify URL matches existing pattern

### Trigger Not Firing

❌ **BAD:** Popup never appears

✅ **GOOD:** Check session storage, verify triggers configured, test manually

### HubSpot Sync Issues

❌ **BAD:** Contact not created in HubSpot

✅ **GOOD:** Check API token, verify form GUID, test connectivity (`?debug_hubspot=test`)

### Google Sheets Sync Issues

❌ **BAD:** Row not created in Google Sheets

✅ **GOOD:** Check credentials, verify spreadsheet ID, check service account permissions

## Reference Documentation

- `docs/systems/lead-capture/ARCHITECTURE.md` - System architecture
- `docs/systems/lead-capture/DUPLICATE_CONTACT_PREVENTION.md` - Duplicate contact root cause, fix, manual merge
- `docs/systems/lead-capture/INTEGRATION_GUIDE.md` - Adding popup to pages
- `docs/systems/lead-capture/TRIGGER_CONFIGURATION.md` - Customizing triggers
- `docs/systems/lead-capture/COPY_MANAGEMENT.md` - Managing copy
- `docs/systems/lead-capture/TROUBLESHOOTING.md` - Common issues
- `docs/systems/lead-capture/TESTING_CHECKLIST.md` - Testing procedures
- `docs/systems/lead-capture/HUBSPOT_WORKFLOW.md` - HubSpot integration
- `docs/systems/lead-capture/GOOGLE_SHEETS_WORKFLOW.md` - Google Sheets integration
- `docs/systems/lead-capture/QUICK_REFERENCE.md` - Quick reference

## Related Documentation

See [docs/ai/RULE_TO_DOC_MAPPING.md](../../docs/ai/RULE_TO_DOC_MAPPING.md) for complete mapping.

**Key Documentation:**

- [Lead Capture Component](../../docs/systems/shared-components/LEAD_CAPTURE_COMPONENT.md) - Complete component documentation
- [Component Usage Guide](../../docs/systems/shared-components/COMPONENT_USAGE_GUIDE.md) - Integration patterns and examples
- [Lead Capture System](../../docs/systems/lead-capture/README.md) - System overview and index
- [Lead Capture Architecture](../../docs/systems/lead-capture/ARCHITECTURE.md) - System architecture
- [Lead Capture Integration Guide](../../docs/systems/lead-capture/INTEGRATION_GUIDE.md) - Integration patterns
- [Form Configuration Reference](../../docs/systems/forms/FORM_CONFIGURATION_REFERENCE.md) - Form field mappings
- [HubSpot API Reference](../../docs/systems/apis/HUBSPOT_API_REFERENCE.md) - API endpoint documentation
