Convert HTML to Image API: Render Dynamic Cards and Templates in One Call
You have HTML. You need it as an image. One API call — no Chromium, no browser lifecycle, no infrastructure. Email previews, OG cards, certificates, notification images.
You have HTML. You need it as an image. You could spin up a headless browser, manage Chromium, scale infrastructure. Or you could make one API call.
Why HTML-to-Image?
- Email templates — render HTML emails as preview images for QA before sending
- Dynamic social cards — generate unique OG images for each article or product
- Certificate generation — diploma templates rendered as pixel-perfect images
- Notification cards — Slack, Discord, webhook payloads with visual previews
- Receipts and invoices — HTML invoice → image → PDF pipeline
The problem: Puppeteer + Chromium = infrastructure overhead. PageBolt removes that entirely.
JavaScript: One Function
async function htmlToImage(htmlString, options = {}) {
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: htmlString,
format: options.format || 'png',
width: options.width || 1280,
height: options.height || 720,
}),
});
if (!response.ok) throw new Error(`API error: ${response.statusText}`);
return response.arrayBuffer();
}
// Render an email template
const emailTemplate = `
<div style="font-family: Arial; padding: 20px; background: #f5f5f5;">
<h1>Order Confirmation</h1>
<p>Your order #12345 has been confirmed.</p>
<p><strong>Total:</strong> $99.99</p>
</div>
`;
const imageBuffer = await htmlToImage(emailTemplate);
fs.writeFileSync('order-confirmation.png', Buffer.from(imageBuffer));
No browser management. No Chromium. One API call.
Python
import requests, os
def html_to_image(html_string, format='png', width=1280, height=720):
response = requests.post(
'https://pagebolt.dev/api/v1/screenshot',
headers={
'x-api-key': os.getenv('PAGEBOLT_API_KEY'),
'Content-Type': 'application/json',
},
json={'html': html_string, 'format': format, 'width': width, 'height': height}
)
if response.status_code != 200:
raise Exception(f"API error: {response.status_code}")
return response.content
# Certificate template
certificate_html = """
<div style="width:800px;height:600px;border:3px solid gold;padding:40px;
text-align:center;font-family:serif;background:linear-gradient(to bottom,#fff9e6,#fffdf0)">
<h1>Certificate of Completion</h1>
<p style="font-size:18px;margin-top:40px">This certifies that</p>
<h2>Jane Doe</h2>
<p>Has successfully completed Advanced Python Programming</p>
<p style="margin-top:40px">March 28, 2026 — Verified ✓</p>
</div>
"""
with open('certificate.png', 'wb') as f:
f.write(html_to_image(certificate_html))
Real-World: Dynamic Email Preview Cards
Render email templates before sending to catch layout issues:
async function previewEmailTemplate(templateHtml, recipientName) {
const personalized = templateHtml.replace('{{name}}', recipientName);
return htmlToImage(personalized, { width: 600, height: 800 });
}
const template = `
<div style="font-family:'Helvetica Neue',sans-serif;max-width:600px">
<h2>Hello {{name}},</h2>
<p>Your order is on the way.</p>
</div>
`;
const preview = await previewEmailTemplate(template, 'Alice');
// Send to QA team for review before email blast
Batch: 100 Personalized Images in Parallel
const certificates = Array.from({ length: 100 }, (_, i) => `
<div style="text-align:center;padding:40px;border:2px solid gold">
<h1>Certificate #${i + 1}</h1>
<p>Awarded to User ${i + 1}</p>
</div>
`);
const images = await Promise.all(certificates.map(html => htmlToImage(html)));
// All 100 rendered in parallel — ~800ms total
Cost: 100 images = 100 API requests ≈ $5–10/month on the Growth plan. Self-hosted Chromium = $200–500/month infrastructure + developer time.
Supported Rendering Features
| Feature | Supported |
|---|---|
| CSS: Flexbox, Grid, Gradients, Shadows | ✓ |
| Google Fonts, @font-face | ✓ |
| JavaScript execution (final frame) | ✓ |
| Inline base64 images | ✓ |
| SVG (inline or external) | ✓ |
| Custom dimensions (any width/height) | ✓ |
| Formats: PNG, JPEG, WebP | ✓ |
| Transparent background (PNG) | ✓ |
Limitations
- External images — use base64 data URIs for guaranteed loading
- Single-frame capture — animations render as the final frame
- No interactivity — can't simulate clicks (use
/sequencefor that) - 30-second timeout — page load must complete within 30s
Getting Started
- Sign up — Free tier: 100 requests/month, no credit card
- Set your API key —
PAGEBOLT_API_KEY=your_key - Copy the JS or Python example above — it works as-is
- Render your first template — HTML → PNG in one call
No infrastructure. No browser management. Just HTML → Image.
Convert HTML to image — free
100 requests/month, no credit card. Email previews, OG cards, certificates — any HTML string to PNG in one API call.
Get API key free →