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',
},
});
}