HTML to Image API: Convert Any HTML Template to a PNG in One Request
You need to generate images dynamically. Not screenshots of existing pages — images from HTML templates you control.
Think about it:
- OG social cards — generate a unique preview image for every blog post, product, or page
- Email header images — personalized images with user names, dates, or stats
- Certificates — render diplomas, badges, or achievement cards with dynamic data
- Dynamic badges — GitHub stats, contributor badges, live metrics as images
- Invoice thumbnails — preview of what a PDF will look like before sending
You could build this with Puppeteer, but that's overkill. You don't need a full browser. You just need HTML → PNG.
An HTML-to-image API solves this in one request.
The Problem: Building Image Generation In-House
Option 1: Self-hosted Puppeteer
const puppeteer = require('puppeteer');
async function generateImage(htmlString) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Set viewport for the image size you want
await page.setViewport({ width: 1200, height: 630 });
// Set HTML content
await page.setContent(htmlString);
// Wait for fonts and images to load
await page.waitForTimeout(500);
// Take screenshot
const screenshot = await page.screenshot({ type: 'png' });
await browser.close();
return screenshot;
}
Problems:
- You own the Chrome process (memory, crashes, updates)
- Slow (cold starts, process overhead)
- Hard to scale
- Can't run on shared hosting or serverless easily
- 500MB+ Docker images just for image generation
Option 2: HTML-to-Image API (PageBolt)
const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
html: `
<html>
<style>
body {
width: 1200px;
height: 630px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-family: Arial;
margin: 0;
}
h1 { font-size: 48px; margin: 0; }
p { font-size: 24px; margin-top: 10px; }
</style>
<body>
<div>
<h1>Blog Post Title</h1>
<p>By Author Name</p>
</div>
</body>
</html>
`
})
});
const { imageUrl } = await response.json();
console.log(imageUrl); // Ready to use
Advantages:
- One HTTP request
- No Chrome process to manage
- Instant scaling
- Works on serverless, shared hosting, anywhere
Real-World Examples
1. Dynamic OG Image Generator
Generate a unique social preview for every blog post:
async function generateOGImage(title, author, date) {
const html = `
<html>
<style>
body {
width: 1200px;
height: 630px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 60px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
color: white;
font-family: 'Segoe UI', Arial;
}
h1 { font-size: 56px; margin: 0 0 20px 0; line-height: 1.2; }
.meta { font-size: 20px; opacity: 0.9; }
.logo { font-size: 32px; margin-bottom: 40px; font-weight: bold; }
</style>
<body>
<div class="logo">YourBlog.com</div>
<h1>${title}</h1>
<div class="meta">${author} · ${date}</div>
</body>
</html>
`;
const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ html })
});
return (await response.json()).imageUrl;
}
// Usage
const ogImage = await generateOGImage(
'How to Build Scalable APIs',
'Jane Developer',
'Mar 24, 2026'
);
console.log(ogImage); // https://cdn.pagebolt.dev/...
2. Email Preview Image
Generate a preview of what the email will look like:
import requests
import json
def generate_email_preview(name, stats):
html = f"""
<html>
<style>
body {{
width: 600px;
height: 400px;
background: white;
padding: 40px;
box-sizing: border-box;
font-family: Arial;
color: #333;
}}
h1 {{ font-size: 32px; margin: 0 0 20px 0; }}
.stats {{
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-top: 40px;
}}
.stat {{
text-align: center;
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
}}
.stat-value {{ font-size: 28px; font-weight: bold; color: #667eea; }}
.stat-label {{ font-size: 14px; color: #999; margin-top: 5px; }}
</style>
<body>
<h1>Hello {name}!</h1>
<p>Here's your weekly summary:</p>
<div class="stats">
<div class="stat">
<div class="stat-value">{stats['views']}</div>
<div class="stat-label">Views</div>
</div>
<div class="stat">
<div class="stat-value">{stats['clicks']}</div>
<div class="stat-label">Clicks</div>
</div>
</div>
</body>
</html>
"""
response = requests.post('https://api.pagebolt.dev/take_screenshot', {
'headers': {'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json'},
'json': {'html': html}
})
return response.json()['imageUrl']
# Usage
preview_url = generate_email_preview('Jane', {'views': 1234, 'clicks': 567})
print(preview_url)
3. Achievement Badge Renderer
Generate badges for certifications or achievements:
async function generateBadge(achievement, earnedDate) {
const html = `
<html>
<style>
body {
width: 300px;
height: 300px;
background: radial-gradient(circle, #FFD700 0%, #FFA500 100%);
display: flex;
align-items: center;
justify-content: center;
margin: 0;
border-radius: 50%;
}
.badge-content {
text-align: center;
color: white;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.2));
}
h2 { margin: 0; font-size: 28px; font-family: Arial; }
p { margin: 5px 0 0 0; font-size: 14px; }
</style>
<body>
<div class="badge-content">
<h2>🏆</h2>
<h2>${achievement}</h2>
<p>${earnedDate}</p>
</div>
</body>
</html>
`;
const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ html, width: 300, height: 300 })
});
return (await response.json()).imageUrl;
}
// Usage
const badge = await generateBadge('Expert Developer', 'Mar 2026');
Feature Comparison: HTML-to-Image Solutions
| Feature | Self-Hosted Puppeteer | HTML-to-Image API (PageBolt) |
|---|---|---|
| Setup Time | Hours (install, Docker) | Minutes (API key) |
| Infrastructure | Your responsibility | Provider handles |
| Scaling | More servers needed | Automatic |
| CSS Support | Full modern CSS | Full modern CSS |
| SVG/Fonts | ✅ Supported | ✅ Supported |
| Templates | You manage | Simple HTML strings |
| Serverless | Difficult (500MB+) | Perfect fit |
| Cost (1000 images/month) | $50-100 (infra) | $10 (API) |
| Time to First Image | 30min–2hrs | 5 minutes |
Use Case Coverage
Perfect for:
- OG image generation (blog posts, products, pages)
- Email header/preview images
- Certificates and badges
- Dynamic user-generated content (stats cards, achievement badges)
- Invoice/receipt previews
- Live metrics dashboards as images
- Social media card generation
Not ideal for:
- Bulk screenshot capture (use screenshot API instead)
- Page testing (use take_screenshot API instead)
- Real-time page monitoring (use headless browser directly)
Getting Started
1. Create your HTML template
<html>
<style>
body { width: 1200px; height: 630px; /* set your dimensions */ }
</style>
<body>
<!-- Your content here -->
</body>
</html>
2. Send to the API
const response = await fetch('https://api.pagebolt.dev/take_screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ html: yourHtmlString })
});
const { imageUrl } = await response.json();
3. Use the image URL
Store it, serve it, embed it, whatever your use case needs.
Next Steps
- Try PageBolt free — 100 requests/month, no credit card. Generate your first OG image.
- Pick your use case — OG cards, email previews, badges, dynamic images. Start with one.
- Template library — Build a library of HTML templates you can reuse and customize.
Stop maintaining image generation infrastructure. Start generating images in one API call.
PageBolt: HTML to beautiful images, instantly. Get started free →
Top comments (0)