Heading text on the image, rendered at 76px. Trimmed, and truncated to 100 characters with a trailing ellipsis.
OG Images
The /og route handler draws an Open Graph (OG) card for every page, a 1200×630
PNG rendered on demand with next/og. Page metadata points both the OpenGraph
and the Twitter card image at that URL. No file lands in the repo, and no
third-party service touches the request. The parameters below cover every
element on the frame.
Quick Start
Hit the route with a title and a PNG comes back.
/og?title=Hello&breadcrumb=Demo
/og?title=Hello&breadcrumb=DemoDrop the title and the image still renders; title falls back to OwnDocs, so
a bare /og is a valid site-wide card.
Adding Options
Combine the title, breadcrumb, description, and theme parameters. URL-encode the
values, so spaces become %20.
/og?title=Authentication&breadcrumb=Getting%20Started&description=Set%20up%20JWT%20sessions&theme=darkThe handler trims every value before it renders, and treats a parameter that
trims down to an empty string as absent: title returns to OwnDocs, while
breadcrumb and description drop their blocks from the layout entirely.
theme accepts light and dark and nothing else. A misspelled or missing
value renders light rather than erroring.
The frame draws five things, top to bottom: a rounded accent square holding the
letter C beside the OwnDocs wordmark, the breadcrumb line, the title at
76px, the description at 28px, then a footer rule with Documentation on the
left and owndocs in the accent color on the right.
Advanced
The route rarely needs a hand-written call. generateMetadata in the catch-all
route builds the URL for every page from the page title, its breadcrumb label,
and its description, then hands it to both the OpenGraph and Twitter card. It
never sets theme, so page images render in the light palette.
const ogParams = new URLSearchParams({ title: plainTitle })
if (breadcrumb) ogParams.set('breadcrumb', breadcrumb)
if (description) ogParams.set('description', description)
const ogImageUrl = `${siteUrl}/og?${ogParams.toString()}`The values it passes are the resolved ones: title is the frontmatter title,
falling back to the first # heading and then to OwnDocs; description is
the frontmatter description, falling back to a 160-character extract of the
body; and breadcrumb is the route's segments run through the same
acronym-aware formatter the visible breadcrumbs use, joined with /. The
absolute host comes from DOCS_SITE_URL, then VERCEL_PROJECT_PRODUCTION_URL,
then http://localhost:$PORT for local development. generateMetadata
registers the same URL twice: once under openGraph.images with width,
height, and the plain title as alt, and once under twitter.images with a
summary_large_image card.
Colors come from the palette named by THEME_VARIANT, so the image matches the
site: background, text, and border read from the variant's light or dark
token set, and the brand square and footer accent use --color-accent.
Truncation cuts one character short and appends an ellipsis, so a 140-character
title ships as 99 characters plus .... The limits are 100 for the title, 80
for the breadcrumb, and 200 for the description.
The handler runs on the Node.js runtime and answers GET only. If next/og
throws while rendering, the route returns a 500 with a JSON body of
{"error":"og-render-failed"} and cache-control: no-store, so a bad frame
never gets cached.
{ "error": "og-render-failed" }Options
titlequeryDefault: OwnDocsbreadcrumbqueryBreadcrumb text above the title. Trimmed and truncated to 80 characters; the block is omitted when empty.
descriptionquerySubtitle below the title. Trimmed and truncated to 200 characters; the block is omitted when empty.
themequeryDefault: lightlight or dark. Any other value falls back to light.
THEME_VARIANTenvDefault: violetServer env var naming the palette. Supplies the background, text, tertiary
text, accent, and border colors used in the image. An unknown name falls back
to violet.
DOCS_SITE_URLenvAbsolute host used to build the image URL in page metadata. Set this to the
site's real domain in production. Falls back to
VERCEL_PROJECT_PRODUCTION_URL, then http://localhost:$PORT for local
development.
widthnumberDefault: 1200Fixed output width in pixels.
heightnumberDefault: 630Fixed output height in pixels, giving the 1.91:1 ratio social platforms crop to.