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.
The free checker shows your previews for nine platforms — from X and WhatsApp to iMessage, Discord and Bluesky.
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
- ssr = false on shareable pagesClient-side-only pages send scrapers an empty document. If a page needs a preview, it needs SSR (or prerendering).
- Hardcoding localhost originsog:url and og:image built from a hardcoded dev origin end up in production HTML. Derive the origin from $page.url or an env var.
- Duplicate tags from nested layoutsIf both a layout and a page render og: tags, platforms pick unpredictably. Render social tags in exactly one place per route.
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.
Paste your URL and see within two seconds whether everything is right — on every platform.