# OG Image Generator API — Social Preview Images from Templates (`reverend_sal/og-image-generator`) Actor

Generate Open Graph, Twitter/X, LinkedIn, Instagram and Pinterest images from 8 templates or your own HTML/CSS with {{variables}}. Batch hundreds per run, emoji and any language (CJK, Arabic, Cyrillic), PNG/JPEG/WebP, public URLs. Pay per image.

- **URL**: https://apify.com/reverend_sal/og-image-generator.md
- **Developed by:** [North Eng](https://apify.com/reverend_sal) (community)
- **Categories:** Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 images

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## OG Image Generator API — Social Preview Images from Templates or HTML

Generate **Open Graph, Twitter/X, LinkedIn, Instagram and Pinterest images** in bulk. Pick one of 8 designer templates and fill in the fields, or send your own **HTML/CSS with {{variables}}**. Each image is saved with a public URL and listed as one dataset row. You pay only for images that were created.

![Examples rendered by this Actor: blog post, gradient, product, code repository, quote, event, photo and minimal templates](https://api.apify.com/v2/key-value-stores/yKLfOOqzSplOo987v/records/templates.png?signature=zohfIEgqzwtiSImTz8z9)

### What it does

- **8 templates** that look good out of the box: `blog-post`, `gradient`, `product`, `github-repo`, `quote`, `event`, `photo`, `minimal`. Each one adapts to landscape, square and portrait sizes.
- **Your own HTML** instead: write a design once with `{{title}}`, `{{price}}` or any other variable, then render it for hundreds of rows.
- **Batch mode**: one run renders a list of up to 10,000 items. Each item can override any setting (template, colors, size, format…).
- **Every size**: `og` 1200×630 (default), `twitter`, `linkedin`, `facebook`, `instagram-square`, `instagram-portrait`, `instagram-story`, `pinterest`, `youtube-thumbnail`, or any custom width and height from 100 to 4096 px. Use `scale` 2 or 3 for retina output.
- **PNG, JPEG or WebP**, with a quality setting.
- **Any language and emoji**. Fonts for Latin, Cyrillic, Greek, Vietnamese, Arabic, Hebrew, Hindi (Devanagari), Thai, Chinese, Japanese and Korean, plus color emoji, are built in. Arabic and Hebrew are shaped and laid out right to left.
- **Any Google Font** by name (for example `"Lobster"` or `"Roboto Slab"`). It is downloaded automatically.
- **Text always fits**: long titles shrink, and lines are balanced. Text that still doesn't fit ends with "…" instead of overflowing.

![The same templates with Russian, Japanese, Arabic, Chinese, Korean, Hebrew, Hindi and Thai titles](https://api.apify.com/v2/key-value-stores/yKLfOOqzSplOo987v/records/languages.png?signature=h7lsjG3I500dFiyXZywV)

### Why use it

- **Fast.** One browser stays warm for the whole run and renders many cards in parallel, while finished images upload in the background. Fonts are loaded once, and pages never wait on fixed timers. In our Apify tests, 500 mixed 1200×630 cards took about 50 seconds at 4 GB of memory and about 15 seconds at 8 GB.
- **Reliable.** A broken image URL, an invalid color or a font that doesn't exist never crashes the run. That image gets a clear warning, or an unpaid error row, and the rest of the batch continues. If a run is restarted, images that are already finished are kept and are not charged again.
- **Simple.** You don't need a template editor, an account on another service or an API key. Send JSON, get URLs.
- **Safe for untrusted input.** Your HTML is rendered with JavaScript off by default. Requests to private or internal network addresses are blocked.

### How to use

1. Choose a **template** and fill in **title** (plus subtitle, author, logo… as you like). Or paste your own **HTML**.
2. For many images, add **items**. Each item is one image, and plain strings work as titles: `["Post A", "Post B"]`.
3. Run the Actor. Open the dataset and click the image URLs, or call the API and read `imageUrl` from each row.

You can call it from code with the [Apify API](https://docs.apify.com/api/v2) or the `apify-client` package for JavaScript and Python. You can also use Make, Zapier or n8n: for example, generate a card whenever a CMS post is published.

### Input

Single image with a template:

```json
{
  "template": "blog-post",
  "title": "How we cut our image pipeline from 4 seconds to 40 ms",
  "subtitle": "A deep dive into page pools, font caching and fast encoders.",
  "eyebrow": "Engineering",
  "author": "Maya Chen",
  "authorTitle": "Staff Engineer",
  "date": "Oct 27, 2026",
  "siteName": "northwind.dev",
  "logoUrl": "https://example.com/logo.svg"
}
```

Batch: top-level fields are the defaults, and each item overrides them:

```json
{
  "template": "minimal",
  "siteName": "acme.blog",
  "format": "webp",
  "items": [
    "Plain strings become titles",
    { "title": "Items can override anything", "template": "gradient", "format": "jpeg", "size": "twitter" },
    { "title": "Square for Instagram", "size": "instagram-square", "template": "quote" },
    { "title": "Custom size, retina", "width": 800, "height": 418, "scale": 2, "fileName": "custom-2x" }
  ]
}
```

Your own HTML with variables. Values are HTML-escaped; use `{{{name}}}` for trusted raw HTML:

```json
{
  "html": "<div style=\"height:100vh;display:grid;place-content:center;background:{{bg}};color:#fff;font-family:Inter\"><h1 style=\"font-size:80px\">{{title}}</h1><p style=\"font-size:32px\">{{subtitle}}</p></div>",
  "bg": "#0f172a",
  "items": [
    { "title": "v2.4: faster builds", "subtitle": "Incremental caching is on by default" },
    { "title": "v2.5: dark mode 🌙", "subtitle": "Every screen, every theme", "bg": "#18181b" }
  ]
}
```

The main fields are listed below. The input tab documents all of them.

| Field | What it does |
|---|---|
| `template` | `blog-post` (default), `gradient`, `product`, `github-repo`, `quote`, `event`, `photo`, `minimal` |
| `title`, `subtitle`, `eyebrow`, `author`, `authorTitle`, `siteName`, `date`, `price`, `ctaText`, `tags`, `stats` | Template text |
| `logoUrl`, `avatarUrl`, `imageUrl`, `backgroundImageUrl` | Images (http(s) or `data:` URLs; PNG, JPEG, WebP, GIF, AVIF, SVG) |
| `theme`, `accentColor`, `secondaryColor`, `backgroundColor`, `textColor` | Colors: any CSS color (`#7c3aed`, `rgb()`, `hsl()`, `oklch()`, names) |
| `fontFamily`, `headingFontFamily` | A built-in font or any Google Fonts family |
| `size`, `width`, `height`, `scale` | Output size |
| `format`, `quality`, `fileName` | Output file |
| `html`, `css`, `variables`, `enableJavaScript` | Custom design mode |
| `items` | Batch: one image per item |

### Output

Each image is saved in the run's key-value store, and its public URL goes in one dataset row:

```json
{
  "index": 2,
  "template": "gradient",
  "size": "twitter",
  "format": "jpeg",
  "imageUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/og-0002-items-can-override-anything-61e07bce.jpg",
  "keyValueStoreKey": "og-0002-items-can-override-anything-61e07bce.jpg",
  "width": 1200,
  "height": 628,
  "scale": 1,
  "contentType": "image/jpeg",
  "fileSizeBytes": 43530,
  "durationMs": 41,
  "warnings": [],
  "error": null,
  "errorCode": null,
  "input": { "title": "Items can override anything", "siteName": "acme.blog", "template": "gradient", "theme": "auto" }
}
```

An item that can't be rendered still gets a row, with `error` and `errorCode` set (for example `INVALID_INPUT` or `MISSING_TITLE`) and no image. You are not charged for it. Problems that don't stop the image, such as a logo URL that returns 404 or an unknown font, are listed in `warnings`. The run summary (requested, images, failed, timings) is saved as `OUTPUT` in the key-value store.

### Pricing

Pay per image. Only images that were created successfully are charged:

| Event | Price |
|---|---|
| Image (one generated image, any template, size or format) | **$0.002** ($2 per 1,000) |
| Actor start | Apify default ($0.00005) |

Examples: 100 blog cards cost **$0.20**, and 1,000 product images cost **$2**. Failed items cost nothing. If you set a maximum cost per run, the Actor stops cleanly when it is reached and keeps the images it already made. If a run is restarted, images that were already charged are not charged again.

### FAQ

**How much memory should I use?** The default 1 GB is enough for a few dozen cards. For batches of hundreds or thousands of images, raise it to 4–8 GB in the run options: more memory renders more cards at once, so the run finishes much sooner.

**How is this different from a website screenshot tool?** This Actor doesn't visit URLs. It draws images from a template, or from HTML that you provide. That makes it faster and the results repeatable, with no cookie banners, logins or slow pages.

**Can I use my brand fonts and colors?** Yes. Set the color fields, and set `fontFamily` to any Google Fonts family. For a fully custom look, use `html` and `css`. A web font loaded with `@font-face` from a public URL works too.

**Do emoji and non-Latin languages work?** Yes. All fonts are bundled, so text never falls back to empty boxes. Emoji are drawn in color, and Arabic and Hebrew are shaped and right-aligned.

**What happens with a very long title?** It shrinks down to a readable minimum size, and if it still doesn't fit, it ends with "…". You get a warning in that row.

**My image URL is broken. Does the run fail?** No. The image is rendered without it and a warning names the field. Private or internal network addresses are blocked for safety.

**How long are image URLs available?** As long as the run's storage is kept (see your Apify data retention settings). To keep images longer, copy them to your own storage.

**Can it run JavaScript in my HTML?** Set `enableJavaScript` to true, for example for chart libraries. Pages still have a time limit, so an endless loop fails that image instead of hanging the run.

### Limitations

- Images are 100–4096 px per side. Up to 10,000 items per run (split bigger jobs into several runs).
- Animated output (GIF or video) is not supported.
- Custom HTML is one static frame. Anything loading from a slow external server can be cut off by the per-image time limit.

# Actor input Schema

## `template` (type: `string`):

Design to render. Every template adapts to landscape, square and portrait sizes. Ignored when you provide custom HTML.

## `title` (type: `string`):

Main text. Long titles shrink to fit; anything that still does not fit ends with "…". Emoji and any language work.

## `subtitle` (type: `string`):

Secondary text under the title (description, excerpt, location…).

## `eyebrow` (type: `string`):

Short label above the title: category, "New", event type, or the repository owner on the code repository template.

## `author` (type: `string`):

Shown with the avatar (or the author's initials when there is no avatar).

## `authorTitle` (type: `string`):

Shown under the author name, e.g. "Staff Engineer".

## `avatarUrl` (type: `string`):

Round author photo. http(s) or data:image URL; PNG, JPEG, WebP, GIF, AVIF or SVG.

## `siteName` (type: `string`):

Shown next to the logo.

## `logoUrl` (type: `string`):

Brand logo (transparent PNG or SVG works best).

## `date` (type: `string`):

Free text, shown as you write it, e.g. "Oct 27, 2026" or "Thu 18:00 CET".

## `imageUrl` (type: `string`):

Product photo (product), side image (blog post) or speaker photo (event).

## `backgroundImageUrl` (type: `string`):

Full-bleed background. On the photo template the text sits on a dark fade; on others the image is tinted with the background color so text stays readable.

## `price` (type: `string`):

Product template: price text, e.g. "$49" or "€19.90".

## `ctaText` (type: `string`):

Product and event templates: call-to-action button, e.g. "Shop now" or "Register".

## `tags` (type: `array`):

Up to 6 short tags (blog post and code repository templates).

## `stats` (type: `array`):

Code repository template: up to 4 numbers, e.g. \[{"value": "12.4k", "label": "stars"}, {"value": "TypeScript"}].

## `theme` (type: `string`):

Light or dark variant of the template's palette (auto = the template's own default).

## `accentColor` (type: `string`):

Highlights, buttons, gradient color 1. Example: "#7c3aed".

## `secondaryColor` (type: `string`):

Gradient color 2 and secondary decoration.

## `backgroundColor` (type: `string`):

Page background. The text color switches to light or dark automatically unless you set it.

## `textColor` (type: `string`):

Main text color.

## `fontFamily` (type: `string`):

Built in: Inter, Space Grotesk, Manrope, Outfit, Playfair Display, DM Serif Display, JetBrains Mono, Noto Sans. Any other Google Fonts family name (e.g. "Lobster", "Roboto Slab") is downloaded automatically. Unknown names fall back to the template font with a warning.

## `headingFontFamily` (type: `string`):

Optional separate font for the title (same rules as Font).

## `size` (type: `string`):

Output size preset. Width/height below override it.

## `width` (type: `integer`):

Overrides the preset width. 100–4096.

## `height` (type: `integer`):

Overrides the preset height. 100–4096.

## `scale` (type: `integer`):

2 or 3 renders a sharper (retina) image with 2× or 3× the pixels per side.

## `format` (type: `string`):

PNG (lossless, default), JPEG (smallest for photos) or WebP (small, sharp).

## `quality` (type: `integer`):

1–100. Ignored for PNG.

## `fileName` (type: `string`):

Optional readable part of the saved file's key, e.g. "launch-post". Keys always start with og-<index> and end with a short hash, so names never collide. Usually set per item in a batch.

## `items` (type: `array`):

One image per item. Each item can set any field above (title, template, colors, size, html…); missing fields come from the fields above. Plain strings are used as titles: \["Post one", "Post two"]. Up to 10,000 per run.

## `html` (type: `string`):

Your own design instead of a template. {{name}} is replaced with the HTML-escaped value of any field or variable (e.g. {{title}}), {{{name}}} inserts it unescaped. Built-in fonts, emoji and CJK/Arabic fallbacks are available; external images and stylesheets load too.

## `css` (type: `string`):

Extra CSS added to your HTML.

## `variables` (type: `object`):

Extra {{variables}} for the custom HTML, e.g. {"price": "$9", "badge": "NEW"}. Items can override them.

## `enableJavaScript` (type: `boolean`):

Off by default (faster, and pages cannot change themselves). Turn on if your HTML needs scripts to draw, e.g. charts.

## `lang` (type: `string`):

Optional BCP 47 tag (e.g. "ja", "ar") for language-specific line breaking.

## `maxConcurrency` (type: `integer`):

Pages rendered at once. 0 = automatic from the run memory.

## Actor input object example

```json
{
  "template": "gradient",
  "title": "Ship social images in seconds, not sprints 🚀",
  "subtitle": "Templates or your own HTML, any language, batches of hundreds.",
  "eyebrow": "Developer tools",
  "author": "Ada Lovelace",
  "siteName": "example.com",
  "theme": "auto",
  "size": "og",
  "scale": 1,
  "format": "png",
  "quality": 90,
  "items": [],
  "enableJavaScript": false,
  "maxConcurrency": 0
}
```

# Actor output Schema

## `images` (type: `string`):

One row per image with the image link, size, template and the input it was made from.

## `files` (type: `string`):

All image files in the key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "template": "gradient",
    "title": "Ship social images in seconds, not sprints 🚀",
    "subtitle": "Templates or your own HTML, any language, batches of hundreds.",
    "eyebrow": "Developer tools",
    "author": "Ada Lovelace",
    "siteName": "example.com",
    "items": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("reverend_sal/og-image-generator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "template": "gradient",
    "title": "Ship social images in seconds, not sprints 🚀",
    "subtitle": "Templates or your own HTML, any language, batches of hundreds.",
    "eyebrow": "Developer tools",
    "author": "Ada Lovelace",
    "siteName": "example.com",
    "items": [],
}

# Run the Actor and wait for it to finish
run = client.actor("reverend_sal/og-image-generator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "template": "gradient",
  "title": "Ship social images in seconds, not sprints 🚀",
  "subtitle": "Templates or your own HTML, any language, batches of hundreds.",
  "eyebrow": "Developer tools",
  "author": "Ada Lovelace",
  "siteName": "example.com",
  "items": []
}' |
apify call reverend_sal/og-image-generator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reverend_sal/og-image-generator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0YbD0WwRi46J8pFvZ/builds/eLM5BKIf6Aow6tPRx/openapi.json
