April 2026 · 6 min read · Blog

Screenshot API for Svelte & SvelteKit — Server Endpoints, Stores, and OG Images

Integrate SnapAPI into Svelte and SvelteKit apps: server-only API routes, Svelte stores for state management, and automated OG image generation for your content.

Why Svelte Apps Benefit from a Screenshot API

Svelte and SvelteKit power a growing share of content sites, documentation platforms, portfolio sites, and SaaS dashboards. All of these share a common set of screenshot needs: OG image generation for social sharing, PDF export for reports and invoices, and visual regression testing in CI. SnapAPI is a plain REST endpoint — no framework-specific SDK, just fetch — which means it works identically in Svelte components, SvelteKit server hooks, and standalone Node.js scripts.

SvelteKit Server Route for Screenshot Proxy

In SvelteKit, always proxy SnapAPI calls through a server route to keep your API key out of the browser bundle. Create the route at src/routes/api/screenshot/+server.ts:

// src/routes/api/screenshot/+server.ts
import { env } from '$env/dynamic/private';
import { error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ url }) => {
  const target = url.searchParams.get('url');
  if (!target) throw error(400, 'url is required');

  const params = new URLSearchParams({
    url: target,
    format: url.searchParams.get('format') || 'webp',
    width: url.searchParams.get('width') || '1280',
    access_key: env.SNAP_KEY
  });

  const resp = await fetch(`https://api.snapapi.pics/v1/screenshot?${params}`);
  if (!resp.ok) throw error(resp.status, 'SnapAPI error');

  return new Response(resp.body, {
    headers: {
      'Content-Type': resp.headers.get('content-type') || 'image/webp',
      'Cache-Control': 'public, max-age=3600'
    }
  });
};

Your Svelte components call /api/screenshot?url=... — the API key never leaves your server. SvelteKit's streaming response support means the screenshot binary is piped directly to the client without buffering the entire image in memory.

Svelte Store for Screenshot State

For Svelte components that capture screenshots on demand, a writable store manages loading and result state cleanly:

// lib/stores/screenshot.ts
import { writable } from 'svelte/store';

interface ScreenshotState {
  loading: boolean;
  url: string | null;
  error: string | null;
}

export function createScreenshotStore() {
  const { subscribe, set, update } = writable<ScreenshotState>({
    loading: false, url: null, error: null
  });

  async function capture(targetUrl: string, options: Record<string, string> = {}) {
    update(s => ({ ...s, loading: true, error: null }));
    try {
      const params = new URLSearchParams({ url: targetUrl, ...options });
      const resp = await fetch('/api/screenshot?' + params);
      if (!resp.ok) throw new Error('Screenshot failed: ' + resp.status);
      const blob = await resp.blob();
      const objectUrl = URL.createObjectURL(blob);
      set({ loading: false, url: objectUrl, error: null });
    } catch (e) {
      update(s => ({ ...s, loading: false, error: e instanceof Error ? e.message : 'Error' }));
    }
  }

  return { subscribe, capture };
}

Use it in any Svelte component:

<script lang="ts">
  import { createScreenshotStore } from '$lib/stores/screenshot';
  const screenshot = createScreenshotStore();
</script>

<button on:click={() => screenshot.capture('https://example.com')} disabled={$screenshot.loading}>
  {$screenshot.loading ? 'Capturing...' : 'Take Screenshot'}
</button>

