March 29, 2026 · 9 min read

How to Add Dynamic OG Images to SvelteKit with OGPeek API

SvelteKit gives you file-based routing, server-side rendering, and static prerendering out of the box. But generating unique Open Graph images for every page still requires either manual work or complex server-side tooling. Here's how to solve it in under five minutes with a single API URL—no npm packages, no image libraries, no headless browsers.

Dynamic OG image for SvelteKit sites generated by OGPeek API

Why SvelteKit Needs Dynamic OG Images

When someone shares your SvelteKit app's URL on Twitter/X, LinkedIn, Slack, or Discord, the platform's crawler fetches the page, reads the og:image meta tag, and requests that image to display as a preview card. If every page on your site points to the same generic image—or has no og:image at all—your links look identical in every feed and get fewer clicks.

This matters because social preview cards are the first impression of your content. A blog post titled "Building a Real-Time Dashboard with SvelteKit" should have a social card that says exactly that—not a generic logo or a blank rectangle.

The traditional approaches to solving this each come with friction:

There is a simpler approach: point your og:image meta tag at an external API that returns a PNG. Your SvelteKit app stays lean. The image generation happens somewhere else entirely.

How OGPeek Works

OGPeek is an OG image generation API. You construct a URL with your title, subtitle, template, and brand color as query parameters. When that URL is requested, OGPeek renders the image and returns a 1200×630 PNG—the standard size for Open Graph images across all major platforms.

GET https://ogpeek.com/api/v1/og
  ?title=Your+Page+Title
  &subtitle=yourdomain.com
  &template=gradient
  &theme=midnight
  &brandColor=%23FF7A00

That is the entire integration. A GET request returns a PNG. No API keys for the free tier, no SDK to install, no build configuration to change. You embed this URL in your SvelteKit page's <svelte:head> and every page gets a unique social card based on its title.

Key point: Social platform crawlers follow the URL in your og:image meta tag and fetch whatever is there. They cannot distinguish between a static PNG on your CDN and an API endpoint that generates a PNG on the fly. Both are just HTTP responses with Content-Type: image/png.

Step 1: Add OGPeek to Your Root Layout

SvelteKit uses +layout.svelte files for shared UI that wraps child routes. The root layout at src/routes/+layout.svelte is the ideal place to add default OG meta tags that apply across your entire site.

First, create a +layout.ts (or +layout.server.ts) to expose page metadata:

// src/routes/+layout.ts
export function load() {
  return {
    siteName: 'Your Site Name',
    siteUrl: 'https://yourdomain.com'
  };
}

Then use <svelte:head> in your root layout to set the default OG tags:

<!-- src/routes/+layout.svelte -->
<script>
  let { data, children } = $props();
</script>

<svelte:head>
  <meta property="og:site_name" content={data.siteName} />
  <meta property="og:type" content="website" />
</svelte:head>

{@render children()}

This sets site-wide defaults. Individual pages will override these with their own <svelte:head> blocks, including the dynamic OG image URL.

Step 2: Dynamic OG Images on Individual Pages

Each +page.svelte file in SvelteKit can include its own <svelte:head> block. Tags defined in a page's head block take precedence over those in parent layouts. This is where you add the OGPeek URL with the page-specific title.

<!-- src/routes/about/+page.svelte -->
<script>
  const title = 'About Us';
  const description = 'Learn about our team and mission.';
  const ogImage = `https://ogpeek.com/api/v1/og?title=${
    encodeURIComponent(title)
  }&subtitle=${
    encodeURIComponent('yourdomain.com')
  }&template=gradient&theme=midnight&brandColor=%23FF7A00`;
</script>

<svelte:head>
  <title>{title}</title>
  <meta name="description" content={description} />
  <meta property="og:title" content={title} />
  <meta property="og:description" content={description} />
  <meta property="og:image" content={ogImage} />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content={title} />
  <meta name="twitter:image" content={ogImage} />
</svelte:head>

<h1>{title}</h1>
<p>{description}</p>

That is a complete integration for a single page. The og:image meta tag points to OGPeek, which generates a 1200×630 PNG with "About Us" as the title text. Zero dependencies added to your project.

