Skip to main content

OG / Social Cards

How to add Open Graph metadata to new pages across ɳSelf web properties.

Every ɳSelf web property generates dynamic Open Graph (OG) images via the shared nself package. Cards render correctly on Twitter/X, LinkedIn, Slack unfurl, and Facebook.

Architecture

The shared package at web/packages/og/ provides:

  • colors.ts: product accent color map (7 products)
  • template.tsx: Satori JSX template (1200×630, gray-950 background, left accent bar)
  • route.ts: Edge Function handler with 24h cache headers

How each app serves OG images depends on its framework:

  • Vite SPAs (task, sentry): a root-level api/og.ts Vercel Edge Function re-exporting buildOgResponse — dynamic per-page titles via query params.
  • Astro sites (org, docs, tv): a static public/og.png rendered from the same shared template. @vercel/og only runs on the Edge runtime, and the Astro Vercel adapter deploys endpoints as Node serverless functions (root api/ directories are not deployed for Build Output API frameworks), so a dynamic /api/og route is not possible there.

Adding OG metadata to a new page

In any page.tsx or layout.tsx:

export const metadata = {
  openGraph: {
    images: [{
      url: `/api/og?title=${encodeURIComponent('Your Page Title')}&product=docs`,
      width: 1200,
      height: 630,
    }],
  },
  twitter: {
    card: 'summary_large_image',
    images: [`/api/og?title=${encodeURIComponent('Your Page Title')}&product=docs`],
  },
}

Replace product=docs with the product key for the app you are working in.

Product keys

AppKey
nself.orgorg
docs.nself.orgdocs
cloud.nself.orgcloud
chat.nself.orgnself
claw.nself.orgnself
ntv.nself.orgnself
family.nself.orgnself
task.nself.orgnself
clawde.nself.orgclawde

Query parameters

ParamRequiredDescription
titleYesPage title, displayed at 56px bold, truncated at 80 chars
productNoProduct key (defaults to org)
breadcrumbNoSubtitle below title, e.g. docs.nself.org / guides / deploy

Fallback

If the /api/og route is unreachable, the browser falls back to the static /og-default.png (1200×630) in each app’s public/ directory. Keep this file up to date with the current brand.

Cache

All /api/og responses carry:

Cache-Control: public, max-age=86400, s-maxage=86400

Vercel caches at the edge. Cold start renders in well under 500ms.