Skip to content

SDK Reference

Full reference for all methods on the OGEngine client. All methods return Promises and throw typed OGEngineError instances on failure.

Generates a single image. Returns a Buffer containing the binary image data.

og.render(request: RenderRequest): Promise<Buffer>
interface RenderRequest {
format: 'og' | 'twitter' | 'square' | 'linkedin' | 'story'
template?: 'default' | 'social-card' | 'blog-hero' | 'email-banner'
title: string
description?: string
author?: string
tag?: string
style?: {
accent?: string
font?: string
titleSize?: number
descSize?: number
layout?: 'left' | 'center' | 'bottom'
gradient?: 'void' | 'deep-sea' | 'ember' | 'forest' | 'plum' | 'slate'
overlayOpacity?: number
}
output?: {
format?: 'png' | 'webp'
quality?: number
}
backgroundImage?: Buffer | Uint8Array
}
const imageBuffer = await og.render({
format: 'og',
title: 'Hello from the SDK',
description: 'Generated in ~22ms, no browser needed.',
tag: 'Tutorial',
style: {
accent: '#38ef7d',
font: 'Outfit',
gradient: 'void',
},
})
await Bun.write('card.png', imageBuffer)

The returned Buffer has extra properties attached for diagnostic access:

const image = await og.render({ format: 'og', title: 'Hello' })
console.log(image.meta.renderTimeMs) // 2.34
console.log(image.meta.titleLines) // 2
console.log(image.meta.descLines) // 0
console.log(image.meta.layoutOverflow) // false

Checks if text fits a layout without generating an image. Returns layout metrics.

og.validate(request: ValidateRequest): Promise<ValidateResult>
interface ValidateRequest {
format: 'og' | 'twitter' | 'square' | 'linkedin' | 'story'
title: string
description?: string
font?: string
titleSize?: number
descSize?: number
maxTitleLines?: number
maxDescLines?: number
}
interface ValidateResult {
fits: boolean
title: { lines: number; maxLines: number; overflow: boolean }
description: { lines: number; maxLines: number; overflow: boolean }
computeTimeMs: number
}
const result = await og.validate({
format: 'og',
title: 'My Article Title That Might Be Too Long',
description: 'My article description.',
})
if (!result.fits) {
console.warn(`Title overflows: ${result.title.lines} lines, max ${result.title.maxLines}`)
}

Renders multiple images in a single API call. Returns a Buffer containing a ZIP archive.

og.batch(items: RenderRequest[]): Promise<Buffer>

Plan requirement: Pro and Scale only.

const zipBuffer = await og.batch([
{ format: 'og', title: 'First Post', tag: 'Blog' },
{ format: 'og', title: 'Second Post', tag: 'Blog' },
{ format: 'twitter', template: 'social-card', title: 'Announcement' },
])
await Bun.write('images.zip', zipBuffer)

The ZIP contents follow the same structure as the REST API: 0.png, 1.png, … with an optional errors.json for partial failures.


Returns current quota usage for your API key.

og.usage(): Promise<UsageResult>
interface UsageResult {
plan: 'free' | 'starter' | 'pro' | 'scale'
limit: number
used: number
remaining: number
resetAt: string // ISO 8601 timestamp
}
const { plan, used, remaining, resetAt } = await og.usage()
console.log(`Plan: ${plan}`)
console.log(`Used: ${used} / ${used + remaining} renders`)
console.log(`Resets: ${new Date(resetAt).toLocaleDateString()}`)

Checks service status and returns available fonts, formats, and templates.

og.health(): Promise<HealthResult>
const { status, version, fonts, formats, templates } = await og.health()

The SDK automatically attaches the Authorization: Bearer header to every request. You never need to set it manually.

The SDK retries failed requests on 5xx errors with exponential backoff (200ms, 400ms, 800ms). The retry count is configurable via the retries option (default: 3). Client errors (4xx) are never retried.

All errors are thrown as OGEngineError instances with typed properties:

import { OGEngine, OGEngineError } from '@atypical-consulting/og-engine-sdk'
try {
const image = await og.render({ format: 'og', title: 'Hello' })
} catch (err) {
if (err instanceof OGEngineError) {
console.error(err.code) // e.g. 'rate_limited'
console.error(err.message) // human-readable message
console.error(err.status) // HTTP status code
console.error(err.details) // extra context object or null
}
}

app/api/og/route.ts
import { og } from '@/lib/og'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(req: NextRequest) {
const title = req.nextUrl.searchParams.get('title') ?? 'Untitled'
const image = await og.render({
format: 'og',
title,
tag: 'Blog',
})
return new NextResponse(image, {
headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400' },
})
}
src/pages/og/[slug].png.ts
import type { APIRoute } from 'astro'
import { og } from '@/lib/og'
import { getEntry } from 'astro:content'
export const GET: APIRoute = async ({ params }) => {
const post = await getEntry('blog', params.slug!)
const image = await og.render({
format: 'og',
title: post.data.title,
description: post.data.description,
tag: post.data.category,
})
return new Response(image, {
headers: { 'Content-Type': 'image/png' },
})
}
import express from 'express'
import { OGEngine } from '@atypical-consulting/og-engine-sdk'
const app = express()
const og = new OGEngine(process.env.OG_ENGINE_KEY!)
app.get('/og/:slug', async (req, res) => {
const title = req.params.slug.replace(/-/g, ' ')
const image = await og.render({ format: 'og', title })
res.setHeader('Content-Type', 'image/png')
res.setHeader('Cache-Control', 'public, max-age=86400')
res.send(image)
})
import { OGEngine } from '@atypical-consulting/og-engine-sdk'
interface Env {
OG_ENGINE_KEY: string
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url)
const title = url.searchParams.get('title') ?? 'Hello'
const og = new OGEngine(env.OG_ENGINE_KEY)
const image = await og.render({ format: 'og', title })
return new Response(image, {
headers: { 'Content-Type': 'image/png' },
})
},
}