Automating SEO Meta Descriptions at Scale: A Script + GPT-4o Pipeline

The math: 500 pages × 3 minutes per meta description = 25 hours of mind-numbing work. Or: one Python script + GPT-4o = 500 descriptions in 20 minutes, with human review on the worst 10%.

I built this for a site migration where every URL changed and every meta description needed rewriting. Here's the exact pipeline.

What You'll Need

  • 15 minutes to review edge cases

Step 1: Extract Page Context

Meta descriptions fail when they're generic. The fix is feeding GPT-4o real page context, not just a title.

Scrape or export for each URL:

  • Top 3 keywords the page targets

Store this in pages.csv.

Step 2: The Meta Description Prompt

This is the entire quality control mechanism. A bad prompt = 500 bad descriptions.

``

You are an SEO copywriter. Write a meta description for this page.

URL: {url}

Page Title: {title}

H1: {h1}

Content excerpt: {excerpt}

Target keywords: {keywords}

Requirements:

  • One sentence only, no periods at the end unless grammatically necessary

Return ONLY the meta description. No quotes, no explanation.

`

The {intent_type} variable is crucial. Informational queries get "Learn how..." Commercial get "See how..." Navigational get "Find..."

Step 3: The Python Script

`python

import pandas as pd

import openai

from concurrent.futures import ThreadPoolExecutor

openai.api_key = "YOUR_KEY"

def generate_meta(row):

prompt = f"""

You are an SEO copywriter...

URL: {row['url']}

Page Title: {row['title']}

H1: {row['h1']}

Content excerpt: {row['excerpt']}

Target keywords: {row['keywords']}

Intent: {row['intent']}

"""

response = openai.chat.completions.create(

model="gpt-4o",

messages=[{"role": "user", "content": prompt}],

temperature=0.3,

max_tokens=80

)

desc = response.choices[0].message.content.strip()

# Enforce character limit

return desc[:160] if len(desc) > 160 else desc

Process in batches of 50

pages = pd.read_csv("pages.csv")

with ThreadPoolExecutor(max_workers=10) as executor:

pages['new_meta'] = list(executor.map(generate_meta, pages.to_dict('records')))

pages.to_csv("meta_descriptions_output.csv", index=False)

``

Temperature 0.3 keeps output consistent. Max 80 tokens prevents runaway generation.

Step 4: The Approval Gate

Not every description needs human eyes. Use these filters:

  • Human task: review the flagged 10–15%, fix brand voice issues, approve in bulk

I use a Google Sheet with three columns: auto-generated, human-edited, status (approved / needs work / rejected).

Step 5: Bulk Update

Export approved descriptions and upload via:

  • Next.js/Vercel: Update frontmatter and redeploy

The Catch (What's Still Hard)

AI still misses nuance. It wrote "Learn how to handle a data breach" for a page about breach prevention. The intent was wrong. Every flagged description gets a second look for intent match.

Character counting is imprecise. GPT-4o counts tokens, not characters. The script truncates at 160, which sometimes cuts a word mid-thought. I add a 5-character buffer and let the human round out the final 2%.

Brand voice doesn't transfer automatically. For a medical client, AI generated "Discover how to manage your diabetes" — too casual. The approved version was "Learn evidence-based strategies for diabetes management." Brand guardrails must be explicit in the prompt.

What's Still Hard

  • API costs at scale: 500 descriptions × ~1,500 input tokens = ~750K tokens = ~$3.75 on GPT-4o. Cheap, but 50,000 pages = $375. Budget accordingly.

Related reading

The Bottom Line

This isn't a future possibility—it's happening now for organizations that moved early. The question isn't whether this technology will reshape your workflows. It's whether your team will be leading that change or reacting to competitors who did.