Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The practical SvelteKit pattern is a server endpoint that returns an ImageResponse. Install @ethercorps/sveltekit-og v4 for Svelte 5, register its Vite plugin, create a Svelte component (or HTML template), and return that component from src/routes/.../+server.ts. Use request-time rendering for content that changes per request; use prerendered entries when every image variant is known during the build.

What you are building

An Open Graph image is the preview graphic social networks and messaging clients can show for a URL. In SvelteKit, the image itself can be another route, such as /og.png or /docs/[...slug]/og.png. The route receives a request, renders a Svelte component through SvelteKit OG, and sends the resulting PNG (or another supported output) as the response.

SvelteKit OG uses Satori to convert supported HTML and CSS into SVG, then Resvg to rasterize that SVG. It is not a headless-browser screenshot pipeline, so design your template around the CSS features the current SvelteKit OG documentation supports, especially flexbox-oriented layouts. Components and HTML/CSS strings are both supported.

Requirements and version choices

  • Svelte 5 or later.
  • SvelteKit 4.1.0 or later if you want the preferred sveltekitOG() Vite plugin.
  • @ethercorps/sveltekit-og v4. Earlier package versions are unmaintained according to the project guide.
  • A deployment adapter/runtime that can execute your endpoint and load the renderer and any fonts you use.

For SvelteKit 4.0, the project still documents its Rollup plugin; that path is planned for deprecation in SvelteKit OG v5. After changing Vite configuration, restart the development server.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install and configure SvelteKit OG

Install the package

npm i @ethercorps/sveltekit-og

Use the equivalent command for pnpm, yarn, or another package manager if your project uses one.

Register the Vite plugin

Add the plugin to vite.config.ts. Keep your existing SvelteKit configuration and insert sveltekitOG() in the plugins array:

import { sveltekit } from '@sveltejs/kit/vite';
import { sveltekitOG } from '@ethercorps/sveltekit-og/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [sveltekit(), sveltekitOG()]
});

The exact import path should match the v4 package documentation for your installed release. Restart Vite after saving this file.

Create a reusable Open Graph template

Put a component beside the route, for example at src/routes/og/OgTemplate.svelte. The root element should fill the output dimensions. If you use a component-level <style> block, enable CSS injection with <svelte:options css="injected" />.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<svelte:options css="injected" />

<script lang="ts">
  export let title: string;
  export let description: string = '';
  export let siteName: string = 'Example site';
</script>