Step 3: Dynamic Routes with Load Functions

The real power shows up with SvelteKit's dynamic routes. If you have a blog at /blog/[slug], each post should get its own unique OG image. The title comes from your load function—whether that loads from a CMS, a database, Markdown files, or an API.

Here is a typical setup with a load function returning post data:

// src/routes/blog/[slug]/+page.ts
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params }) => {
  // Fetch from your CMS, database, or local files
  const post = await getPost(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
    slug: params.slug
  };
};

Then in the corresponding +page.svelte, use the data to construct the OGPeek URL:

<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
  let { data } = $props();

  const ogImage = `https://ogpeek.com/api/v1/og?title=${
    encodeURIComponent(data.title)
  }&subtitle=${
    encodeURIComponent('Blog · yourdomain.com')
  }&template=gradient&theme=midnight&brandColor=%23FF7A00`;
</script>

<svelte:head>
  <title>{data.title} — Your Site</title>
  <meta name="description" content={data.description} />
  <meta property="og:title" content={data.title} />
  <meta property="og:description" content={data.description} />
  <meta property="og:type" content="article" />
  <meta property="og:image" content={ogImage} />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content={data.title} />
  <meta name="twitter:image" content={ogImage} />
</svelte:head>

<article>
  <h1>{data.title}</h1>
  <p>{data.description}</p>
  <!-- Rest of your blog post -->
</article>

Every blog post now gets a branded social card with its own title. A post called "Building Real-Time Features in SvelteKit" produces a social card with that exact text. No manual image creation, no server-side rendering of images.

Reusable SEO Component

If you have many page types, extract the OG logic into a reusable Svelte component to keep things DRY:

<!-- src/lib/components/SEO.svelte -->
<script>
  let { title, description, subtitle = 'yourdomain.com' } = $props();

  const ogImage = `https://ogpeek.com/api/v1/og?title=${
    encodeURIComponent(title)
  }&subtitle=${
    encodeURIComponent(subtitle)
  }&template=gradient&theme=midnight&brandColor=%23FF7A00`;
</script>

<svelte:head>
  <title>{title}</title>
  <meta name="description" content={description} />
  <meta property="og:title" content={title} />
  <meta property="og:description" content={description} />
  <meta property="og:image" content={ogImage} />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content={title} />
  <meta name="twitter:image" content={ogImage} />
</svelte:head>

Then use it in any page with a single line:

<!-- src/routes/pricing/+page.svelte -->
<script>
  import SEO from '$lib/components/SEO.svelte';
</script>

<SEO title="Pricing" description="Simple, transparent pricing." />

<h1>Pricing</h1>

Every page that imports SEO.svelte gets a unique, dynamic OG image without repeating the meta tag boilerplate.

Static vs. Server-Rendered SvelteKit Sites

SvelteKit supports multiple adapters for different deployment targets. OGPeek works with all of them because the integration is just a meta tag in your HTML—nothing runs on your server to generate images.

Adapter How It Works OGPeek Compatible
adapter-static Prerenders all pages to static HTML at build time Yes
adapter-node Runs a Node.js server with SSR Yes
adapter-vercel Deploys to Vercel with edge/serverless functions Yes
adapter-cloudflare Runs on Cloudflare Workers Yes
adapter-netlify Deploys to Netlify with serverless functions Yes

With adapter-static, the OGPeek URL is baked into the prerendered HTML. With SSR adapters, the URL is rendered server-side on each request. Either way, social platform crawlers receive valid HTML with a working og:image URL.

Tip: If you use adapter-static with prerender = true, make sure your load functions do not depend on request-time data for OG metadata. The title and description should be deterministic at build time so the correct OGPeek URL gets prerendered into each page.

OGPeek vs. SvelteKit Server Routes vs. Manual Creation

Here is how the three main approaches compare for SvelteKit projects:

Feature OGPeek API SvelteKit +server.ts Manual (Figma)
Setup time 2 minutes 1–3 hours 5–10 min per image
Dependencies added 0 Sharp, Puppeteer, or Satori 0
Server load Zero (external API) CPU-intensive per request Zero
Works with adapter-static Yes No (needs server) Yes
Hosting lock-in None Needs SSR-capable host None
Scales to 1000+ pages Yes Depends on server capacity No
Custom CSS layout Pre-built templates Full control Full control
Maintenance burden None Ongoing (deps, runtime) Per-page manual effort

