Skip to content

Svelte Integration

Generate OG images for SvelteKit applications.

SvelteKit Setup

1. Environment Variable

bash
# .env
OG_IMAGE_API_KEY=og_your_api_key_here

2. Create API Endpoint

javascript
// src/routes/api/og/+server.js
import { env } from '$env/dynamic/private';

export async function GET({ url }) {
  const title = url.searchParams.get('title') || 'My Site';
  const subtitle = url.searchParams.get('subtitle') || '';
  const template = url.searchParams.get('template') || 'default';
  
  const response = await fetch('https://ogimageapi.io/api/generate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': env.OG_IMAGE_API_KEY
    },
    body: JSON.stringify({
      title,
      subtitle,
      template,
      theme: 'dark'
    })
  });
  
  const imageBuffer = await response.arrayBuffer();
  
  return new Response(imageBuffer, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=86400, s-maxage=86400'
    }
  });
}

3. Create SEO Component

svelte
<!-- src/lib/components/SEO.svelte -->
<script>
  import { page } from '$app/stores';
  
  export let title;
  export let description = '';
  export let image = null;
  export let type = 'website';
  
  $: ogImage = image || `/api/og?title=${encodeURIComponent(title)}&subtitle=${encodeURIComponent(description)}`;
  $: fullUrl = $page.url.href;
</script>

<svelte:head>
  <title>{title}</title>
  <meta name="description" content={description} />
  
  <!-- Open Graph -->
  <meta property="og:title" content={title} />
  <meta property="og:description" content={description} />
  <meta property="og:image" content={ogImage} />
  <meta property="og:url" content={fullUrl} />
  <meta property="og:type" content={type} />
  
  <!-- Twitter -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content={title} />
  <meta name="twitter:description" content={description} />
  <meta name="twitter:image" content={ogImage} />
</svelte:head>

4. Use in Pages

svelte
<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
  import SEO from '$lib/components/SEO.svelte';
  
  export let data;
</script>

<SEO
  title={data.post.title}
  description={data.post.excerpt}
  type="article"
/>

<article>
  <h1>{data.post.title}</h1>
  {@html data.post.content}
</article>

Static Site Generation

Generate images at build time for static sites:

Build Script

javascript
// scripts/generate-og.js
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

async function generateOGImages() {
  // Get your content
  const posts = await getPosts(); // Your data fetching logic
  
  const outputDir = path.join(__dirname, '../static/og');
  fs.mkdirSync(outputDir, { recursive: true });
  
  for (const post of posts) {
    const response = await fetch('https://ogimageapi.io/api/generate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': process.env.OG_IMAGE_API_KEY
      },
      body: JSON.stringify({
        title: post.title,
        subtitle: post.excerpt,
        author_name: post.author,
        template: 'blog',
        theme: 'dark'
      })
    });
    
    const buffer = await response.arrayBuffer();
    fs.writeFileSync(
      path.join(outputDir, `${post.slug}.png`),
      Buffer.from(buffer)
    );
    
    console.log(`✓ ${post.slug}.png`);
  }
}

generateOGImages();

Package.json

json
{
  "scripts": {
    "generate-og": "node scripts/generate-og.js",
    "build": "npm run generate-og && vite build"
  }
}

Load Function Integration

javascript
// src/routes/blog/[slug]/+page.server.js
import { env } from '$env/dynamic/private';

export async function load({ params, fetch }) {
  const post = await getPost(params.slug);
  
  // Option 1: Dynamic OG URL
  const ogImage = `/api/og?title=${encodeURIComponent(post.title)}&subtitle=${encodeURIComponent(post.excerpt)}`;
  
  // Option 2: Pre-generated static image
  // const ogImage = `/og/${params.slug}.png`;
  
  return {
    post,
    ogImage
  };
}

Layout-Level SEO

svelte
<!-- src/routes/+layout.svelte -->
<script>
  import { page } from '$app/stores';
  
  // Default OG image for pages without custom ones
  const defaultOGImage = '/api/og?title=My+Svelte+App&subtitle=Welcome';
</script>

<svelte:head>
  <meta property="og:site_name" content="My Svelte App" />
  <meta property="og:image" content={$page.data.ogImage || defaultOGImage} />
</svelte:head>

<slot />

Prerender Hook

Generate OG images during prerendering:

javascript
// src/hooks.server.js
import { env } from '$env/dynamic/private';
import fs from 'fs';
import path from 'path';

const generatedImages = new Set();

export async function handle({ event, resolve }) {
  // During prerendering, generate OG images
  if (event.url.pathname.startsWith('/blog/')) {
    const slug = event.url.pathname.split('/').pop();
    
    if (!generatedImages.has(slug)) {
      await generateOGImage(slug);
      generatedImages.add(slug);
    }
  }
  
  return resolve(event);
}

async function generateOGImage(slug) {
  const post = await getPost(slug);
  
  const response = await fetch('https://ogimageapi.io/api/generate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': env.OG_IMAGE_API_KEY
    },
    body: JSON.stringify({
      title: post.title,
      subtitle: post.excerpt,
      template: 'blog',
      theme: 'dark'
    })
  });
  
  const buffer = await response.arrayBuffer();
  const outputPath = path.join('./static/og', `${slug}.png`);
  fs.writeFileSync(outputPath, Buffer.from(buffer));
}

Adapter Configuration

Vercel

javascript
// svelte.config.js
import adapter from '@sveltejs/adapter-vercel';

export default {
  kit: {
    adapter: adapter({
      runtime: 'nodejs18.x'
    })
  }
};

Node

javascript
// svelte.config.js
import adapter from '@sveltejs/adapter-node';

export default {
  kit: {
    adapter: adapter()
  }
};

Best Practices

  1. Use server routes for dynamic OG images
  2. Generate statically when content is known at build time
  3. Cache responses — Set appropriate cache headers
  4. Use layout-level defaults — Fallback for pages without custom OG
  5. Test with dev tools — Check meta tags are correct

Generate stunning Open Graph images programmatically.