Lee este artículo en español.
HTML to Image: 6 Ways to Convert HTML to PNG or JPG (with Code)
Short answer: to turn HTML into an image you need something that draws it the way a browser does and then takes a picture. Inside a web page, use the html-to-image or html2canvas JavaScript libraries. On a server, open the HTML in headless Chrome with Puppeteer or Playwright and call
screenshot(). If you'd rather not run a browser yourself, send the HTML to an HTML to image API and get the PNG back in one request.
Converting HTML to an image is how most social cards, Open Graph images, certificates, tickets, receipts and email banners get made: you design once in HTML and CSS, fill in the data, and export a PNG, JPG or WebP. The hard part is never the idea. It's getting fonts, images and CSS to look exactly like they do in your browser, every time, without anything cut off.
This guide covers the six ways that actually work, with code you can copy, and when each one is the right choice.
Which method to pick
| Method | Runs on | Same as Chrome? | Best for |
|---|---|---|---|
| html-to-image | Visitor's browser | Almost | Downloads from your page |
| html2canvas | Visitor's browser | Almost | The same, older |
| Puppeteer | Your server | Yes | Node.js projects |
| Playwright | Your server | Yes | Python, Java, .NET or Node |
| html2image | Your computer | Yes | Quick Python scripts |
| An API | Someone else's server | Yes | No-code tools, no browser |
One method is missing on purpose: wkhtmltoimage (and Python's imgkit, which wraps it). It uses a very old browser engine, the project was archived in 2023, and modern CSS such as grid layouts often comes out broken. Avoid it for new projects.
1. In the browser: html-to-image
If the HTML is already on screen and you want the visitor to download it as an image, the html-to-image package does it without any server:
import { toPng } from 'html-to-image';
const node = document.getElementById('card');
const dataUrl = await toPng(node, { pixelRatio: 2 });
const link = document.createElement('a');
link.download = 'card.png';
link.href = dataUrl;
link.click();
There are also toJpeg, toSvg and toBlob. Things to know: images from another domain only appear if that server allows it (CORS), web fonts must have finished loading, and a few CSS effects can come out slightly different. It only works where there's a browser, so it doesn't help in a backend or an automation.
2. In the browser: html2canvas
html2canvas is the older, very popular alternative. It reads the page's CSS and redraws it on a canvas:
const canvas = await html2canvas(document.getElementById('card'), { scale: 2 });
const png = canvas.toDataURL('image/png');
Because it re-implements the drawing itself, CSS it doesn't support is simply skipped, so check complex designs carefully. Same limits as above with images from other domains.
3. On a server with Node.js: Puppeteer
When the image has to be made on a server (a card per new blog post, a certificate per student), you need a real browser. Puppeteer opens headless Chrome, loads your HTML and takes the screenshot:
import puppeteer from 'puppeteer';
const html = '<div style="font:700 48px sans-serif;padding:40px">Hello</div>';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1200, height: 630, deviceScaleFactor: 2 });
await page.setContent(html, { waitUntil: 'networkidle0' });
await page.screenshot({ path: 'card.png' });
await browser.close();
The result is exactly what Chrome shows. The price is running a browser on your server: memory for every page, updates, timeouts, and care with security if the HTML comes from users, because that browser can reach anything your server can reach.
4. In Python: Playwright or html2image
Playwright does the same from Python (pip install playwright, then playwright install chromium):
from playwright.sync_api import sync_playwright
html = "<div style='font:700 48px sans-serif;padding:40px'>Hello</div>"
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1200, "height": 630}, device_scale_factor=2)
page.set_content(html, wait_until="networkidle")
page.screenshot(path="card.png")
browser.close()
For a quick script on your own computer, the html2image package uses the Chrome or Edge you already have installed:
from html2image import Html2Image
hti = Html2Image(size=(1200, 630))
hti.screenshot(html_str="<h1>Hello</h1>", save_as="card.png")
5. In PHP, Java and .NET
The idea is the same in every language: drive a headless browser.
- PHP: Browsershot uses Puppeteer underneath, so it needs Node.js on the server:
Browsershot::html($html)->windowSize(1200, 630)->save('card.png'); - Java: Playwright for Java: load the HTML with
page.setContent(html)and save it withpage.screenshot(...). - .NET: Playwright for .NET or PuppeteerSharp, with the same two steps.
6. With an API: no browser to run
An HTML to image API runs the browser for you: you send the HTML, it sends back the image. It's the practical option when you work in a no-code tool, when you don't want to keep Chrome running on a server, or when you only need a few images a day.
With Cofferdock, one request is enough:
curl -X POST "https://api.cofferdock.com/capture?width=1200&height=630" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: text/html" \
--data-binary "<h1 style='font-family:sans-serif'>Hello</h1>" \
-o card.png
The same from Python, sending the options as JSON:
import requests
r = requests.post(
"https://api.cofferdock.com/capture",
headers={"x-api-key": "YOUR_KEY"},
json={"html": "<h1>Hello</h1>", "width": 1200, "height": 630, "format": "png", "output": "binary"},
)
open("card.png", "wb").write(r.content)
What to know before choosing it: it returns PNG, JPEG or WebP up to 3840 x 2160 pixels (or the full page height), web fonts and images from the internet load fine, and wait_ms waits up to 5 seconds for them. It does not run JavaScript, so a chart drawn by a script needs one of the methods above, or a chart made by another API. Each image uses 1 credit; the free plan includes 50 a month, and you can try it without an account first.
In n8n, Make or Zapier it's one HTTP step: see the guides for n8n, Make and Zapier.
Common problems (whatever the method)
- The font looks different. The web font hadn't loaded yet. Wait for the network to go quiet (
networkidle) or add a short wait. - Images are missing. In the browser libraries it's usually CORS; on a server, the image hadn't finished loading.
- The image is blurry. Render at double resolution:
pixelRatio: 2,scale: 2ordeviceScaleFactor: 2. - Part of the design is cut off. The window is smaller than the design: set the width and height, or capture the full page.
- Emoji or accents come out as squares. Servers, especially Linux containers, often lack those fonts. Install them, or load a web font that includes them.
- The HTML comes from your users. Don't render it in a browser that can reach your internal network: block private addresses first.
FAQ
What's the easiest way to convert HTML to an image? Without code, an HTML to image API or its online demo. With code inside a web page, the html-to-image library. On a server, Puppeteer or Playwright.
Can I convert HTML to an image without a browser? Not reliably. Something has to understand the CSS and draw it. Libraries that don't use a browser only support a small part of CSS, and APIs simply run the browser for you.
Is html-to-image the same as html2canvas? No. Both run in the visitor's browser, but html-to-image copies the element into an SVG and lets the browser draw it, while html2canvas redraws it on a canvas by itself. html-to-image tends to look closer to the original.
PNG, JPG or WebP? PNG for text, logos and sharp edges. JPG for photos, when file size matters more. WebP is lighter than both, but check that wherever you'll use the image accepts it.
How do I convert HTML to an image in n8n? With an HTTP Request node that sends the HTML to an API and returns the file. Step by step, with a free workflow to import: HTML to image in n8n.
Related guides
- HTML to image in n8n, in Make and in Zapier
- htmlcsstoimage alternative: when Cofferdock makes sense and when it doesn't
- How to take a full-page screenshot of a website
Full reference with every option: HTML to image API. No account yet? Create one for free.