Auto-Generate SEO Meta Descriptions at Scale | OpsBlu Docs

Auto-Generate SEO Meta Descriptions at Scale

Build systems to auto-generate meta descriptions for large sites. Covers template patterns, character limits, CTR benchmarks, and when Google rewrites.

Meta descriptions do not directly affect rankings, but they significantly influence click-through rate. Google rewrites meta descriptions approximately 63% of the time (Ahrefs study), but providing a well-crafted description still gives you the best chance of controlling your SERP snippet.

When Auto-Generation Makes Sense

Manual meta descriptions work for sites with 50-200 pages. For sites with 5,000+ pages -- especially ecommerce catalogs, directories, and documentation sites -- auto-generation is the only practical approach.

Template-Based Generation

The most reliable method uses structured templates with dynamic variables:

// Template patterns by page type
const metaTemplates = {
  product: (p) =>
    `Buy ${p.name} for $${p.price}. ${p.shortDesc}. Free shipping on orders over $50. ${p.reviewCount} reviews.`,
  category: (c) =>
    `Shop ${c.count}+ ${c.name} products. Compare prices, read reviews, and find the best ${c.name} for your needs.`,
  blogPost: (b) =>
    `${b.excerpt.substring(0, 120)}... Read our ${b.readTime}-minute guide.`,
  location: (l) =>
    `Find ${l.service} in ${l.city}, ${l.state}. ${l.reviewCount} reviews, ${l.rating}/5 stars. Open ${l.hours}.`
};

// Enforce character limits
function generateMeta(template, data) {
  const raw = template(data);
  if (raw.length > 155) return raw.substring(0, 152) + '...';
  if (raw.length < 70) return raw + ` | ${data.brandName}`;
  return raw;
}

Character Length Guidelines

Target Length Notes
Desktop 150-155 chars Google truncates at ~155 characters
Mobile 120-130 chars Smaller viewport truncates earlier
Minimum 70 chars Below this, Google almost always rewrites
Sweet spot 120-145 chars Best balance of completeness and display

Why Google Rewrites Your Descriptions

Google replaces your meta description when:

  1. The description does not match the query -- If someone searches "red running shoes size 10" and your meta says "Shop our athletic footwear collection," Google will pull a more relevant snippet from the page body.
  2. The description is too short or generic -- Descriptions under 70 characters or stuffed with boilerplate get replaced.
  3. The description is duplicate -- Identical descriptions across multiple pages signal low effort.
  4. No description exists -- Google generates one from page content (often poorly).

Reducing Google Rewrites

  • Include the primary keyword naturally in the first 60 characters
  • Match the search intent of the target query
  • Include specific details: numbers, prices, dates, locations
  • Avoid generic calls-to-action like "Learn more" or "Click here"

Implementation Patterns

Generate descriptions during page build for best crawler visibility:

# Django template tag example
from django import template
register = template.Library()

@register.simple_tag
def auto_meta_description(page):
    if page.manual_meta:
        return page.manual_meta  # Manual override always wins

    if page.page_type == 'product':
        desc = f"Buy {page.title} - ${page.price:.2f}. "
        desc += f"{page.short_description[:80]}. "
        desc += f"{'Free shipping. ' if page.free_shipping else ''}"
        desc += f"{page.review_count} customer reviews."
    elif page.page_type == 'category':
        desc = f"Browse {page.product_count}+ {page.title}. "
        desc += f"Compare top brands, read reviews, find deals."
    else:
        # Fallback: first 150 chars of body content
        desc = page.body_text[:150].rsplit(' ', 1)[0] + '...'

    return desc[:155]

CMS Plugin Approach

For WordPress sites at scale, use a programmatic approach rather than relying on per-page SEO plugin fields:

  • Yoast SEO -- Supports template variables like %%title%%, %%excerpt%%, %%category%%
  • Rank Math -- Similar template system with %seo_title%, %excerpt%
  • Custom function -- Hook into wp_head to output computed descriptions based on post type and taxonomy

Headless CMS / Static Site Generators

For Astro, Next.js, or similar frameworks:

---
// Astro example: auto-generate meta for documentation pages
const { title, description, content } = Astro.props;

const autoDescription = description ||
  content.replace(/[#*`\[\]]/g, '')  // Strip markdown
    .replace(/\s+/g, ' ')            // Normalize whitespace
    .trim()
    .substring(0, 150)
    .replace(/\s\S*$/, '...');       // Break at word boundary
---
<meta name="description" content={autoDescription} />

Quality Assurance for Auto-Generated Descriptions

Automated Checks

Run these validations in your CI/CD pipeline or as a scheduled crawl:

  • Length check -- Flag descriptions outside 70-155 character range
  • Duplicate check -- No two pages should share the same description
  • Keyword presence -- Primary target keyword should appear in the description
  • Boilerplate ratio -- If more than 40% of descriptions share identical phrasing, templates need refinement
  • Special character escaping -- Ensure quotes, ampersands, and HTML entities render correctly

Monitoring in Search Console

Track CTR by page type in Search Console. If auto-generated descriptions produce CTR below 2% for informational queries or below 4% for branded queries, the templates need improvement.

Compare pages with manual descriptions against auto-generated ones. If manual pages consistently outperform by more than 1.5x CTR, your templates are too generic.

Common Mistakes

  • Keyword stuffing -- Repeating the target keyword 3+ times in 155 characters looks spammy and gets rewritten
  • Missing call-to-action -- Descriptions without a verb ("Shop," "Learn," "Compare," "Get") underperform
  • Ignoring page type differences -- Using the same template for products, categories, and blog posts produces poor results
  • Not allowing manual overrides -- Always let editors override auto-generated descriptions for high-value pages
  • Forgetting mobile truncation -- Testing only on desktop misses the shorter mobile display