# Lead Capture Copy Management Guide

**Last Updated:** 2026-03-24

## Overview

The lead capture popup uses dynamic copy detection to show relevant headlines and descriptions based on the current page. This guide explains how copy detection works and how to add or update copy patterns.

**Step 1 primary button** (CTA label) is **not** in this file—it is set once in `v2/components/lead-capture-popup.php`. This file only supplies **headline** and **description** for Step 1.

**Outbound callback (Fonio):** After submit, HubSpot/Fonio typically start the callback quickly. Put **immediacy** in the **headline** or **global CTA** when useful; keep **descriptions** benefit-led (Ordio, topic, kostenlos/unverbindlich)—see [FONIO_CALLBACK_COPY.md](./FONIO_CALLBACK_COPY.md).

**New blog posts:** Every new blog post must have custom lead capture copy. Use the generator script when creating posts. See [Adding Copy for New Blog Posts](#adding-copy-for-new-blog-posts) below.

## How Copy Detection Works

### Detection Process

1. **Quick Lookup (O(1)):** Checks quick lookup table for common pages. Blog post URLs are auto-added from config at runtime, so all 134+ posts get O(1) lookup without manual maintenance.
2. **Pattern Matching:** Matches URL/filename against patterns in config (longest match wins)
3. **Default Fallback:** Uses default copy if no match found

### Detection Order

```php
// 1. Check quick lookup table (fastest) - exact URL match
if (isset($quickLookup[$currentUrlPath])) {
    return $config['patterns'][$quickLookup[$currentUrlPath]];
}

// 2. Check filename in quick lookup
if (isset($quickLookup[$currentFile])) {
    return $config['patterns'][$quickLookup[$currentFile]];
}

// 3. Linear search - LONGEST (most specific) match wins
// CRITICAL: Broad patterns like /insights/ match all blog URLs; we pick the longest match
$bestMatch = null;
$bestMatchLength = 0;
foreach ($config['patterns'] as $type => $pattern) {
    foreach ($pattern['urls'] as $urlPattern) {
        $matches = (strpos($currentUrlPath, $urlPattern) !== false || strpos($currentFile, $urlPattern) !== false);
        if ($matches && strlen($urlPattern) > $bestMatchLength) {
            $bestMatchLength = strlen($urlPattern);
            $bestMatch = $pattern;
        }
    }
}
if ($bestMatch) return $bestMatch;

// 4. Return default
return $config['default'];
```

## Copy Structure

Each copy pattern consists of:

```php
'pattern_name' => [
    'urls' => ['/url-pattern', 'filename_pattern.php'], // URL/filename patterns to match
    'headline' => 'Headline Text',                      // H2 headline
    'description' => 'Description text.',               // Subtitle description
    'funnel_stage' => 'TOF'                            // TOF, MOF, or BOF
]
```

### Funnel Stages

- **TOF (Top of Funnel):** Awareness stage (tools, blog posts)
- **MOF (Middle of Funnel):** Consideration stage (industry pages, templates)
- **BOF (Bottom of Funnel):** Decision stage (pricing, comparison pages)

## Adding Copy for New Blog Posts

**When creating a new blog post**, add custom lead capture copy as part of the workflow:

```bash
php v2/scripts/blog/generate-lead-capture-copy.php --post=slug --category=lexikon [--write]
```

- **Without `--write`:** Outputs a PHP block to copy into `v2/data/lead_capture_copy.php`
- **With `--write`:** Inserts the pattern automatically before the PILLAR PAGES section

The generator uses the post title, slug, and `docs/data/blog-product-feature-mapping.json` to create contextual headline and description. Run after the post JSON exists.

**Validation:** `validate-new-post.php` warns if a post has no custom lead capture copy.

**Audit:** Run `php v2/scripts/blog/audit-lead-capture-copy.php` to list posts missing custom copy. Use `--fix` to automatically run the generator for each missing post.

## Adding New Copy Patterns (Manual)

### Step 1: Edit Copy Configuration

Edit `v2/data/lead_capture_copy.php`:

```php
return [
    'patterns' => [
        // ... existing patterns ...
        
        'my_new_page' => [
            'urls' => ['/my-new-page', 'my_new_page.php'],
            'headline' => 'Hast du Fragen zu [Topic]?',
            'description' => 'Wir rufen dich in der Regel schnell an und zeigen dir [concrete Ordio benefit]. Kostenlos und unverbindlich.',
            'funnel_stage' => 'MOF'
        ],
    ],
    
    'default' => [
        'headline' => 'Schnell einen Rückruf?',
        'description' => 'Dein Rückruf startet in der Regel direkt nach dem Absenden – wir melden uns am Telefon. Kostenlos und unverbindlich.',
        'funnel_stage' => 'Unknown'
    ]
];
```

### Step 2: Add to Quick Lookup (Optional)

For non-blog pages, add to quick lookup table in `v2/components/lead-capture-copy-detector.php`. **Blog posts are auto-added** from config at runtime, so no manual step is needed for new blog posts.

### Step 3: Test Copy Detection

1. Visit the page
2. Open browser console
3. Check popup headline/description
4. Verify it matches expected copy

## Updating Existing Copy

### Update Pattern Copy

Edit `v2/data/lead_capture_copy.php`:

```php
'pricing' => [
    'urls' => ['/preise', '/pricing', 'static_pricing'],
    'headline' => 'Updated Headline',  // Changed
    'description' => 'Updated description.',  // Changed
    'funnel_stage' => 'BOF'
],
```

### Update Multiple Patterns

Use find/replace or edit each pattern individually:

```php
// Update all tool pages
'tools_bruttonetto' => [
    'headline' => 'New Tool Headline',
    // ...
],
'tools_arbeitstage' => [
    'headline' => 'New Tool Headline',
    // ...
],
```

## Copy Best Practices

### Callback Framing (Required)

Every description must indicate that this is a callback request. Use at least one of: Rückruf, zurückrufen, anrufen, Beratung, "rufen dich", "rufen wir". See [LEAD_CAPTURE_COPY_BEST_PRACTICES.md](./LEAD_CAPTURE_COPY_BEST_PRACTICES.md#callback-framing-required).

### Grammar

Use main-clause word order; avoid verb-at-end (subordinate-clause) in descriptions. Example: "Ordio automatisiert die Zeiterfassung" not "Ordio die Zeiterfassung automatisiert".

### Uniqueness

No duplicate headlines or descriptions across patterns. Each pattern should have distinct, topic-specific copy.

### Headlines

- **Keep it short:** 5-10 words maximum
- **Use question format:** "Hast du Fragen zu...?"
- **Be specific:** Mention page topic when relevant
- **Use du tone:** Informal "du" not formal "Sie"
- **Include benefit:** What user gets from filling form

**Examples:**
- ✅ "Hast du Fragen zu unseren Preisen?"
- ✅ "Lohnabrechnung komplett automatisieren?"
- ❌ "Kontaktieren Sie uns für weitere Informationen" (too formal, too generic)

### Descriptions

- **Keep it concise:** 1-2 sentences maximum
- **Lead with benefit:** What user gets
- **Include CTA:** "kostenlos und unverbindlich"
- **Use du tone:** Informal, conversational
- **Be specific:** Mention relevant feature/topic

**Examples:**
- ✅ "Wir helfen dir gerne, den passenden Plan für deine Bedürfnisse zu finden – kostenlos und unverbindlich."
- ✅ "Entdecke, wie Ordio die gesamte Gehaltsabrechnung für dich übernimmt – kostenlos und unverbindlich."
- ❌ "Bitte füllen Sie das Formular aus, um weitere Informationen zu erhalten." (too formal, no benefit)

### Funnel Stage Selection

**TOF (Top of Funnel):**
- Tools pages (calculators, converters)
- Blog posts (educational content)
- General information pages

**MOF (Middle of Funnel):**
- Industry pages (vertical-specific)
- Templates (downloadable resources)
- Feature pages (product features)

**BOF (Bottom of Funnel):**
- Pricing pages (ready to buy)
- Comparison pages (evaluating options)
- Product pages (high intent)

## Common Copy Patterns

### Pricing Pages

```php
'pricing' => [
    'urls' => ['/preise', '/pricing', 'static_pricing'],
    'headline' => 'Hast du Fragen zu unseren Preisen?',
    'description' => 'Wir helfen dir gerne, den passenden Plan für deine Bedürfnisse zu finden – kostenlos und unverbindlich.',
    'funnel_stage' => 'BOF'
],
```

### Tools Pages

```php
'tools_bruttonetto' => [
    'urls' => ['/tools/brutto-netto-rechner'],
    'headline' => 'Lohnabrechnung komplett automatisieren?',
    'description' => 'Entdecke, wie Ordio die gesamte Gehaltsabrechnung für dich übernimmt – kostenlos und unverbindlich.',
    'funnel_stage' => 'TOF'
],
```

### Comparison Pages

```php
'comparison' => [
    'urls' => ['compare_', '/alternativen/'],
    'headline' => 'Brauchst du Hilfe bei der Entscheidung?',
    'description' => 'Lass uns dir zeigen, warum Ordio die beste Wahl für dich ist – kostenlos und unverbindlich.',
    'funnel_stage' => 'BOF'
],
```

### Blog Posts

```php
'blog_default' => [
    'urls' => ['/insights/', '/ratgeber/', '/lexikon/'],
    'headline' => 'Mehr über Ordio erfahren?',
    'description' => 'Erfahre, wie Ordio dir bei [Topic] helfen kann – kostenlos und unverbindlich.',
    'funnel_stage' => 'TOF'
],
```

## Performance Optimization

### Quick Lookup Table

Blog post URLs are **auto-added** from config at runtime. For other high-traffic pages (tools, pricing, etc.), add to the hardcoded quick lookup in `lead-capture-copy-detector.php`:

```php
// In lead-capture-copy-detector.php
$quickLookup = [
    '/preise' => 'pricing',
    '/tools/brutto-netto-rechner' => 'tools_bruttonetto',
    // Add more high-traffic non-blog pages here
];
```

**When to add:** Non-blog pages with >1000 monthly visits or in critical conversion paths.

### Pattern Ordering

Order patterns by frequency (most common first):

```php
'patterns' => [
    'pricing' => [...],        // Most common
    'tools_bruttonetto' => [...],
    'comparison' => [...],
    // Less common patterns last
],
```

## Avoiding Repetitive Patterns

**CRITICAL:** Do not use generic, repetitive copy that feels automated. See [LEAD_CAPTURE_COPY_BEST_PRACTICES.md](./LEAD_CAPTURE_COPY_BEST_PRACTICES.md) for full guidelines.

**Avoid:**
- Description containing "dir bei diesem Thema hilft" (generic placeholder)
- Overused headline pattern "[Topic] automatisch [verb]?"
- Identical lead-ins (Entdecke/Erfahre/Lass uns dir zeigen) without topic-specific benefits

**Audit:** Run `php v2/scripts/blog/audit-repetitive-lead-capture-copy.php` to list posts with repetitive patterns. Use `--json` or `--csv` for machine-readable output. Additional flags:
- `--callback` – warn if description lacks callback keywords
- `--grammar` – warn on verb-at-end patterns
- `--duplicates` – warn on duplicate headlines/descriptions
- `--tools` – validate tool patterns match tool topic

**Analysis:** `python3 v2/scripts/dev-helpers/analyze-lead-capture-copy.py` – JSON report (duplicates, grammar, mismatches, callback).

**Scoring:** `python3 v2/scripts/dev-helpers/score-lead-capture-copy.py` – prioritization scores for manual review.

## Verification

### Runtime Verification Script

Run `php v2/scripts/blog/verify-lead-capture-copy.php` to verify that each blog post URL resolves to its intended (non-generic) copy. The script simulates `getLeadCaptureCopy()` for every post and fails if any return generic fallbacks (`blog_insights_hauptseite`, `blog_generic`, `blog_hr`, or `default`).

**Options:**
- `--strict` – Also fail if the matched description contains "dir bei diesem Thema hilft" (repetitive pattern). Use before deployment to ensure all copy is tailored.

**When to run:**
- After adding or modifying lead capture copy patterns
- After changes to the copy detector logic
- As part of pre-deployment validation
- Use `--strict` when all repetitive patterns have been fixed

**Exit code:** 0 if all pass, 1 if any failures.

## Testing Copy Detection

### Manual Testing

1. Visit page with pattern
2. Open popup (manual trigger or wait for auto-trigger)
3. Verify headline matches expected copy
4. Verify description matches expected copy

### Debug Function

Use debug function to check detection:

```php
// In browser console (if debug function available)
console.log(debugLeadCaptureCopy());
```

### Performance Testing

Check detection performance:

```php
// In browser console (if performance function available)
console.log(getLeadCapturePerformance());
```

## Troubleshooting

### Copy Doesn't Match

1. **Check URL pattern:** Verify page URL matches pattern in config
2. **Check filename:** Verify filename matches pattern
3. **Check quick lookup:** Verify entry exists if using quick lookup
4. **Check pattern order:** Ensure more specific patterns come before generic ones

### Copy Shows Default

1. **Verify pattern exists:** Check if pattern is in config
2. **Verify URL matches:** Check if URL/filename matches pattern
3. **Check pattern syntax:** Ensure pattern array is correctly formatted
4. **Clear cache:** PHP may cache config file

### Performance Issues

1. **Add to quick lookup:** Move high-traffic pages to quick lookup
2. **Reorder patterns:** Put most common patterns first
3. **Optimize patterns:** Use more specific patterns (fewer matches)

## Related Documentation

- [Lead Capture Copy Best Practices](./LEAD_CAPTURE_COPY_BEST_PRACTICES.md) - Copy quality guidelines, AI avoidance, conversion optimization
- [Architecture Overview](./ARCHITECTURE.md) - System architecture
- [Integration Guide](./INTEGRATION_GUIDE.md) - Adding popup to pages
- [Troubleshooting Guide](./TROUBLESHOOTING.md) - Common issues
- [Testing Checklist](./TESTING_CHECKLIST.md) - Testing copy detection

