Systems Library / Marketing Automation / How to Build an AI Product Description Generator
Marketing Automation content marketing

How to Build an AI Product Description Generator

Generate unique, SEO-optimized product descriptions at scale.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Writing product descriptions for 500 SKUs manually is the kind of work that burns out good copywriters. This ai product description generator ecommerce system takes your product data, a brand voice profile, and an SEO target, and outputs publish-ready descriptions in seconds. I have run this for catalogs with thousands of products and the quality holds up because the prompt is doing the heavy lifting.

Product descriptions are one of the highest-leverage pieces of copy in ecommerce. Bad descriptions cost you both SEO rankings and conversion rate at the same time. This system fixes both without hiring a team of writers.

What You Need Before Starting

Step 1: Define Your Brand Voice Profile

The voice profile is what keeps every description sounding like your brand instead of generic AI output. Create brand_voice.py:

BRAND_VOICES = {
    "premium": {
        "tone": "Confident, sophisticated, understated. We do not oversell.",
        "avoid": "Superlatives like 'best', 'amazing', 'incredible'. Passive voice. Filler phrases.",
        "structure": "Lead with the key benefit. Follow with material/spec details. End with use case.",
        "reading_level": "Grade 8. Professional but approachable.",
        "length": "80-120 words for standard products, 150-200 for hero products."
    },
    "direct": {
        "tone": "Straight-talking. No fluff. Tells you what it does and why that matters.",
        "avoid": "Poetic language. Vague claims. Anything that delays the main point.",
        "structure": "What it is. What it does. Who it is for. Key specs.",
        "reading_level": "Grade 5-6. Anyone can understand it.",
        "length": "60-90 words."
    },
    "enthusiast": {
        "tone": "Passionate, knowledgeable, peer-to-peer. Talks to people who care deeply about the category.",
        "avoid": "Explaining basics the audience already knows. Condescending simplification.",
        "structure": "Hook with the differentiator. Dig into the specs. Connect specs to real-world performance.",
        "reading_level": "Grade 7-8. Technical terms are fine if accurate.",
        "length": "100-150 words."
    }
}

Step 2: Set Up the Generator

import os
import anthropic
import pandas as pd
from dotenv import load_dotenv
from brand_voice import BRAND_VOICES

load_dotenv()
client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

def generate_description(product: dict, voice_key: str = "direct", seo_keyword: str = "") -> dict:
    voice = BRAND_VOICES.get(voice_key, BRAND_VOICES["direct"])
    
    keyword_instruction = ""
    if seo_keyword:
        keyword_instruction = f"\nSEO KEYWORD: Include '{seo_keyword}' naturally once in the description."
    
    prompt = f"""Write a product description for this item.

PRODUCT NAME: {product.get('name', '')}
CATEGORY: {product.get('category', '')}
KEY FEATURES: {product.get('features', '')}
PRICE: {product.get('price', '')}
ADDITIONAL NOTES: {product.get('notes', '')}
{keyword_instruction}

BRAND VOICE PROFILE:
- Tone: {voice['tone']}
- Avoid: {voice['avoid']}
- Structure: {voice['structure']}
- Reading level: {voice['reading_level']}
- Target length: {voice['length']}

Also generate:
- META DESCRIPTION: 155 characters max, includes the product name and primary benefit
- BULLET POINTS: 4 key selling points as short bullets (for listing pages)

Format your response as:
DESCRIPTION:
[description here]

META:
[meta description here]

BULLETS:
- [bullet 1]
- [bullet 2]
- [bullet 3]
- [bullet 4]"""

    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=600,
        messages=[{"role": "user", "content": prompt}]
    )
    
    raw = message.content[0].text
    
    result = {"name": product["name"], "raw_output": raw}
    
    if "DESCRIPTION:" in raw:
        parts = raw.split("META:")
        result["description"] = parts[0].replace("DESCRIPTION:", "").strip()
        
        if len(parts) > 1:
            meta_bullets = parts[1].split("BULLETS:")
            result["meta"] = meta_bullets[0].strip()
            if len(meta_bullets) > 1:
                result["bullets"] = meta_bullets[1].strip()
    
    return result

Step 3: Load Products from CSV

Your product CSV should look like this:

name,category,features,price,notes
Titanium Chef Knife 8",Kitchen,Japanese steel blade|Full tang|Pakkawood handle,89.99,Flagship product
Cotton Crew Tee,Apparel,100% organic cotton|Pre-shrunk|12 color options,34.99,
Wireless Earbuds Pro,Electronics,ANC|32hr battery|IPX5 waterproof,149.99,Hero product for Q4

Load and process it:

def process_catalog(csv_path: str, voice_key: str = "direct") -> list:
    df = pd.read_csv(csv_path)
    results = []
    
    for _, row in df.iterrows():
        product = row.to_dict()
        print(f"Generating: {product['name']}")
        
        try:
            result = generate_description(product, voice_key)
            results.append(result)
        except Exception as e:
            print(f"Failed on {product['name']}: {e}")
            results.append({"name": product["name"], "error": str(e)})
    
    return results

Step 4: Save Results Back to CSV

def save_results(results: list, output_path: str):
    rows = []
    for r in results:
        rows.append({
            "name": r.get("name", ""),
            "description": r.get("description", r.get("raw_output", "")),
            "meta_description": r.get("meta", ""),
            "bullets": r.get("bullets", ""),
            "error": r.get("error", "")
        })
    
    df = pd.DataFrame(rows)
    df.to_csv(output_path, index=False)
    print(f"Saved {len(rows)} descriptions to {output_path}")

if __name__ == "__main__":
    results = process_catalog("products.csv", voice_key="direct")
    save_results(results, "products_with_descriptions.csv")

Step 5: Add a Quality Check Pass

Before you send these to the site, run a quick quality filter:

def quality_check(description: str, min_words: int = 50, max_words: int = 200) -> dict:
    words = len(description.split())
    
    issues = []
    if words < min_words:
        issues.append(f"Too short: {words} words")
    if words > max_words:
        issues.append(f"Too long: {words} words")
    if description.lower().count("amazing") > 0:
        issues.append("Contains banned word: 'amazing'")
    if description.lower().count("best") > 0:
        issues.append("Contains banned word: 'best'")
    
    return {
        "word_count": words,
        "issues": issues,
        "pass": len(issues) == 0
    }

What to Build Next

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