Documentation

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 download flag — receive the raw PNG binary instead of JSON
  • 🔒 API key passed via x-api-key header — never exposed in URLs
  • 🔒 Requires an active Pro subscription

Quick Start

  1. 1. Get your API key

    Subscribe to Pro, then go to Dashboard → API Keys to create a key.

  2. 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. 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] },
  }
}
Full type definitions, configuration options (custom 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.

POST
https://ogawesome.vercel.app/api/ogDefaultClassic templates — gradient, dark, light, etc.
POST
https://ogawesome.vercel.app/api/og/blogBlogArticle / blog post cards with author avatar support.
POST
https://ogawesome.vercel.app/api/og/productProductProduct showcase — image is required.
POST
https://ogawesome.vercel.app/api/og/profileProfilePersonal / team member cards with profile photo.

Default Theme — /api/og

General-purpose OG cards. Supports 10 background templates.

Parameters

FieldRequiredDefaultDescription
title✅ YesMain heading. Max 100 chars.
subtitleNo""Subheading / description. Alias: desc. Max 200 chars.
authorNo""Author or site name shown at bottom. Max 40 chars.
templateNogradientBackground template key. See list below.
fontNoRobotoFont key. See Fonts section.
weightNo400"400" for regular, "700" for bold (if font supports it).
styleNonormal"normal" or "italic" (if font supports it).
downloadNofalsetrue → returns raw PNG binary instead of { url }.

Templates

gradient
gradient

Indigo → Purple (default)

indigo
indigo

Flat indigo

sunset
sunset

Orange → Pink

ocean
ocean

Sky → Indigo

aurora
aurora

Teal & Violet glows

crimson
crimson

Deep red

midnight
midnight

Deep navy

rose
rose

Rose → Deep rose

dark
dark

Dark (near-black)

light
light

White / light

Blog Theme — /api/og/blog

Designed for articles and blog posts. Displays title, excerpt, author name, avatar, and site name.

Parameters

FieldRequiredDefaultDescription
title✅ YesPost title. Max 100 chars.
subtitleNo""Excerpt / description. Alias: desc. Max 200 chars.
authorNo""Author name. Max 40 chars.
siteNameNo""Site / publication name shown at top. Max 40 chars.
authorImageNo""Author avatar URL (https://). Shown in classic & dark templates.
templateNoclassic"classic" | "dark" | "minimal"
fontNoRobotoFont key. See Fonts section.
weightNo400"400" or "700".
styleNonormal"normal" or "italic".
downloadNofalsetrue → returns raw PNG binary.

Templates

classic

White bg, gradient accent bar, author avatar

dark

Near-black bg, indigo accent, author avatar

minimal

Clean 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

FieldRequiredDefaultDescription
title✅ YesProduct name. Max 100 chars.
subtitleNo""Tagline / description. Alias: desc. Max 200 chars.
authorNo""Brand / company name. Max 40 chars.
image✅ YesProduct image. https:// URL or data:image/ base64.
templateNosplit"split" | "feature" | "card"
fontNoRobotoFont key. See Fonts section.
weightNo400"400" or "700".
styleNonormal"normal" or "italic".
downloadNofalsetrue → returns raw PNG binary.

Templates

split

Text left, product image right (default)

feature

Dark bg, full right-half image, text on left

card

Centered 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

FieldRequiredDefaultDescription
title✅ YesPerson's full name. Max 100 chars.
subtitleNo""Job title / role. Alias: desc. Max 200 chars.
authorNo""Company / organisation name. Max 40 chars.
imageNo""Profile photo. https:// URL. Falls back to initials avatar.
templateNogradient"gradient" | "dark" | "card" | "neon" | "minimal"
fontNoRobotoFont key. See Fonts section.
weightNo400"400" or "700".
styleNonormal"normal" or "italic".
downloadNofalsetrue → returns raw PNG binary.

Templates

gradient

Indigo → purple gradient bg with avatar (default)

dark

Near-black bg with gradient ring around avatar

card

Light card with subtle shadow

neon

Dark bg with neon accent lines

minimal

Clean 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.

KeyDisplay NameBoldItalic
RobotoRoboto
FunnelSansFunnel Sans
SNProSN Pro
PacificoPacifico
PirataOnePirata One
MeaCulpaMea Culpa
BitcountPropDoubleBitcount 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:

  1. Subscribe to a Pro plan at Pricing
  2. Go to Dashboard → API Keys
  3. Click Create new key and copy the key (shown only once)
⚠️ Keep your API key secret. Pass it only from server-side code via environment variables. Never include it in client-side JavaScript or public repositories.

Plans & Limits

FeatureFreePro / 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 === true

curl — 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 binary

Error Codes

StatusMessageCause
400Invalid JSON bodyRequest body is not valid JSON
400Invalid titletitle is missing or exceeds 100 characters
400Invalid subtitlesubtitle exceeds 200 characters
400Invalid authorauthor exceeds 40 characters
400image is required (product only)/api/og/product — image field missing or invalid URL
401Missing API keyx-api-key header not provided
401Invalid API keyx-api-key does not match any active key
403Pro subscription requiredAccount does not have an active Pro subscription
422Failed to load product image/api/og/product — could not fetch the provided image URL
502Failed to upload image to storageS3 upload failed (contact support)
503Service unavailableCDN / S3 not configured on the server