Your Blog Posts Deserve Better Social Previews
You spend hours writing a technical blog post. You share it on Twitter. And the preview looks like this:
Home Page
yourdomain.com
No image. No description. Just a sad, generic text preview that nobody clicks on.
The fix is Open Graph meta tags — specifically og:image. But if you have 50+ blog posts, you can't open Figma and design a unique image for each one. You need dynamic generation.
Why Puppeteer/Playwright Sucks for Blog OG Images
The "standard" approach is:
- Spin up a headless browser in a serverless function
- Load an HTML template with your post title
- Screenshot it
- Serve the PNG
This works in theory. In practice:
- Cold boot times of 3-5 seconds mean social platforms time out and cache nothing
- Memory usage of 200-500MB per invocation means expensive serverless bills
- Font loading is unreliable in headless environments
- You end up maintaining a mini rendering pipeline for what should be a simple image
A Better Approach: URL-Based Image Generation
What if every blog post got a unique social preview by just adding a URL to your og:image tag?
<meta property="og:image"
content="https://socialcard.risero.io/generate?title=Building+a+REST+API+with+Hono&template=blog&api_key=YOUR_KEY" />
That URL returns a 1200×630 PNG. No serverless function in your codebase. No headless browser. No build step. The image is edge-cached for 24 hours so it loads instantly when someone shares your link.
How It Works Under the Hood
Instead of using a browser to render HTML:
- Satori (by Vercel) — converts JSX to SVG using a custom layout engine
- resvg-wasm — rasterizes SVG to PNG in WebAssembly
- Cloudflare Workers — runs at the edge, <100ms response time
Browser-quality rendering without an actual browser.
Framework Integration Examples
Next.js (App Router)
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
const ogImage = new URL('https://socialcard.risero.io/generate');
ogImage.searchParams.set('title', post.title);
ogImage.searchParams.set('description', post.excerpt);
ogImage.searchParams.set('template', 'blog');
ogImage.searchParams.set('api_key', 'YOUR_KEY');
return {
openGraph: {
images: [{ url: ogImage.toString(), width: 1200, height: 630 }],
},
};
}
Astro
---
const { title, description } = Astro.props;
const ogUrl = `https://socialcard.risero.io/generate?title=${encodeURIComponent(title)}&template=developer&api_key=YOUR_KEY`;
---
<meta property="og:image" content={ogUrl} />
Hugo
{{ $ogUrl := printf "https://socialcard.risero.io/generate?title=%s&template=blog&api_key=YOUR_KEY" (urlquery .Title) }}
<meta property="og:image" content="{{ $ogUrl }}" />
Ghost (via Code Injection)
<script>
const title = document.querySelector('meta[property="og:title"]')?.content || document.title;
const ogMeta = document.createElement('meta');
ogMeta.setAttribute('property', 'og:image');
ogMeta.content = `https://socialcard.risero.io/generate?title=${encodeURIComponent(title)}&template=blog&api_key=YOUR_KEY`;
document.head.appendChild(ogMeta);
</script>
Plain HTML (any static site)
<meta property="og:image"
content="https://socialcard.risero.io/generate?title=Welcome+to+My+Blog&template=minimal&api_key=YOUR_KEY" />
Templates Built for Dev Content
The API has 10 templates, but these are the ones built specifically for developer blogs:
- blog — title, description, author with gradient accent. Perfect for articles.
- developer — dark theme, monospace font, terminal aesthetics. For dev tool blogs.
- changelog — version badge with diff-style indicators. For release notes.
- github — repo card with language, stars, forks. For open source posts.
- announcement — launch badge with vibrant gradient. For product announcements.
Each supports light/dark themes and custom accent colors.
Get Started in 2 Minutes
- Get a free API key at socialcard.risero.io (just your email, no credit card)
- Try the live playground to preview templates with your own titles
- Copy the URL and drop it in your
og:imagemeta tag - Share a link on Twitter/LinkedIn/Slack and see the preview
Free tier gives you 50 images/day — enough for any personal or team blog.
I built this to solve my own dev blog problem. If you try it, I'd love to hear which templates work best for your content and what's missing.
Top comments (0)