Every time you share a link on Twitter, Slack, or Discord, the preview image matters. A good one gets clicks. A missing one gets scrolled past.
Here's how to generate them automatically in 15 lines of Python.
The Problem
You write a blog post. You share it. The link preview shows... nothing. Or worse, a random cropped image from your page.
You could open Figma every time and design a card. But you won't. Nobody does.
The Solution
Use an API to render HTML as an image. You design the card once as HTML/CSS, then generate unique images for each post by swapping in the title and metadata.
import requests
def generate_card(title, author="My Blog", theme="dark"):
html = f"""
<div style="width:1200px;height:630px;display:flex;align-items:center;
justify-content:center;background:{"#1a1a2e" if theme == "dark" else "#fff"};
color:{"#fff" if theme == "dark" else "#1a1a2e"};font-family:system-ui;
padding:60px;box-sizing:border-box;">
<div>
<h1 style="font-size:52px;margin:0 0 20px 0;">{title}</h1>
<p style="font-size:24px;opacity:0.7;">by {author}</p>
</div>
</div>"""
resp = requests.post("https://rendly-api.fly.dev/api/v1/images",
headers={"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"},
json={"html": html, "width": 1200, "height": 630, "format": "png"})
return resp.json()["image_url"]
That's it. Call generate_card("My Post Title") and you get a PNG URL back.
Make It Better
The HTML is just a string. You can go wild:
- Add gradients, patterns, or background images
- Include your logo
- Show reading time, date, tags
- Use different layouts per category
# Gradient background version
html = f"""
<div style="width:1200px;height:630px;display:flex;align-items:center;
justify-content:center;
background:linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color:#fff;font-family:system-ui;padding:60px;box-sizing:border-box;">
<div>
<p style="font-size:18px;text-transform:uppercase;letter-spacing:3px;
opacity:0.8;margin:0 0 20px 0;">✨ {category}</p>
<h1 style="font-size:48px;margin:0 0 24px 0;line-height:1.1;">{title}</h1>
<p style="font-size:20px;opacity:0.7;">{date} · {reading_time} min read</p>
</div>
</div>"""
Automate It
Hook this into your blog's build process:
import json, os
posts = json.load(open("posts.json"))
for post in posts:
image_url = generate_card(post["title"], theme="dark")
post["og_image"] = f"https://rendly-api.fly.dev{image_url}"
print(f"✅ Generated card for: {post["title"]}")
# Update your posts with the new og:image URLs
json.dump(posts, open("posts.json", "w"), indent=2)
Now every post gets a unique, styled preview image — automatically.
Try It Live
You can test this right now without signing up: Rendly Playground
Paste in your HTML, hit render, see the result. The free tier gives you 100 renders/month.
I built Rendly because I was tired of manually creating OG images. It's a simple API — send HTML, get an image back. Try the playground or grab a free API key.
Top comments (0)