Open Graph images

Generate an Open Graph image for every page: the card a link to your site shows in a chat, a feed or a search result.

Syntax

$ vela enable og

It has no dependencies on other features and needs no backend. On a static site the cards are written as files when the site is built; on a server they are rendered when first requested.

What you get

  • src/lib/og/card.svelte, the card itself: a Svelte component with its own <style> block, yours to redesign.
  • src/lib/server/og.ts, which renders the component to a 1200 × 630 PNG with Takumi.
  • A route at src/routes/og/[...path].png that serves the card for each page at the page’s own path: /og/about.png for /about, /og/index.png for /.
  • withCard around the meta tags in src/routes/+layout.svelte, which points each page’s og:image at its card.
  • The @takumi-rs/core package, in dependencies.

How a card gets its text

The route asks the page for it. Whatever a page sets as its title and description is in the meta tags it renders, and the card reads them from there, so a new page gets a card with nothing to wire up:

// src/routes/pricing/+page.ts
import { definePageMetaTags } from 'svelte-meta-tags';

export const load = () => ({
	...definePageMetaTags({ title: 'Pricing', description: 'One plan, billed monthly.' })
});

A page with no title gets a card with the site’s name. A path with no page, or a page that redirects (one behind sign-in, for example), gets no card.

Designing the card

Edit src/lib/og/card.svelte. It receives title, description and siteName, and is rendered outside the browser, so:

  • Lay it out with flexbox, and style it in the component’s own <style> block. Tailwind classes and app.css do not reach it.
  • Custom properties, gradients, oklch() and color-mix() work.
  • Text is drawn in Geist, which the renderer includes. To use another font, register its file in src/lib/server/og.ts; the comment there shows how.

Open /og/index.png while vela dev is running to see the result.

A page with its own image

A page that sets an Open Graph image keeps it. Only the site-wide default (static/og.jpg) is replaced by the card:

definePageMetaTags({
	title: 'Launch day',
	openGraph: { images: [{ url: 'https://example.com/launch.jpg', width: 1200, height: 630 }] }
});

Before you deploy

The image URL in the meta tags is built from url in src/lib/site.ts. Set it to the address the site is deployed at, or the services that read og:image are sent to the wrong host.

To remove it, run vela disable og.