OG Awesome API
Generate beautiful 1200×630 Open Graph images on-the-fly via a simple POST API.
Overview
OG Awesome exposes four theme-specific POST endpoints. Call an endpoint from your server, receive a { "url": "..." } JSON response, and use that CloudFront CDN URL directly as your og:image.
- ✅ Returns a CloudFront CDN URL — fast worldwide delivery
- ✅ Same params on repeat requests return the cached URL instantly
- ✅ 7 fonts with bold & italic support across all themes
- ✅ Optional
downloadflag — receive the raw PNG binary instead of JSON - 🔒 API key passed via
x-api-keyheader — never exposed in URLs - 🔒 Requires an active Pro subscription
Quick Start
- 1. Get your API key
Subscribe to Pro, then go to Dashboard → API Keys to create a key.
- 2. POST to an endpoint
curl -X POST https://ogawesome.vercel.app/api/og \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "title": "Hello World", "template": "gradient" }' - 3. Use the returned URL
// Response: { "url": "https://cdn.ogawesome.net/og-images/abc123.png" } // Add to your HTML: <meta property="og:image" content="https://cdn.ogawesome.net/og-images/abc123.png" />
npm SDK — og-awesome
Instead of calling the API with raw fetch, you can use the official type-safe Node.js / Edge SDK. It works in Next.js, Node.js, and any Edge Runtime.
Install
npm install og-awesome # or pnpm add og-awesome
Initialise
import { OgAwesome } from 'og-awesome'
const og = new OgAwesome({ apiKey: process.env.OG_API_KEY })Default theme
const { url } = await og.default({
title: 'Hello World',
template: 'gradient',
font: 'FunnelSans',
weight: '700',
})Blog theme
const { url } = await og.blog({
title: 'TypeScript Tips You Need to Know',
subtitle: 'Level up your type safety.',
author: 'Jane Doe',
siteName: 'Dev Weekly',
authorImage: 'https://example.com/avatar.jpg',
template: 'dark',
})Product theme
const { url } = await og.product({
title: 'Acme Widget Pro',
subtitle: 'The fastest widget on the market.',
author: 'Acme Corp',
image: product.imageUrl, // required
template: 'split',
})Profile theme
Semantic aliases are available for profile fields:
const { url } = await og.profile({
name: 'Jane Doe', // → title
jobTitle: 'Senior Engineer', // → subtitle
company: 'Acme Corp', // → author
image: 'https://example.com/jane.jpg',
template: 'dark',
})Download PNG directly
Pass download: true to receive an ArrayBuffer instead of a URL. TypeScript narrows the return type automatically.
const buffer = await og.blog({ title: 'My Post', download: true })
// buffer is ArrayBuffer — write to disk, pipe to response, etc.Error handling
import { OgAwesome, OgAwesomeError } from 'og-awesome'
try {
const { url } = await og.blog({ title: 'My Post' })
} catch (err) {
if (err instanceof OgAwesomeError) {
console.error(err.status, err.body)
// e.g. 401, { error: 'Invalid API key' }
}
throw err
}Next.js generateMetadata
// app/blog/[slug]/page.tsx
import { OgAwesome } from 'og-awesome'
import type { Metadata } from 'next'
const og = new OgAwesome({ apiKey: process.env.OG_API_KEY })
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug)
const { url } = await og.blog({
title: post.title,
subtitle: post.excerpt,
author: post.authorName,
siteName: 'My Blog',
template: 'dark',
})
return {
openGraph: { images: [{ url, width: 1200, height: 630 }] },
twitter: { card: 'summary_large_image', images: [url] },
}
}baseUrl and fetch), and the complete README are available on npmjs.com/package/og-awesome.Endpoints
Each theme has its own endpoint. All require x-api-key and a JSON body.
Default Theme — /api/og
General-purpose OG cards. Supports 10 background templates.
Parameters
| Field | Required | Default | Description |
|---|---|---|---|
| title | ✅ Yes | — | Main heading. Max 100 chars. |
| subtitle | No | "" | Subheading / description. Alias: desc. Max 200 chars. |
| author | No | "" | Author or site name shown at bottom. Max 40 chars. |
| template | No | gradient | Background template key. See list below. |
| font | No | Roboto | Font key. See Fonts section. |
| weight | No | 400 | "400" for regular, "700" for bold (if font supports it). |
| style | No | normal | "normal" or "italic" (if font supports it). |
| download | No | false | true → returns raw PNG binary instead of { url }. |
Templates
gradientIndigo → Purple (default)
indigoFlat indigo
sunsetOrange → Pink
oceanSky → Indigo
auroraTeal & Violet glows
crimsonDeep red
midnightDeep navy
roseRose → Deep rose
darkDark (near-black)
lightWhite / light
Blog Theme — /api/og/blog
Designed for articles and blog posts. Displays title, excerpt, author name, avatar, and site name.
Parameters
| Field | Required | Default | Description |
|---|---|---|---|
| title | ✅ Yes | — | Post title. Max 100 chars. |
| subtitle | No | "" | Excerpt / description. Alias: desc. Max 200 chars. |
| author | No | "" | Author name. Max 40 chars. |
| siteName | No | "" | Site / publication name shown at top. Max 40 chars. |
| authorImage | No | "" | Author avatar URL (https://). Shown in classic & dark templates. |
| template | No | classic | "classic" | "dark" | "minimal" |
| font | No | Roboto | Font key. See Fonts section. |
| weight | No | 400 | "400" or "700". |
| style | No | normal | "normal" or "italic". |
| download | No | false | true → returns raw PNG binary. |
Templates
classicWhite bg, gradient accent bar, author avatar
darkNear-black bg, indigo accent, author avatar
minimalClean white, large typography, author line
Example
curl -X POST https://ogawesome.vercel.app/api/og/blog \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"title": "10 Tips for Better TypeScript",
"subtitle": "Level up your type safety with these practical patterns.",
"author": "Jane Doe",
"siteName": "My Dev Blog",
"authorImage": "https://example.com/avatar.jpg",
"template": "dark",
"font": "FunnelSans"
}'Product Theme — /api/og/product
Showcase your product with name, tagline, brand, and product image. The image field is required.
Parameters
| Field | Required | Default | Description |
|---|---|---|---|
| title | ✅ Yes | — | Product name. Max 100 chars. |
| subtitle | No | "" | Tagline / description. Alias: desc. Max 200 chars. |
| author | No | "" | Brand / company name. Max 40 chars. |
| image | ✅ Yes | — | Product image. https:// URL or data:image/ base64. |
| template | No | split | "split" | "feature" | "card" |
| font | No | Roboto | Font key. See Fonts section. |
| weight | No | 400 | "400" or "700". |
| style | No | normal | "normal" or "italic". |
| download | No | false | true → returns raw PNG binary. |
Templates
splitText left, product image right (default)
featureDark bg, full right-half image, text on left
cardCentered card with image above title
Example
curl -X POST https://ogawesome.vercel.app/api/og/product \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"title": "Acme Widget Pro",
"subtitle": "The fastest widget on the market.",
"author": "Acme Corp",
"image": "https://example.com/product.png",
"template": "split",
"font": "SNPro",
"weight": "700"
}'Profile Theme — /api/og/profile
Personal or team member cards. title = person name, subtitle = job title, author = company.
Parameters
| Field | Required | Default | Description |
|---|---|---|---|
| title | ✅ Yes | — | Person's full name. Max 100 chars. |
| subtitle | No | "" | Job title / role. Alias: desc. Max 200 chars. |
| author | No | "" | Company / organisation name. Max 40 chars. |
| image | No | "" | Profile photo. https:// URL. Falls back to initials avatar. |
| template | No | gradient | "gradient" | "dark" | "card" | "neon" | "minimal" |
| font | No | Roboto | Font key. See Fonts section. |
| weight | No | 400 | "400" or "700". |
| style | No | normal | "normal" or "italic". |
| download | No | false | true → returns raw PNG binary. |
Templates
gradientIndigo → purple gradient bg with avatar (default)
darkNear-black bg with gradient ring around avatar
cardLight card with subtle shadow
neonDark bg with neon accent lines
minimalClean white, large name, small job title
Example
curl -X POST https://ogawesome.vercel.app/api/og/profile \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"title": "Jane Doe",
"subtitle": "Senior Engineer",
"author": "Acme Corp",
"image": "https://example.com/jane.jpg",
"template": "dark",
"font": "Roboto",
"weight": "700"
}'Fonts
Pass one of the following font keys to the font parameter. Available across all four endpoints.
| Key | Display Name | Bold | Italic |
|---|---|---|---|
| Roboto | Roboto | ✅ | ✅ |
| FunnelSans | Funnel Sans | ✅ | ✅ |
| SNPro | SN Pro | ✅ | ✅ |
| Pacifico | Pacifico | — | — |
| PirataOne | Pirata One | — | — |
| MeaCulpa | Mea Culpa | — | — |
| BitcountPropDouble | Bitcount Prop | — | — |
If a font file for the requested weight/style is not found, the server silently falls back to the Regular variant.
Authentication
All API requests require a Pro subscription and a valid API key passed in the x-api-key request header.
POST https://ogawesome.vercel.app/api/og
Content-Type: application/json
x-api-key: ogas_xxxxxxxxxxxx
{ "title": "My Title" }To create an API key:
- Subscribe to a Pro plan at Pricing
- Go to Dashboard → API Keys
- Click Create new key and copy the key (shown only once)
Plans & Limits
| Feature | Free | Pro / Pro Annual |
|---|---|---|
| Web generator | ✅ | ✅ |
| API access (all 4 endpoints) | ❌ | ✅ |
| All themes & templates | ❌ Default only | ✅ |
| All 7 fonts | ❌ Default only | ✅ |
| Watermark | ✅ (shown) | ❌ (removed) |
| CDN cached images | — | ✅ |
| Image history (Dashboard) | — | ✅ |
Code Examples
SDK — Default theme
import { OgAwesome } from 'og-awesome'
const og = new OgAwesome({ apiKey: process.env.OG_API_KEY })
const { url } = await og.default({
title: 'My Post Title',
subtitle: 'Short description here',
template: 'gradient',
font: 'FunnelSans',
weight: '700',
})
// => url: "https://cdn.ogawesome.net/og-images/abc123.png"SDK — Next.js generateMetadata (Blog theme)
// app/blog/[slug]/page.tsx
import { OgAwesome } from 'og-awesome'
import type { Metadata } from 'next'
const og = new OgAwesome({ apiKey: process.env.OG_API_KEY })
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug)
const { url } = await og.blog({
title: post.title,
subtitle: post.excerpt,
author: post.authorName,
siteName: 'My Blog',
authorImage: post.authorAvatarUrl,
template: 'dark',
font: 'FunnelSans',
})
return {
openGraph: { images: [{ url, width: 1200, height: 630 }] },
twitter: { card: 'summary_large_image', images: [url] },
}
}SDK — Product theme
const { url } = await og.product({
title: 'Acme Widget Pro',
subtitle: 'The fastest widget on the market.',
author: 'Acme Corp',
image: product.imageUrl, // required
template: 'split',
font: 'SNPro',
weight: '700',
})SDK — Profile theme (semantic aliases)
const { url } = await og.profile({
name: 'Jane Doe', // → title
jobTitle: 'Senior Engineer', // → subtitle
company: 'Acme Corp', // → author
image: 'https://example.com/jane.jpg',
template: 'dark',
})SDK — Download PNG directly
// download: true → returns ArrayBuffer (TypeScript narrows automatically)
const buffer = await og.blog({ title: 'My Post', download: true })
// buffer instanceof ArrayBuffer === truecurl — Default theme (raw API)
curl -X POST https://ogawesome.vercel.app/api/og \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"title": "My Post Title",
"subtitle": "Short description here",
"template": "gradient",
"font": "FunnelSans",
"weight": "700"
}'
# => { "url": "https://cdn.ogawesome.net/og-images/abc123.png" }fetch — Blog theme (raw API)
const res = await fetch('https://ogawesome.vercel.app/api/og/blog', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.OG_API_KEY,
},
body: JSON.stringify({
title: 'My Post',
template: 'dark',
download: true,
}),
})
// res.headers['Content-Type'] => 'image/png'
// res.body => raw PNG binaryError Codes
| Status | Message | Cause |
|---|---|---|
| 400 | Invalid JSON body | Request body is not valid JSON |
| 400 | Invalid title | title is missing or exceeds 100 characters |
| 400 | Invalid subtitle | subtitle exceeds 200 characters |
| 400 | Invalid author | author exceeds 40 characters |
| 400 | image is required (product only) | /api/og/product — image field missing or invalid URL |
| 401 | Missing API key | x-api-key header not provided |
| 401 | Invalid API key | x-api-key does not match any active key |
| 403 | Pro subscription required | Account does not have an active Pro subscription |
| 422 | Failed to load product image | /api/og/product — could not fetch the provided image URL |
| 502 | Failed to upload image to storage | S3 upload failed (contact support) |
| 503 | Service unavailable | CDN / S3 not configured on the server |