Skip to content

Best Practices

Guidelines for optimal use of OG Image API.

Security

Protect Your API Key

javascript
// ❌ Never expose in client-side code
const response = await fetch('/api/generate', {
  headers: { 'X-API-Key': 'og_secret_key' } // EXPOSED!
});

// ✅ Use server-side routes or signed URLs
const response = await fetch('/api/og?title=Hello'); // Internal route

Use Environment Variables

bash
# .env (never commit)
OG_IMAGE_API_KEY=og_your_key_here
javascript
// Access securely
const apiKey = process.env.OG_IMAGE_API_KEY;

Validate Inputs

javascript
function validateOGParams(params) {
  return {
    title: sanitize(params.title?.slice(0, 200)),
    subtitle: sanitize(params.subtitle?.slice(0, 300)),
    theme: ['dark', 'light'].includes(params.theme) ? params.theme : 'dark',
    template: VALID_TEMPLATES.includes(params.template) ? params.template : 'default'
  };
}

Performance

Generate at Build Time

For static content, generate images during build:

javascript
// build.js
async function prebuildOGImages() {
  const posts = await getAllPosts();
  
  for (const post of posts) {
    await generateOGImage(post);
  }
}

Cache Aggressively

javascript
// Set long cache headers
res.setHeader('Cache-Control', 'public, max-age=86400, s-maxage=604800');

Use CDN

Deploy your OG image route to edge locations:

javascript
// Next.js Edge runtime
export const config = { runtime: 'edge' };

Optimize Source Images

  • Compress images before sending URLs
  • Use appropriately sized images (not 4K for avatars)
  • Prefer JPEG for photos, PNG for graphics

Content Guidelines

Title Best Practices

DoDon't
5-10 words20+ words
Clear value propVague statements
Include keywordsKeyword stuffing
Proper capitalizationALL CAPS everything

Subtitle Best Practices

  • Expand on the title
  • Add context or benefit
  • Keep under 100 characters for best display

Image URLs

javascript
// ✅ Use HTTPS
"https://example.com/image.png"

// ✅ Use optimized images
"https://cdn.example.com/image-800x800.jpg"

// ❌ Avoid
"http://example.com/image.png"  // Not HTTPS
"https://example.com/huge-4k-image.png"  // Too large

Error Handling

Implement Fallbacks

javascript
async function getOGImage(params) {
  try {
    const response = await fetch('/api/og', {
      method: 'POST',
      body: JSON.stringify(params)
    });
    
    if (!response.ok) throw new Error('Generation failed');
    
    return await response.arrayBuffer();
  } catch (error) {
    console.error('OG image error:', error);
    return fs.readFileSync('./public/fallback-og.png');
  }
}

Log Errors

javascript
if (!response.ok) {
  console.error('OG API Error', {
    status: response.status,
    params: sanitizeForLogging(params)
  });
}

Rate Limiting

Respect Limits

PlanRate Limit
Free10/minute
Pro60/minute
Business120/minute

Implement Backoff

javascript
async function generateWithRetry(params, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    const response = await fetch('/api/generate', {/*...*/});
    
    if (response.status === 429) {
      const delay = Math.pow(2, i) * 1000;
      await new Promise(r => setTimeout(r, delay));
      continue;
    }
    
    return response;
  }
  throw new Error('Rate limit exceeded');
}

SEO Optimization

Complete Meta Tags

html
<meta property="og:title" content="Your Title">
<meta property="og:description" content="Your description">
<meta property="og:image" content="https://yoursite.com/og/page.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:type" content="article">
<meta property="og:url" content="https://yoursite.com/page">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Your Title">
<meta name="twitter:description" content="Your description">
<meta name="twitter:image" content="https://yoursite.com/og/page.png">

Use Absolute URLs

html
<!-- ✅ Correct -->
<meta property="og:image" content="https://example.com/og/image.png">

<!-- ❌ Wrong -->
<meta property="og:image" content="/og/image.png">

Test Your Images

Use these validators:

Architecture Patterns

Static Site Pattern

Build Time:
  Content → Generate OG Images → Save to /public/og/

Runtime:
  Page → Reference /og/page-slug.png

Dynamic API Pattern

Request:
  /api/og?title=Hello&subtitle=World

  Check Cache → Hit? Return cached

  Generate → Save to cache → Return

Signed URL Pattern

Build/SSR:
  Get signed URL from API (with API key)

  Store signed URL in meta tags

Client:
  Browser requests signed URL directly
  No API key exposed

Checklist

  • [ ] API key stored securely in environment variables
  • [ ] Input validation on all user-provided content
  • [ ] Fallback images for error cases
  • [ ] Caching implemented (CDN, Redis, or file system)
  • [ ] Rate limiting handled with backoff
  • [ ] Complete meta tags including dimensions
  • [ ] Absolute URLs in all meta tags
  • [ ] Tested on Facebook, Twitter, LinkedIn validators

Generate stunning Open Graph images programmatically.