How to add Open Graph tags in SvelteKit

SvelteKit renders on the server by default, which makes Open Graph straightforward: put the tags in <svelte:head>, feed them from your load function, and every page ships scraper-readable HTML. The mistakes people make are the same as everywhere — relative image URLs and client-only rendering.

Want to see how your page looks right now?

The free checker shows your previews for nine platforms — from X and WhatsApp to iMessage, Discord and Bluesky.

Check your URL

Render tags in <svelte:head>

In +page.svelte, add a <svelte:head> block with og:title, og:description, og:image, og:url and twitter:card. Svelte hoists these into the document head during SSR.

Feed the values from load

Fetch the page data in +page.js / +page.server.js and export what the head needs (title, description, image). The page component reads it from the data prop — tags and content always stay in sync.

Build absolute URLs from the page store

Use $page.url.origin (or a PUBLIC_SITE_URL env var for canonical domains behind proxies) to prefix image paths and build og:url. Relative og:image paths get ignored by scrapers.

Keep SSR on and verify

With export const ssr = false, scrapers receive an empty shell — previews die. Leave SSR on for shareable pages, then paste a deployed URL into the MetaPeek checker to confirm what the scraper sees.

Code example

<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
  import { page } from '$app/stores';
  export let data; // from +page.server.js load()
  $: origin = $page.url.origin;
</script>

<svelte:head>
  <title>{data.post.title}</title>
  <meta name="description" content={data.post.excerpt} />
  <meta property="og:title" content={data.post.title} />
  <meta property="og:description" content={data.post.excerpt} />
  <meta property="og:type" content="article" />
  <meta property="og:url" content={origin + $page.url.pathname} />
  <meta property="og:image" content={origin + data.post.ogImage} />
  <meta name="twitter:card" content="summary_large_image" />
</svelte:head>

Common mistakes

Frequently asked questions

Should I use a head-management library?

Usually unnecessary — <svelte:head> plus load data covers Open Graph completely. Libraries only help if you want typed, centralized SEO config across many routes.

Do prerendered pages work for previews?

Yes. Prerendering (export const prerender = true) bakes the tags into static HTML, which is ideal for scrapers — just rebuild when the content changes.

How do I test before deploying?

Run the production build locally (vite preview), view-source the page and paste the HTML into the MetaPeek paste-HTML mode.

Changed your tags? Verify the result.

Paste your URL and see within two seconds whether everything is right — on every platform.

Open the checker

Related guides