<div class="canvas">
  <div class="brand">{siteName}</div>
  <h1>{title}</h1>
  {#if description}
    <p>{description}</p>
  {/if}
</div>

<style>
  .canvas {
    width: 1200px;
    height: 630px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 72px;
    box-sizing: border-box;
    background: #111827;
    color: white;
    font-family: Arial, sans-serif;
  }
  .brand { font-size: 30px; color: #93c5fd; margin-bottom: 28px; }
  h1 { font-size: 68px; line-height: 1.05; margin: 0 0 24px; }
  p { font-size: 30px; line-height: 1.25; margin: 0; color: #d1d5db; }
</style>

The documented example uses 1200 by 630 pixels. Treat that as a useful template size, not a universal requirement imposed by every social platform. Keep layouts simple, and verify any advanced CSS, external assets, or font behavior against the current package documentation.

Return an image from a SvelteKit server route

Create src/routes/og/+server.ts:

import { ImageResponse } from '@ethercorps/sveltekit-og';
import OgTemplate from './OgTemplate.svelte';

export const GET = async ({ url }) => {
  const title = url.searchParams.get('title') ?? 'SvelteKit Open Graph image';
  const description = url.searchParams.get('description') ?? 'Generated at request time';

  return new ImageResponse(
    OgTemplate,
    {
      width: 1200,
      height: 630,
      props: { title, description, siteName: 'Example site' }
    }
  );
};

Your installed v4 release may expose slightly different constructor typing; follow that release’s API reference if TypeScript reports a signature mismatch. The essential contract is unchanged: a +server.ts GET handler returns an ImageResponse.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Use the image in page metadata

In a page’s server load function, construct an absolute URL for the image route and pass it to your Open Graph metadata. A query-string example is:

const image = new URL('/og', url);
image.searchParams.set('title', data.title);
image.searchParams.set('description', data.summary);

return { image: image.href };

Render that value as the page’s og:image (and usually twitter:image) URL in your document head. The image endpoint should be publicly reachable by the crawler requesting the page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Dynamic route images with parameters

For documentation or blog pages, place an image route next to the parameterized page. For example:

src/routes/docs/[...slug]/og.png/+server.ts

Read params.slug, load the corresponding title, and pass it to the component:

import { ImageResponse } from '@ethercorps/sveltekit-og';
import OgTemplate from './OgTemplate.svelte';

export const GET = async ({ params }) => {
  const title = params.slug ? params.slug.replaceAll('-', ' ') : 'Documentation';
  return new ImageResponse(OgTemplate, {
    width: 1200,
    height: 630,
    props: { title, description: 'Documentation', siteName: 'Example site' }
  });
};

Sanitize or constrain values that come from the URL. Do not place untrusted strings into raw HTML; passing them as component props keeps the template boundary clear.

Choose request-time rendering or prerendering

Approach Use it when Trade-off
Request-time endpoint The title, status, locale, or personalization must be resolved when requested. Rendering work occurs on requests, so the selected runtime must support the renderer, Wasm, dependencies, and fonts.
Build-time prerender All image routes and their content can be enumerated during a build. Images become static files and avoid per-request rendering, but updates require another build.

Prerender one fixed image

If the image never changes at runtime, add this export to the route:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
export const prerender = true;

Prerender known parameter values

For parameterized routes, provide an entries generator so SvelteKit knows which variants to build. The project documentation demonstrates an entries function beside a catch-all documentation route. Conceptually:

export const prerender = true;

export async function entries() {
  const pages = await getDocumentationPages();
  return pages.map((page) => ({ slug: page.slug }));
}

Use the parameter key required by your route (for a catch-all route, that is commonly a slug string or array according to your SvelteKit version). Generated images are saved as static files, reducing runtime work.

Fonts, assets, and CSS limits

  • Bundle or load fonts in the manner supported by your adapter and SvelteKit OG version; do not assume browser font loading behaves the same way.
  • Prefer local, deterministic assets. A remote image that is unavailable at render time can produce an incomplete image or a failed response.
  • Use flexbox-oriented CSS and test each change. Satori supports a subset of HTML/CSS rather than the full browser layout engine.
  • Keep the root element exactly the output size, then test long titles, missing descriptions, non-Latin text, and very narrow screens where the image is displayed.

Deployment considerations

Vercel

The SvelteKit OG Vercel guide documents adapter and plugin configuration and warns that a Vercel Edge function’s total bundle must fit under 1 MB, including Wasm, dependencies, and fonts. That is a bundle-size limit, not a rendering-speed measurement. If your renderer and fonts cannot fit, use a runtime/adapter arrangement that permits them or move fixed images to prerendering.

Cloudflare Pages

Cloudflare’s official SvelteKit Pages documentation describes installing and configuring @sveltejs/adapter-cloudflare and implementing request handlers as SvelteKit endpoints. Confirm Wasm and asset behavior for the exact Pages runtime you deploy to; adapters do not all provide identical support.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Testing checklist

  1. Run the development server and request a simple image URL such as /og?title=Hello.
  2. Open the response directly and verify its content type and dimensions.
  3. Test encoded characters, ampersands, emoji, long titles, and absent query parameters.
  4. Run a production build with the selected adapter, then request the endpoint from the deployed URL.
  5. Inspect the rendered page source and confirm that og:image is an absolute, publicly reachable URL.
  6. If using prerendering, inspect the generated static output and confirm every expected parameter entry exists.

Troubleshooting common failures

“Cannot find module” or plugin errors

Check that v4 is installed, the import path matches that release, and the Vite server was restarted after editing vite.config.ts. On SvelteKit 4.0, use the documented Rollup path rather than assuming the newer plugin is compatible.

The image is blank or styling is missing

Ensure the component has a full-size root, add <svelte:options css="injected" /> when using component styles, and remove unsupported CSS until a minimal flex layout renders. Verify that fonts and images are available to the deployment runtime.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Build fails while prerendering

An entry is missing, a load function is throwing, or the route expects request-only data. Enumerate every slug in entries(), make data loading build-safe, and switch to request-time rendering when values cannot be known at build time.

Works locally but fails after deployment

Compare adapter/runtime capabilities, especially Wasm, font loading, bundle size, and outbound asset access. On Vercel Edge, check the complete 1 MB function limit rather than measuring only your application code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Social networks show an old image

The endpoint may be correct while a crawler is serving a cached result. Change the image URL when you intentionally need cache invalidation, and confirm the crawler can fetch the deployed route without authentication or bot challenges.

Or skip the browser setup

If you need a screenshot-style image of a rendered URL rather than a Svelte component pipeline, ScreenshotNeo provides a single HTTP request. It accepts cookie/consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, with the outcome reported in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

See the ScreenshotNeo API documentation for all options. cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Frequently asked questions

Can I return an HTML string instead of a Svelte component?

Yes. SvelteKit OG accepts HTML/CSS templates as well as Svelte components. A component is usually easier to type and reuse when titles and descriptions vary.

Is 1200×630 mandatory?

No. It is the dimensions used by the documented example. Choose dimensions appropriate for your consuming platforms and keep the component root and ImageResponse options consistent.

Should every image route be prerendered?

No. Prerender only when routes and data are known at build time. Personalized or frequently changing content belongs in a request-time endpoint.

Does this approach run a browser?

No. Satori produces SVG from supported markup and CSS, and Resvg rasterizes it. That makes it lightweight compared with a headless-browser capture, but it also means browser-only CSS and behavior are unavailable.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I use the same endpoint for PNG and JPEG output?

Use the output controls documented by the exact SvelteKit OG version you installed, then verify the response content type in your deployed adapter; the core route pattern remains a GET handler returning ImageResponse.

Where should Open Graph metadata be generated?

Generate the absolute image URL in the page’s load/data layer and emit it in the document head as og:image, alongside your other page metadata.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.