DEV Community

Mack
Mack

Posted on

How to Convert HTML to an Image (PNG/JPG) with an API

You've got HTML. You need a PNG. Maybe it's a certificate, a receipt, a social media card, or a report that needs to look exactly the same in every email client.

The browser renders HTML beautifully. The problem is getting that rendering out of the browser and into an image file.

Let's fix that.

The Options

Option 1: Headless browser yourself — Install Puppeteer/Playwright, manage Chrome binaries, handle fonts, timeouts, memory leaks, and Docker configs. Works, but it's a lot.

Option 2: Use an API — Send HTML, get an image back. Done in one HTTP call.

We're going with Option 2.

The API Call

Here's the simplest version using curl:

curl -X POST "https://rendly-api.fly.dev/api/v1/html" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<div style=\"padding:40px;font-family:sans-serif;background:#1a1a2e;color:#eee\"><h1>Hello, World!</h1><p>This is an image now.</p></div>",
    "width": 800,
    "height": 400,
    "format": "png"
  }' --output hello.png
Enter fullscreen mode Exit fullscreen mode

That's it. You send HTML, you get a PNG.

Node.js Example

const response = await fetch('https://rendly-api.fly.dev/api/v1/html', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    html: `
      <div style="padding: 40px; background: linear-gradient(135deg, #667eea, #764ba2); color: white; font-family: system-ui;">
        <h1 style="margin: 0;">Invoice #1042</h1>
        <p>Amount: $2,400.00</p>
        <p>Status: Paid ✓</p>
      </div>
    `,
    width: 600,
    height: 300,
    format: 'png',
  }),
});

const buffer = await response.arrayBuffer();
fs.writeFileSync('invoice.png', Buffer.from(buffer));
Enter fullscreen mode Exit fullscreen mode

Python Example

import requests

resp = requests.post(
    "https://rendly-api.fly.dev/api/v1/html",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "html": """
        <div style="padding:40px; background:#0f0c29; color:#fff; font-family:monospace;">
            <h2>Deploy Report</h2>
            <p>✅ 47 tests passed</p>
            <p>🚀 Deployed to production</p>
            <p>📦 v2.4.1</p>
        </div>
        """,
        "width": 600,
        "height": 300,
        "format": "png",
    },
)

with open("report.png", "wb") as f:
    f.write(resp.content)
Enter fullscreen mode Exit fullscreen mode

Ruby Example

require "net/http"
require "json"

uri = URI("https://rendly-api.fly.dev/api/v1/html")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = {
  html: '<div style="padding:40px;background:#2d3436;color:#dfe6e9;font-family:Georgia"><h1>Certificate of Completion</h1><p>Awarded to: Jane Developer</p></div>',
  width: 800,
  height: 400,
  format: "png"
}.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
File.write("certificate.png", res.body)
Enter fullscreen mode Exit fullscreen mode

Real Use Cases

  • Certificates — Templated HTML, unique per recipient, pixel-perfect every time
  • Receipts/Invoices — Email clients mangle HTML; images don't break
  • Social cards — Dynamic OG images for blogs, products, user profiles
  • Reports — Dashboards → shareable images for Slack/email
  • Email banners — Design in HTML/CSS, render to image, embed anywhere

Why Not Just Screenshot a URL?

You can! But HTML-to-image is better when:

  • You don't have a hosted URL (the HTML is generated dynamically)
  • You need it fast (no page load, no network requests, no waiting for fonts)
  • You want full control over the viewport and rendering

Get Started

Rendly gives you 100 free renders per month. Sign up, grab your API key, and start converting HTML to images in under a minute.

No credit card. No headless browser. No Docker. Just HTML in, image out.


Building something cool with HTML-to-image? Drop a comment — I'd love to see it.

Top comments (0)