For most SvelteKit projects—blogs, SaaS landing pages, documentation sites, portfolios—OGPeek's pre-built templates handle the common cases without adding complexity to your deployment pipeline.

Customizing Your OG Images

OGPeek supports several parameters to match your brand:

You can make any parameter dynamic. For example, pass the blog category or section name as the subtitle:

const ogImage = `https://ogpeek.com/api/v1/og?title=${
  encodeURIComponent(data.title)
}&subtitle=${
  encodeURIComponent(`${data.category} · yourdomain.com`)
}&template=gradient&theme=midnight&brandColor=%23FF4500`;

Testing Your OG Images

After deploying your SvelteKit site, verify your OG images work correctly:

  1. View the page source and confirm the og:image meta tag contains a valid OGPeek URL with your page title encoded in it.
  2. Open the OGPeek URL directly in your browser. You should see a 1200×630 PNG with your title rendered on it.
  3. Use a debugger tool like the Twitter Card Validator or Facebook Sharing Debugger to see exactly what the platform will display.
  4. Share a link in a private Slack channel or Discord server to see the preview card in a real context.

If the image does not appear, check that encodeURIComponent() is encoding special characters correctly. Ampersands, quotes, and hash symbols in titles can break the URL if left unencoded.

Performance Considerations

OGPeek caches generated images at the CDN edge. The first request for a given URL renders the image and caches it. Subsequent requests—including from different social platforms sharing the same link—are served from the cache with sub-50ms response times.

Since the og:image URL is only fetched by social platform crawlers (not by your site's actual visitors in their browsers), there is zero impact on your SvelteKit app's performance metrics. Core Web Vitals, Lighthouse scores, and page load times are completely unaffected.

Frequently Asked Questions

Does OGPeek work with SvelteKit's static adapter?

Yes. OGPeek works perfectly with @sveltejs/adapter-static. The og:image meta tag contains a URL to OGPeek's API, so the image is generated externally when a social platform requests it. Your SvelteKit site can be fully static and prerendered.

Do I need to install any npm packages to use OGPeek with SvelteKit?

No. OGPeek requires zero npm packages. You add a URL to your <svelte:head> block and pass your page title as a query parameter. There is nothing to install, configure, or maintain in your project dependencies.

Can I generate different OG images for each dynamic route in SvelteKit?

Yes. In your +page.svelte file, use the data returned by your load function to construct a unique OGPeek URL for each route. Pass the page title and any other dynamic text into the URL query parameters using encodeURIComponent(). Each route will get its own branded social card.

How is OGPeek different from generating OG images with SvelteKit server routes?

Generating OG images in SvelteKit server routes (+server.ts) requires running a headless browser or image library like Sharp on your server, which adds dependencies, server load, and complexity. OGPeek offloads all image rendering to an external API. You make a GET request and get a PNG back. No server-side image processing on your infrastructure.

What image size does OGPeek return for social cards?

OGPeek returns 1200×630 PNG images by default, which is the recommended size for Open Graph images across Facebook, LinkedIn, Twitter/X, Slack, Discord, and other platforms that render link previews.

Start generating OG images for your SvelteKit app

Read the full API documentation, explore templates, and grab your integration URL. Free tier available—no signup required.

Get started free → Read the API docs

Conclusion

SvelteKit's flexibility—static prerendering, server-side rendering, edge deployment—makes it one of the most versatile frameworks for building modern web applications. Adding dynamic OG images should not compromise that flexibility or add complexity to your deployment.

With OGPeek, you add a URL to your <svelte:head> block, pass the page title as a parameter, and every page on your site gets a unique, branded social preview card. Extract it into a reusable SEO.svelte component and the integration is a single line per page.

No npm packages. No headless browsers. No server-side image processing. No hosting lock-in. Just a GET request that returns a PNG.

Your SvelteKit app stays lean. Your OG images stay dynamic.

More developer APIs from the Peek Suite

← Back to all articles