ShotOG

February 12, 2026 · View on GitHub

Beautiful OG images. One API call.

Generate stunning Open Graph images for your website with a single URL — no design tools, no headless browsers, no infrastructure to manage.

Live Demo License: MIT API Status

ShotOG Basic Template

Why ShotOG?

Every page you share on Twitter, Slack, or Discord needs an OG image. You can:

  1. Design each one manually in Figma (doesn't scale)
  2. Run a headless browser on your server (slow, expensive, breaks)
  3. Call ShotOG's API — one URL, beautiful image, ~50ms at the edge

ShotOG runs on Cloudflare Workers. No cold starts. No servers. Just fast images.

Quick Start

Option 1: Just use a URL

Drop this into your HTML <head>:

<meta property="og:image" content="https://shotog.2214962083.workers.dev/v1/og?title=My%20Page%20Title&template=blog&author=John" />

That's it. No signup required for up to 10 images/day.

Option 2: Use the TypeScript SDK

npm install shotog
import { ShotOG } from "shotog";

const og = new ShotOG({ apiKey: "sk_..." }); // optional, increases rate limit

// Generate a URL (no network request)
const imageUrl = og.url({
  title: "How We Scaled to 1M Users",
  subtitle: "A deep dive into our infrastructure",
  template: "blog",
  author: "Jane Smith",
});
// → https://shotog.2214962083.workers.dev/v1/og?title=How+We+Scaled...

// Or fetch the image binary directly
const imageBuffer = await og.generate({
  title: "Product Launch",
  template: "announcement",
});

Option 3: cURL

# GET — returns PNG directly
curl "https://shotog.2214962083.workers.dev/v1/og?title=Hello&template=basic" -o og.png

# POST — JSON body, more options
curl -X POST https://shotog.2214962083.workers.dev/v1/og \
  -H "Content-Type: application/json" \
  -d '{"title":"Hello World","template":"product","subtitle":"Built with ShotOG"}' \
  -o og.png

Templates

8 professionally designed templates for every use case:

TemplateBest ForPreview
basicGeneral pages, social sharing
blogBlog posts, articles
productSaaS products, launches
socialSocial media posts
eventEvents, webinars
changelogRelease notes
testimonialCustomer quotes
announcementMajor updates, launches

Browse all templates →

API Reference

Generate OG Image

GET /v1/og?title=...&template=...
POST /v1/og  (JSON body)

Parameters:

ParameterTypeRequiredDescription
titlestringYesMain heading text
templatestringNoTemplate name (default: basic)
subtitlestringNoSecondary text
eyebrowstringNoSmall text above title (category, label)
authorstringNoAuthor name
avatarstringNoAvatar image URL (shown in blog/social/testimonial)
logostringNoLogo image URL (shown in basic/product)
fontUrlstringNoURL to TTF/OTF font file (max 5MB, cached 1h)
domainstringNoDomain watermark
bgColorstringNoBackground color (hex, e.g. 1a1a2e)
textColorstringNoText color (hex)
accentColorstringNoAccent color (hex)
formatstringNopng (default) or svg
widthnumberNoImage width 200-2400 (default: 1200)
heightnumberNoImage height 200-1260 (default: 630)
api_keystringNoAPI key for higher limits

Batch Generate (up to 20 images)

curl -X POST https://shotog.2214962083.workers.dev/v1/og/batch \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: sk_..." \
  -d '{
    "images": [
      {"id": "hero", "title": "My Product", "template": "product"},
      {"id": "blog-1", "title": "First Post", "template": "blog", "author": "Alice"},
      {"id": "blog-2", "title": "Second Post", "template": "blog", "author": "Bob"}
    ],
    "defaults": {"format": "png", "width": 1200, "domain": "example.com"}
  }'

Response:

{
  "results": [
    {"id": "hero", "success": true, "dataUri": "data:image/png;base64,..."},
    {"id": "blog-1", "success": true, "dataUri": "data:image/png;base64,..."},
    {"id": "blog-2", "success": true, "dataUri": "data:image/png;base64,..."}
  ],
  "summary": {"total": 3, "succeeded": 3, "failed": 0}
}

Batch features:

  • Max 20 images per request
  • defaults object applies to all images (individual params override)
  • Parallel rendering via Promise.allSettled
  • Quota pre-check: if insufficient quota, returns 429 before rendering
  • Only successful renders count toward usage

Get API Key (Self-Service)

curl -X POST https://shotog.2214962083.workers.dev/v1/keys \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'

Returns:

{
  "id": "key_abc123",
  "key": "sk_live_...",
  "tier": "free",
  "monthly_limit": 500,
  "message": "Store your API key safely — it cannot be retrieved later."
}

Check Usage

curl https://shotog.2214962083.workers.dev/v1/keys/usage \
  -H "X-Api-Key: sk_live_..."

List Templates

curl https://shotog.2214962083.workers.dev/v1/og/templates

SDK

The TypeScript/JavaScript SDK wraps all API functionality:

import { ShotOG } from "shotog";

// Initialize
const og = new ShotOG({ apiKey: "sk_..." });

// Build image URL (no network call)
og.url({ title: "My Post", template: "blog" });

// Generate image binary
await og.generate({ title: "My Post", template: "blog" });

// List templates
await og.templates();

// Check usage
await og.usage();

// Create a new API key (static method)
await ShotOG.createKey("email@example.com");

Framework Examples

Next.js

// app/layout.tsx
export function generateMetadata({ params }) {
  return {
    openGraph: {
      images: [`https://shotog.2214962083.workers.dev/v1/og?title=${encodeURIComponent(params.title)}&template=blog`],
    },
  };
}

Astro

---
const ogImage = `https://shotog.2214962083.workers.dev/v1/og?title=${encodeURIComponent(title)}&template=product`;
---
<meta property="og:image" content={ogImage} />

Hugo

{{ $ogImage := printf "https://shotog.2214962083.workers.dev/v1/og?title=%s&template=blog&author=%s" (querify .Title) (querify .Params.author) }}
<meta property="og:image" content="{{ $ogImage }}" />

Tech Stack

  • Runtime: Cloudflare Workers (edge, ~17ms cold start)
  • Framework: Hono (lightweight, fast)
  • Rendering: @cf-wasm/satori (JSX → SVG at the edge)
  • Rasterizer: @cf-wasm/resvg (SVG → PNG)
  • Database: Cloudflare D1 (API keys + usage tracking)
  • Caching: Built-in CDN cache headers

Self-Hosting

ShotOG is MIT licensed. Deploy your own instance:

git clone https://github.com/nicepkg/shotog.git
cd shotog
npm install

# Set up D1 database
npx wrangler d1 create shotog-prod
# Update wrangler.toml with your database_id
npx wrangler d1 execute shotog-prod --file=./migrations/001_init.sql

# Deploy
npx wrangler deploy

Pricing

PlanPriceMonthly ImagesRate Limit
DemoFree10/day10/day
FreeFree500/month60/min
Starter$9/mo5,000/month120/min
Pro$29/mo25,000/month300/min
Scale$79/mo100,000/month600/min

See pricing details →

License

MIT