Systems Library / Marketing Automation / How to Build an AI Ad Headline Generator
Marketing Automation paid advertising

How to Build an AI Ad Headline Generator

Generate scroll-stopping ad headlines using AI trained on winning ads.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

An ai ad headline generator tool saves hours of brainstorming and produces variations you would never think of manually. I use this to generate 30+ headline options in minutes, then pick the 5 best to test. The system is trained on your winning ads, not generic templates.

Headlines are the highest-impact element of any ad. A good one can double your CTR overnight.

What You Need Before Starting

Step 1: Build Your Headline Training Data

WINNING_HEADLINES = [
    {"headline": "Stop Wasting Money on Ads That Don't Convert", "ctr": 3.2, "type": "pain"},
    {"headline": "We Built 47 Systems for One Client. Here's What Happened.", "ctr": 4.1, "type": "proof"},
    {"headline": "Your Competitors Are Already Using This", "ctr": 2.8, "type": "fomo"},
    {"headline": "The $300K Question Nobody Asks", "ctr": 3.5, "type": "curiosity"},
    {"headline": "I Replaced 3 Employees with One System", "ctr": 4.7, "type": "bold_claim"},
]

HEADLINE_TYPES = [
    "question", "bold_claim", "curiosity", "pain_point", "social_proof",
    "time_based", "dream_outcome", "pattern_interrupt", "stat_driven",
    "before_after", "objection_handling", "fomo", "listicle"
]

Step 2: Create the Generator

import anthropic
from dotenv import load_dotenv

load_dotenv()

def generate_headlines(product, audience, pain_point, count=30):
    client = anthropic.Anthropic()
    
    examples = "\n".join([
        f"- \"{h['headline']}\" (CTR: {h['ctr']}%, Type: {h['type']})"
        for h in WINNING_HEADLINES
    ])
    
    prompt = f"""Generate {count} ad headlines for Meta Ads.

Product: {product}
Target audience: {audience}
Core pain point: {pain_point}

WINNING HEADLINE EXAMPLES (study the patterns):
{examples}

REQUIREMENTS:
- Max 40 characters each
- Use ALL of these headline types: {', '.join(HEADLINE_TYPES)}
- At least 2 headlines per type
- No generic phrases like "transform your business" or "take it to the next level"
- Use specific numbers when possible
- Write at a grade 5 reading level
- Each headline should make someone stop scrolling

Return as JSON array: [{{"headline": "...", "type": "...", "hook_angle": "..."}}]"""

    resp = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=2000,
        messages=[{"role": "user", "content": prompt}]
    )
    return resp.content[0].text

Step 3: Score and Rank Headlines

import json

def score_headlines(headlines_json, audience):
    client = anthropic.Anthropic()
    headlines = json.loads(headlines_json)
    
    headlines_text = "\n".join([f'{i+1}. "{h["headline"]}"' for i, h in enumerate(headlines)])
    
    resp = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1500,
        messages=[{"role": "user", "content": f"""Score each headline 1-10 for a {audience} audience.

Criteria:
- Scroll-stop power (would this make someone pause?)
- Clarity (is the value prop clear in under 2 seconds?)
- Curiosity gap (does it create enough tension to click?)
- Relevance to target audience

Headlines:
{headlines_text}

Return JSON array: [{{"index": N, "headline": "...", "score": N, "reason": "..."}}]
Sort by score descending."""}]
    )
    return resp.content[0].text

Step 4: A/B Test Format

Group the top scorers by type for structured testing:

def prepare_test_groups(scored_headlines, top_n=10):
    headlines = json.loads(scored_headlines)
    top = sorted(headlines, key=lambda x: x["score"], reverse=True)[:top_n]
    
    groups = {}
    for h in top:
        h_type = h.get("type", "unknown")
        if h_type not in groups:
            groups[h_type] = []
        groups[h_type].append(h)
    
    print(f"\nTop {top_n} headlines for testing:\n")
    for h_type, items in groups.items():
        print(f"  {h_type.upper()}:")
        for item in items:
            print(f"    [{item['score']}/10] {item['headline']}")
    
    return top

Step 5: Feed Results Back

After running the ads, log which headlines performed best and add them to your training data:

def update_training_data(headline, ctr, headline_type):
    WINNING_HEADLINES.append({
        "headline": headline,
        "ctr": ctr,
        "type": headline_type,
    })
    # Sort by CTR and keep top 20
    WINNING_HEADLINES.sort(key=lambda x: x["ctr"], reverse=True)
    while len(WINNING_HEADLINES) > 20:
        WINNING_HEADLINES.pop()

The more you test and feed back, the better the generator gets at predicting what your audience responds to.

What to Build Next

Build a headline variation engine that takes your top performer and creates 10 variations with small changes (different numbers, different emotions, different structures). This lets you squeeze more performance from proven winners.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems