Generate images from HTML templates using a headless browser.
Carta renders HTML content in a headless Chrome/Chromium browser and captures it as a JPEG image. A pool of warm browser instances is managed automatically, so repeated renders avoid cold-start overhead.
Use cases: Open Graph images, social media cards, email banners, certificates, invoices, badges — anything you can build with HTML and CSS.
Add carta to your list of dependencies in mix.exs:
def deps do
[
{:carta, "~> 0.1.0"}
]
endCarta requires Chrome or Chromium to be installed on the system. It will auto-detect common installation paths, or you can configure it explicitly:
# config/config.exs
config :carta,
pool_size: 4, # number of warm Chrome instances (default: 2)
chrome_path: "/usr/bin/chromium" # auto-detected if omittedhtml = """
<html>
<style>
body { background: linear-gradient(135deg, #667eea, #764ba2); display: flex;
align-items: center; justify-content: center; width: 1200px; height: 630px; }
h1 { color: white; font-size: 48px; font-family: sans-serif; }
</style>
<body>
<h1>Hello, Carta!</h1>
</body>
</html>
"""
{:ok, jpeg_binary} = Carta.render(html){:ok, jpeg_binary} = Carta.render({:template, "templates/card.html.eex",
title: "My Blog Post",
author: "Jane Doe"
})Since it's a full browser, everything works — Google Fonts via <link>, flexbox, grid, images, SVG, etc.
| Option | Default | Description |
|---|---|---|
:width |
1200 |
Viewport width in pixels |
:height |
630 |
Viewport height in pixels |
:quality |
90 |
JPEG quality (1-100) |
Rendering is expensive. Use Carta.cache_key/2 to derive a stable hash from the input and options, then cache the result in your own store:
key = Carta.cache_key({:template, "card.html.eex", title: "My Post"})
case MyCache.get(key) do
nil ->
{:ok, jpg} = Carta.render({:template, "card.html.eex", title: "My Post"})
MyCache.put(key, jpg)
jpg
cached ->
cached
endMIT License - see LICENSE for details.