Allscreenshots Docs
Guides

Generate social media previews

Automatically create Open Graph images for your content

Generate social media previews

Create eye-catching Open Graph (OG) images that make your content stand out when shared on Twitter, Facebook, LinkedIn, and other platforms.

What you'll build

An automated system that generates preview images for blog posts, product pages, or any content you want to share on social media.

Prerequisites

  • AllScreenshots API key
  • A template page or dynamic route for generating previews

Approach 1: Screenshot existing pages

The simplest approach—capture your actual pages with social media dimensions.

Basic implementation

async function generateOgImage(pageUrl) {
  const response = await fetch('https://api.allscreenshots.com/v1/screenshots', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url: pageUrl,
      device: 'twitter_card', // 1200x675
      waitUntil: 'networkidle',
      blockAds: true,
      blockCookieBanners: true,
    }),
  });

  return response.blob();
}

For multiple platforms

Different platforms have different optimal dimensions:

const platforms = {
  twitter: 'twitter_card',      // 1200x675
  facebook: 'facebook_og',      // 1200x630
  linkedin: 'linkedin_post',    // 1200x627
};

async function generateAllPreviews(pageUrl) {
  const previews = {};

  for (const [platform, device] of Object.entries(platforms)) {
    const response = await fetch('https://api.allscreenshots.com/v1/screenshots', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        url: pageUrl,
        device,
        responseType: 'json',
      }),
    });

    const result = await response.json();
    previews[platform] = result.url;
  }

  return previews;
}

Approach 2: Dedicated OG template

Create a special page designed specifically for OG images, then screenshot it.

Create an OG template route

// pages/og/[slug].jsx or app/og/[slug]/page.jsx
export default function OgTemplate({ params }) {
  const post = getPost(params.slug);

  return (
    <div style={{
      width: 1200,
      height: 630,
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      padding: 80,
      background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
      color: 'white',
    }}>
      <h1 style={{ fontSize: 64, fontWeight: 'bold', marginBottom: 24 }}>
        {post.title}
      </h1>
      <p style={{ fontSize: 28, opacity: 0.9 }}>
        {post.description}
      </p>
      <div style={{ marginTop: 'auto', fontSize: 24 }}>
        yoursite.com
      </div>
    </div>
  );
}

Capture the template

async function generateOgImage(slug) {
  const templateUrl = `https://yoursite.com/og/${slug}`;

  const response = await fetch('https://api.allscreenshots.com/v1/screenshots', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url: templateUrl,
      viewport: { width: 1200, height: 630 },
      format: 'png',
    }),
  });

  return response;
}

Serve the OG image

// API route: /api/og/[slug]
export async function GET(request, { params }) {
  const { slug } = params;

  // Check cache first
  const cached = await cache.get(`og:${slug}`);
  if (cached) {
    return new Response(cached, {
      headers: { 'Content-Type': 'image/png' },
    });
  }

  // Generate new image
  const image = await generateOgImage(slug);
  const buffer = await image.arrayBuffer();

  // Cache for 24 hours
  await cache.set(`og:${slug}`, buffer, { ttl: 86400 });

  return new Response(buffer, {
    headers: { 'Content-Type': 'image/png' },
  });
}

Add meta tags

<meta property="og:image" content="https://yoursite.com/api/og/my-post" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://yoursite.com/api/og/my-post" />

Approach 3: Bulk generation at build time

Generate all OG images during your build process:

// scripts/generate-og-images.js
const posts = getAllPosts();

async function generateAllOgImages() {
  // Use bulk API for efficiency
  const response = await fetch('https://api.allscreenshots.com/v1/screenshots/bulk', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      urls: posts.map(post => ({
        url: `https://yoursite.com/og/${post.slug}`,
      })),
      defaults: {
        viewport: { width: 1200, height: 630 },
        format: 'png',
      },
      webhookUrl: process.env.BUILD_WEBHOOK_URL,
    }),
  });

  const { bulkJobId } = await response.json();
  console.log(`Bulk job started: ${bulkJobId}`);
}

Best practices

Cache aggressively

OG images rarely change—cache them for at least 24 hours:

// With CDN headers
return new Response(image, {
  headers: {
    'Content-Type': 'image/png',
    'Cache-Control': 'public, max-age=86400, s-maxage=604800',
  },
});

Invalidate on content updates

When content changes, regenerate the OG image:

async function updatePost(slug, data) {
  await db.posts.update(slug, data);

  // Invalidate cached OG image
  await cache.delete(`og:${slug}`);

  // Optionally pre-generate new image
  await generateOgImage(slug);
}

Test with social media debuggers

Verify your images with platform tools:

Social platforms cache OG images aggressively. Use their debugger tools to force a refresh after updating images.

Complete example: Next.js integration

// app/api/og/[slug]/route.ts
import { NextRequest } from 'next/server';

export async function GET(
  request: NextRequest,
  { params }: { params: { slug: string } }
) {
  const { slug } = params;

  const response = await fetch('https://api.allscreenshots.com/v1/screenshots', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url: `${process.env.NEXT_PUBLIC_URL}/og/${slug}`,
      viewport: { width: 1200, height: 630 },
      format: 'png',
      waitUntil: 'networkidle',
    }),
  });

  const image = await response.arrayBuffer();

  return new Response(image, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=86400',
    },
  });
}

On this page