{#if $screenshot.url}
  <img src={$screenshot.url} alt="Screenshot" />
{/if}
{#if $screenshot.error}
  <p class="error">{$screenshot.error}</p>
{/if}

OG Image Generation for SvelteKit Content

SvelteKit content sites need OG images for every post or page. Hook into your build process or a post-publish webhook to generate screenshots automatically. A build-time script reads your content directory, screenshots each page, and saves the WebP images as static assets:

// scripts/generate-og.ts
import { readdir, writeFile } from 'fs/promises';

const BASE_URL = 'https://your-sveltekit-site.com';
const SNAP_KEY = process.env.SNAP_KEY!;
const OUTPUT_DIR = 'static/og';

const pages = await readdir('src/content/blog');

for (const file of pages.filter(f => f.endsWith('.md'))) {
  const slug = file.replace('.md', '');
  const url = `${BASE_URL}/blog/${slug}`;

  const resp = await fetch(
    `https://api.snapapi.pics/v1/screenshot?` +
    new URLSearchParams({ url, format: 'webp', width: '1200', height: '630', access_key: SNAP_KEY })
  );

  await writeFile(`${OUTPUT_DIR}/${slug}.webp`, Buffer.from(await resp.arrayBuffer()));
  console.log('OG image generated:', slug);
}

SvelteKit Hooks for Automatic Screenshot on Publish

If your SvelteKit app has a CMS or admin area where content is published, use SvelteKit hooks to trigger screenshot generation as a side effect of publish actions. The hook runs server-side, calls SnapAPI asynchronously (without blocking the response), and stores the screenshot URL in your database for later use as the og:image meta tag value.

Getting Started

Sign up at snapapi.pics, get your free API key (200 screenshots/month, no credit card), and add it to your .env file as SNAP_KEY. In SvelteKit, access it via $env/dynamic/private to ensure it is never exposed to the browser. Your first screenshot route is live in minutes — no npm packages, no configuration beyond the environment variable.

Add screenshot capabilities to your SvelteKit app

Free 200/month. No credit card. Works with any SvelteKit deployment.

Get Free API Key

Advanced Svelte Screenshot Patterns

SvelteKit Hooks for Global Screenshot Middleware

SvelteKit's handle hook in src/hooks.server.ts intercepts every request. Use it to add screenshot-related logic globally — for example, automatically generating and caching an OG image on first page visit if one does not yet exist. The hook checks whether the requested page has a cached OG image; if not, it dispatches a background job to SnapAPI and stores the result. Subsequent visits to the same page serve the cached OG image from your CDN. First-time visitors may get a generic fallback; all subsequent visitors get the custom screenshot.

SvelteKit Adapter Considerations

SnapAPI works identically regardless of which SvelteKit adapter you use. For adapter-vercel and adapter-netlify, server routes that proxy SnapAPI run as edge functions or serverless functions — they are stateless, so do not attempt to cache screenshots in memory. Use an external cache (Redis via Upstash, or a CDN with long TTL) instead. For adapter-node, a process-level Map cache works for single-instance deployments but should be replaced with Redis for multi-instance setups.

// Cache via Upstash Redis in a SvelteKit server route
import { Redis } from '@upstash/redis';
const redis = new Redis({ url: env.UPSTASH_URL, token: env.UPSTASH_TOKEN });

export const GET: RequestHandler = async ({ url }) => {
  const target = url.searchParams.get('url')!;
  const cacheKey = 'snap:' + Buffer.from(target).toString('base64').slice(0, 40);

  const cached = await redis.getBuffer(cacheKey);
  if (cached) {
    return new Response(cached, { headers: { 'Content-Type': 'image/webp', 'X-Cache': 'HIT' }});
  }

  const resp = await fetch('https://api.snapapi.pics/v1/screenshot?' +
    new URLSearchParams({ url: target, format: 'webp', width: '1280', access_key: env.SNAP_KEY }));
  const buffer = Buffer.from(await resp.arrayBuffer());
  await redis.setex(cacheKey, 3600, buffer);

  return new Response(buffer, { headers: { 'Content-Type': 'image/webp', 'X-Cache': 'MISS' }});
};

Svelte 5 Runes Integration

Svelte 5 introduces runes as the new reactivity primitive. Replace the writable store approach with a $state rune for screenshot state, and a $derived rune for computed values like whether the screenshot is ready to display. The API call pattern remains the same — a fetch to your server route — but the component code becomes more concise and the reactivity is more explicit. SnapAPI's synchronous response model (await the fetch, get the image) fits naturally with async rune patterns in Svelte 5.

Testing SvelteKit Screenshot Routes with Playwright

SvelteKit's official testing approach uses Playwright for end-to-end tests. Mock the SnapAPI fetch call in your Playwright test configuration using page.route() to intercept requests to api.snapapi.pics and return a fixture image. This makes your screenshot route tests fast, free, and deterministic — no real API calls in CI. Test the full route handler logic including caching, error handling, and response headers without consuming your SnapAPI quota. Sign up for your free key at snapapi.pics and start integrating in minutes.

One API, Every Use Case

SnapAPI is production-grade screenshot infrastructure serving teams across fintech, SaaS, agencies, e-commerce, edtech, and devtools. One API key covers screenshot in PNG, JPEG, and WebP, full-page capture, PDF export, OG image mode, JS-rendered web scraping, and structured data extraction. Free tier is 200 requests per month with no credit card required. Paid plans from $19 per month. JS, Python, Go, PHP, Swift, and Kotlin SDKs available on GitHub. Get started at snapapi.pics in under a minute.

SnapAPI is purpose-built for teams that need reliable, scalable screenshot generation without the overhead of maintaining Playwright or Puppeteer servers. Every request goes through a production-hardened Chromium instance that correctly renders JavaScript frameworks, web fonts, SVG charts, CSS animations, and third-party widgets. The API handles cookie banner dismissal automatically, supports custom request headers and cookies for authenticated pages, and returns binary image data synchronously so your integration stays simple. Sign up at snapapi.pics for instant access to the free tier — 200 screenshots per month with no credit card required, full feature access, and your API key available immediately after email verification.

All SnapAPI plans include access to screenshot, scrape, and extract endpoints, CDN caching with configurable TTL, full-page and viewport modes, custom viewport dimensions, wait_for CSS selector support, PDF export, and WebP output. The REST API is versioned, backward-compatible, and has maintained 99.9 percent uptime since launch. Integrate once, rely on it indefinitely. SDKs in JavaScript, Python, Go, PHP, Swift, and Kotlin are available on GitHub to accelerate your initial integration and provide typed wrappers around the raw HTTP calls. Get your free key at snapapi.pics.