How to Convert HTML to Images with a Free API
How to Convert HTML to Images with a Free API
Need to turn HTML into an image? Maybe you're generating social cards, email headers, invoices, or badges. The typical approach — spin up Puppeteer, render HTML in a headless browser, take a screenshot — is slow to set up and painful to maintain in production.
The HTML to Image API does this in one POST request. Send HTML, get an image back.
Quick Start
curl -X POST "https://hermesforge.dev/api/html2image" \
-H "Content-Type: application/json" \
-d '{
"html": "<div style=\"padding:40px;background:#1a1a2e;color:#e94560;font-family:sans-serif;font-size:48px;text-align:center\">Hello World</div>",
"width": 800,
"height": 200,
"format": "png"
}' --output hello.png
That's it. No API key required for basic usage. The response is the raw image bytes.
Python: Generate Dynamic Images
import requests
def html_to_image(html, filename, width=800, height=600, fmt="webp"):
"""Convert HTML string to an image file."""
response = requests.post(
"https://hermesforge.dev/api/html2image",
json={
"html": html,
"width": width,
"height": height,
"format": fmt,
}
)
with open(filename, "wb") as f:
f.write(response.content)
print(f"Saved {filename} ({len(response.content)} bytes)")
# Example: status badge
html_to_image(
'<div style="display:inline-flex;align-items:center;gap:8px;padding:6px 12px;'
'background:#2d333b;border-radius:6px;font-family:monospace;font-size:14px;color:#adbac7">'
'<span style="width:8px;height:8px;border-radius:50%;background:#3fb950"></span>'
'All systems operational</div>',
"status.webp",
width=300,
height=40,
)
Use Case: Social Cards from Templates
Generate unique social/OG images for every blog post without a design tool:
def social_card(title, author, bg_color="#667eea"):
"""Generate a 1200x630 social card."""
html = f"""
<div style="width:1200px;height:630px;display:flex;align-items:center;
justify-content:center;background:linear-gradient(135deg,{bg_color},#764ba2);
font-family:-apple-system,sans-serif;color:white;text-align:center">
<div>
<h1 style="font-size:52px;margin:0 60px 20px">{title}</h1>
<p style="font-size:22px;opacity:0.8">by {author}</p>
</div>
</div>"""
return requests.post(
"https://hermesforge.dev/api/html2image",
json={"html": html, "width": 1200, "height": 630, "format": "png"}
).content
# Generate cards for all posts
posts = [
("How We Cut API Latency by 80%", "Alice"),
("Migrating to Postgres 17", "Bob"),
]
for title, author in posts:
filename = title.lower().replace(" ", "-")[:40] + ".png"
with open(filename, "wb") as f:
f.write(social_card(title, author))
This replaces tools like Cloudinary's text overlay API or Vercel's @vercel/og — but works with any stack, not just Next.js.
Use Case: Invoices and Receipts
def generate_invoice(items, total):
rows = "".join(
f'<tr><td style="padding:8px;border-bottom:1px solid #eee">{name}</td>'
f'<td style="padding:8px;border-bottom:1px solid #eee;text-align:right">${price:.2f}</td></tr>'
for name, price in items
)
html = f"""
<div style="padding:40px;font-family:-apple-system,sans-serif;background:white;color:#333">
<h1 style="color:#1a1a2e;margin-bottom:30px">Invoice</h1>
<table style="width:100%;border-collapse:collapse">
<tr style="border-bottom:2px solid #333">
<th style="text-align:left;padding:8px">Item</th>
<th style="text-align:right;padding:8px">Amount</th>
</tr>
{rows}
<tr>
<td style="padding:12px 8px;font-weight:bold;font-size:18px">Total</td>
<td style="padding:12px 8px;text-align:right;font-weight:bold;font-size:18px">${total:.2f}</td>
</tr>
</table>
</div>"""
return requests.post(
"https://hermesforge.dev/api/html2image",
json={"html": html, "width": 600, "height": 400, "format": "png", "background": "#ffffff"}
).content
Parameters
| Parameter | Default | Description |
|---|---|---|
html |
required | HTML string to render |
width |
800 | Image width in pixels (max 1920) |
height |
600 | Image height in pixels (max 1080) |
format |
png |
png, jpeg, or webp |
scale |
1 | Retina scaling: 1, 2, or 3 |
background |
transparent | CSS color for background |
quality |
80 | JPEG/WebP quality (1-100) |
Tips
- Use
scale: 2for retina-quality images. The output is 2x the specified dimensions — great for social cards that need to look sharp on high-DPI screens. - WebP saves bandwidth:
format: "webp"produces files ~40-60% smaller than PNG with no visible quality loss. - Set background explicitly: If your HTML has a transparent background, the default output is transparent PNG. Set
background: "#ffffff"if you need a white background. - Full CSS support: The HTML is rendered in Chromium, so modern CSS (flexbox, grid, gradients, custom fonts via
@import) all works.
vs. Screenshot API
Both endpoints produce images, but they serve different purposes:
| HTML to Image | Screenshot API | |
|---|---|---|
| Input | Raw HTML string | URL to capture |
| Use case | Generate images from templates | Capture existing web pages |
| Hosting | No hosting needed | Page must be accessible via URL |
| Speed | Faster (no network fetch) | Depends on page load time |
If you're generating images from data (cards, badges, invoices), use HTML to Image. If you're capturing an existing webpage, use the Screenshot API.
Getting Started
No signup needed. Just POST your HTML:
POST https://hermesforge.dev/api/html2image
Content-Type: application/json
{"html": "<h1>Your HTML here</h1>"}
Free tier: 10 requests/day without an API key, 50/day with a free key.