Render HTML and Markdown into social cards and receipts

A template, a few fields of data and one call give you a PNG that looks exactly like your brand. The hard parts are escaping, sizing and not rendering the same card twice.

Paste a link to a blog post into Slack, LinkedIn or iMessage and the preview is an image chosen by the page's og:image tag. If you have one generic image for the whole site, every share looks the same and nobody can tell your posts apart. If each post has its own card with its title on it, people click.

Nobody designs those cards by hand for five hundred pages. You write one HTML template, fill it with each page's data, and render it to a PNG. The same trick produces order confirmations for messaging apps that will not display HTML, weekly summary images for a team chat, and certificate-style badges. Two APIs do the rendering: HTML to Image takes HTML, and Markdown to Image takes Markdown and styles it for you.

Your first card

htmltoimage is a POST with a JSON body. html is required. width and height set the viewport in pixels (defaults 1280 by 800), and format picks the output. Open Graph cards are conventionally 1200 by 630, which is a 1.91:1 ratio most platforms crop cleanly.

Try it liveHTML to Image20 credits
POSThttps://api.apiverve.com/v1/htmltoimage
curl -X POST "https://api.apiverve.com/v1/htmltoimage" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<div style='width:1200px;height:630px;display:flex;align-items:center;padding:0 80px;box-sizing:border-box;background:#0f172a;color:#fff;font:700 64px sans-serif'>Invoice #1042 is paid</div>","width":1200,"height":630}'
Sign in or create a free account to run this with your own key.

Open downloadURL to see the card. width, height and htmlLength echo back what was rendered.

The response gives you everything you need to use or verify the result:

FieldWhat it tells you
downloadURLWhere to fetch the image. Temporary.
expiresWhen that link dies, as a Unix timestamp in milliseconds (about two days out).
formatThe format you actually got.
width, heightThe dimensions that were rendered.
htmlLengthHow many characters of HTML were received.
imageNameThe generated file name.

Read format, width and height back rather than assuming. Custom dimensions and a non-PNG format are paid-plan options; on a plan without them you get the 1280 by 800 PNG default, and a card designed for 1200 by 630 will render with empty space. format accepts png and jpeg (jpg is treated as jpeg). Asking for webp currently gives you a PNG, which you will only notice if you check data.format.

htmlLength is more useful than it looks. If it is much smaller than the string you built, something truncated your template before it was sent, usually a templating bug or a proxy limit. Logging it next to the length you sent is a one-line sanity check.

Design the template for a fixed canvas

A web page flows; an image does not. The viewport is exactly width by height, and anything outside it is cut off. That changes how you write the HTML.

Size the root element explicitly. Give your outer element the same pixel dimensions you pass as width and height, use box-sizing: border-box, and lay the content out with flexbox or grid inside it. Percentages of an unknown body are how you end up with a card that is 80% white margin.

Make the HTML self-contained. Put the CSS in a <style> block or inline attributes. A stylesheet or font that loads from another server is one more thing that can be slow or missing at render time, and a missing font silently falls back to a default face. If brand typography matters, embed the font as a data URI or accept a carefully chosen system font stack.

Plan for long text. Titles vary from "Pricing" to "How we cut our cold-start latency by 70% on Cloud Run without minimum instances". Clamp lines with CSS (display: -webkit-box; -webkit-line-clamp: 3; overflow: hidden) and pick a font size that survives the worst title in your data. Better still, shrink the font for long titles in your own code before you render.

Render at the size it will be displayed. Social platforms downscale. Text that is 18 px in a 1200-pixel card is unreadable in a phone feed. Headline text on a card should be at least 48 px.

Check yourself

Your card template uses `<body style='margin:0'>` and a title div with `width: 80%`. Cards come out with the text squeezed into the top-left corner and a lot of empty space. What is the most reliable fix?

Answer the check above to continue.

Run every example on your own key. Free plan, no card.

Scaling up?

Volume pricing, custom SLAs, and dedicated support for high-traffic teams.

Contact sales