Introduction
Platform-aware Open Graph rendering with request resolution, adaptive layout, and multi-runtime adapters.
What is better-og?
better-og provides a set of utilities for generating Open Graph images that automatically adapt to the platform requesting them. Whether a link is shared on Twitter, Telegram, Slack, iMessage, or Instagram, better-og detects the caller and renders the image at the optimal aspect ratio.
Key Features
- Multi-signal platform detection -- uses query overrides,
User-Agent,Referer, and other request hints to identify the requesting platform. - Adaptive layout primitives -- exposes computed safe areas, reusable layout boxes, and platform-native layout strategies.
- Script-aware font resolution -- built-in Google Fonts integration with automatic fallback fonts for
en,ja,ko,zh,ar,hi,ru, anduk. - Multi-runtime adapters -- works with Next.js (Node & Edge), Cloudflare Workers, and TanStack Start.
- Multiple renderers -- choose between
next/og(Vercel's built-in Satori) or Takumi for WASM-based rendering.
Aspect Ratio Presets
| Preset | Dimensions | Ratio | Used by |
|---|---|---|---|
STANDARD | 1200 x 630 | 1.91 : 1 | Twitter, Generic |
SQUARE | 1200 x 1200 | 1 : 1 | Telegram, Slack |
PORTRAIT | 630 x 1200 | 1 : 1.91 | iMessage |
INSTAGRAM | 1200 x 1500 | 4 : 5 |
How It Works
- A middleware intercepts OG image requests and resolves the platform-aware render plan.
- The request plan normalizes
platform,aspect_ratio, andlayoutfor the downstream OG route. - The OG route handler loads the required fonts, computes layout boxes, and renders with the selected runtime adapter.
Installation
Install only the runtime pieces you need.
pnpm add @better-og/core next reactFirst Route (Next.js)
Create your first OG route in a Next.js app:
import { resolveFontSetup } from "@better-og/core";
import {
createOgRouteHandler,
loadGoogleFontForImageResponse,
} from "@better-og/next";
export const runtime = "nodejs";
export const revalidate = false;
const fontSetup = await resolveFontSetup({
baseFonts: await loadGoogleFontForImageResponse({
family: "Geist",
weights: [400, 700],
}),
fallbackLocales: ["ja"],
});
export const GET = createOgRouteHandler({
component: (ogContext) => (
<div
style={{
display: "flex",
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
fontFamily: fontSetup.families.base,
paddingBottom: 32 + ogContext.safeArea.bottom,
background: "linear-gradient(135deg, #0d192c, #174a70, #4993d6)",
color: "white",
}}
>
<div style={{ fontSize: 64, fontWeight: 700 }}>Hello from better-og</div>
</div>
),
baseFonts: fontSetup.fonts,
});Add the Proxy
To enable automatic aspect-ratio detection, add a proxy:
import { withOgRewrite } from "@better-og/next";
import type { NextRequest } from "next/server";
export async function proxy(request: NextRequest) {
return await withOgRewrite(request);
}
export const config = {
matcher: ["/og/:path*"],
};Next.js Config
If using the Takumi renderer, keep it external:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
serverExternalPackages: ["@takumi-rs/image-response"],
};
export default nextConfig;Edit on GitHub
Last updated on