HTML to Image API: Convert HTML/CSS to PNG or JPEG
February 19, 2026 · 10 min read
Need to turn HTML and CSS into an image? Whether you're generating social media cards, invoices, certificates, email headers, or dynamic OG images, an HTML to image API handles the rendering so you don't have to run your own headless browser.
This guide covers every approach: self-hosted libraries, hosted APIs, and when to use each. With working code examples in Node.js, Python, and cURL.
Why convert HTML to images?
HTML and CSS give you pixel-perfect control over layout, typography, and colors. But many platforms only accept images:
- Social media cards - Twitter/X, LinkedIn, and Facebook all display OG images. Generate them dynamically from HTML templates.
- Invoices and receipts - Render HTML invoices as images or PDFs for email attachments.
- Certificates - Generate personalized certificates with names, dates, and custom designs.
- Email headers - Complex layouts that look consistent across email clients.
- Data visualizations - Turn charts, dashboards, or reports into shareable images.
- Marketing materials - Product cards, pricing tables, feature comparisons as images.
Approach 1: Self-hosted with Puppeteer
Run headless Chrome on your own server. Full control, but you manage the infrastructure.
const puppeteer = require('puppeteer');
async function htmlToImage(html) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Set the HTML content directly
await page.setContent(html, { waitUntil: 'networkidle0' });
// Capture the rendered output
const screenshot = await page.screenshot({
type: 'png',
fullPage: true
});
await browser.close();
return screenshot;
}
// Usage
const html = `
<div style="width:1200px;height:630px;background:linear-gradient(135deg,#667eea,#764ba2);
display:flex;align-items:center;justify-content:center;font-family:Inter,sans-serif">
<h1 style="color:white;font-size:48px">Hello World</h1>
</div>`;
const image = await htmlToImage(html);
fs.writeFileSync('output.png', image);
Downsides of self-hosting
- Chrome eats 200-500MB of RAM per instance
- Browser crashes, zombie processes, memory leaks
- Font installation and management on the server
- Cold starts add 2-5 seconds per request
- Scaling means running more Chrome instances
Approach 2: Screenshot API (recommended for production)
A hosted API handles the browser infrastructure. You send a URL or HTML, get an image back. No servers to manage.
GrabShot handles this for you
25 free screenshots per month. Full browser rendering with custom viewports, wait conditions, and format options. Get your free API key →
Node.js
const axios = require('axios');
const response = await axios.get('https://grabshot.dev/v1/screenshot', {
params: {
url: 'https://your-html-template.com/card?name=John',
width: 1200,
height: 630,
format: 'png'
},
headers: { 'X-API-Key': 'your-api-key' },
responseType: 'arraybuffer'
});
fs.writeFileSync('card.png', response.data);
Python
import requests
response = requests.get('https://grabshot.dev/v1/screenshot', params={
'url': 'https://your-html-template.com/card?name=John',
'width': 1200,
'height': 630,
'format': 'png'
}, headers={'X-API-Key': 'your-api-key'})
with open('card.png', 'wb') as f:
f.write(response.content)
cURL
curl "https://grabshot.dev/v1/screenshot?url=https://example.com&width=1200&height=630&format=png" \
-H "X-API-Key: your-api-key" \
--output card.png
Approach 3: Client-side libraries
Libraries like html2canvas and dom-to-image run in the browser. They're useful for "save as image" features but have significant limitations:
- Don't support all CSS features (no
backdrop-filter, limitedgridsupport) - Custom fonts often don't render
- SVG and cross-origin images can fail
- Output quality varies between browsers
- Can't run server-side or in CI/CD pipelines
For production use cases where consistency matters, a real browser engine (Puppeteer or a screenshot API) gives you pixel-perfect results every time.
Common use case: Dynamic OG images
One of the most popular HTML to image use cases is generating Open Graph images for social media. Here's a pattern that works:
- Create an HTML template with CSS for your card design
- Host it as a route (e.g.,
/og?title=My+Post&author=Jane) - Use a screenshot API to render it at 1200x630
- Cache the result and serve it as your
og:image
// Express route that generates OG images on the fly
app.get('/og-image/:slug', async (req, res) => {
const post = await getPost(req.params.slug);
const imageUrl = `https://grabshot.dev/v1/screenshot?` +
`url=${encodeURIComponent(`https://mysite.com/og-template?title=${post.title}`)}&` +
`width=1200&height=630&format=png`;
const img = await fetch(imageUrl, {
headers: { 'X-API-Key': process.env.GRABSHOT_KEY }
});
res.set('Content-Type', 'image/png');
res.set('Cache-Control', 'public, max-age=86400');
res.send(Buffer.from(await img.arrayBuffer()));
});
Read our full guide on automating OG image generation for more details.
API comparison: HTML to image services
| Service | Free tier | Paid from | HTML input |
|---|---|---|---|
| GrabShot | 25/mo | $9/mo | URL + raw HTML |
| ScreenshotOne | 100/mo | $29/mo | URL + raw HTML |
| Urlbox | 7-day trial | $39/mo | URL + raw HTML |
| APIFlash | 100/mo | $7/mo | URL only |
See it in action
Try GrabShot right now — paste any URL and get a screenshot instantly. No signup needed.
Try Free Screenshot Tool →