Skip to main content

AI Meta Generator

Drafts meta titles and descriptions for products, categories, and CMS pages by calling Anthropic's Claude. Architected for catalog-scale runs:

  • Two-block cacheable system prompt — typical batch run hits ~90% prompt-cache discount on input tokens
  • Review queue — every suggestion lands in byte8_seosuite_meta_suggestion for editor approval before being written to the entity (override with auto-approve for trusted batches)
  • Three trigger paths — bulk CLI, in-context "Generate with AI" button, and a 30-min cron auto-generator
  • Token usage tracked per row — input / cached / output, so you can size cost expectations per 1000 SKUs

How it works

┌──────────────────────┐
│ Trigger │ CLI · admin button · cron
└──────────┬───────────┘

┌──────────────────────┐
│ PromptBuilder │ System blocks (cached) + user prompt (per entity)
└──────────┬───────────┘

┌──────────────────────┐
│ AnthropicClient │ POST /v1/messages with cache_control: ephemeral
└──────────┬───────────┘

┌──────────────────────┐
│ SuggestionParser │ Strict JSON parse + char-limit enforcement
└──────────┬───────────┘

┌──────────────────────┐
│ Repository.save() │ byte8_seosuite_meta_suggestion (status=pending)
└──────────┬───────────┘
↓ if auto-approve
┌──────────────────────┐
│ SuggestionApplier │ Writes to product/category/cms.meta_title + meta_description
└──────────────────────┘

Prompt design

Two cacheable system blocks + one per-entity user prompt:

BlockContentWhy it's cacheable
System block 1Framing rules, character limits, store name + locale, brand voice, global keywords, output JSON schemaIdentical for every product in a batch
System block 2Entity-type specific rules (product / category / CMS)Identical for every entity of the same type in a batch
User messageThe current entity's source data as JSONUnique per entity — never cached

Both system blocks are sent with cache_control: { type: "ephemeral" }. After the first request, subsequent requests in the same batch return cache_read_input_tokens > 0, charged at ~10% of the normal input rate.

Output format

Claude is asked to return strict JSON:

{
"meta_title": "Acme Pro Runner — Lightweight road shoe | Sample Store",
"meta_description": "Acme Pro Runner: 220g neutral road shoe with 28mm stack. Free UK delivery, 30-day returns. Discover the range at Sample Store.",
"rationale": "Title leads with model + key differentiator (lightweight + road), suffix repeats brand. Description hits weight, stack height, and a trust signal."
}

The parser:

  1. Strips ```json fences if Claude adds them
  2. Extracts the first balanced { … } object
  3. Validates meta_title and meta_description aren't both empty (failure → status=failed, error populated)
  4. Enforces character limits via word-boundary truncation

Truncation cuts on the nearest space within 60% of the limit, then trims trailing punctuation.

Models

ModelBest for
claude-haiku-4-5 (default)Bulk product runs, cost-sensitive catalogs
claude-sonnet-4-6Hero categories, premium brand voice
claude-opus-4-7One-shot generation for the 50 highest-traffic SKUs where copy quality matters most

You can switch models per-store, or run a Haiku batch for the long tail and an Opus batch for top sellers via different --batch IDs.

Cost rough sizing

For Haiku 4.5 on a typical product (~600 chars description input):

  • Input: ~700 tokens
  • System prompt (cached after row 1): ~400 tokens
  • Output: ~120 tokens

A 1000-SKU run with caching working as expected: roughly $0.50–$1.00. Without caching it would be 5–10× that.

Where suggestions go

Marketing → SEO Suite → AI Meta Suggestions — full grid with mass approve/reject/delete and per-row Approve & Apply / Reject. Filter by status, entity type, batch_id, model.

Next