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

Use @ethercorps/sveltekit-og in a SvelteKit +server.ts route when you are generating an image from a template or HTML string. Use a browser-side capture library such as SnapDOM when you must reproduce an already-rendered element, including its computed styles and current state. Use Playwright or a screenshot API when the page depends on browser JavaScript or full-page behavior. SvelteKit server rendering has no browser layout to capture, so the correct approach depends on where the source HTML exists and how faithfully it must be rendered.

Choose the rendering path first

There are three distinct jobs that are often described as “converting HTML to PNG.” Pick the one that matches your input:

Need Recommended path What it does Main limitation
A deterministic card from a template or raw HTML @ethercorps/sveltekit-og and ImageResponse Runs in a server or edge-style runtime; Satori converts supported HTML/CSS to SVG and Resvg rasterizes it to PNG or JPEG. It is not a complete browser engine. Unsupported CSS and JavaScript-dependent layout will not behave like Chrome.
An element already mounted in the browser SnapDOM from an event handler or onMount Captures the browser’s computed styles, loaded assets and interactive state. It cannot run during SSR, and you must wait for data, images, fonts and transitions.
A page whose output depends on JavaScript, navigation or browser APIs Playwright or a screenshot service Launches a real browser and can wait for selectors, network activity and application state. Browser runtimes add deployment, memory and startup cost.

For Open Graph cards, deterministic server rendering is usually the shortest route. For a “save exactly what the user sees” button, capture the mounted DOM. For an entire third-party page, use a browser runtime or an API.

Generate a PNG on the server with SvelteKit OG

Install the package

From your SvelteKit project, install the renderer:

npm install @ethercorps/sveltekit-og

The package exposes ImageResponse, which can be returned directly from a SvelteKit server endpoint.

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.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Minimal raw-HTML endpoint

Create src/routes/og/+server.ts. This example returns a 1,200 × 630 image, the dimensions used in the project’s documented example:

import type { RequestHandler } from '@sveltejs/kit';
import { ImageResponse } from '@ethercorps/sveltekit-og';

const html = `
  <div style="display:flex;align-items:center;justify-content:center;
    width:100%;height:100%;background:#101011;color:#ddd;
    font-family:Arial,sans-serif">
    <h1 style="font-size:64px">Hello from SvelteKit</h1>
  </div>
`;

export const GET: RequestHandler = async () =>
  new ImageResponse(html, { width: 1200, height: 630 });

Run the development server and request /og. The response is an image, so it can be used directly as an Open Graph URL or saved by a client. Keep the root element at 100% width and height; otherwise the layout may not fill the output canvas.

Render a Svelte component

When the design is easier to maintain as a component, import that component and pass it as the first argument:

// src/routes/og/+server.ts
import type { RequestHandler } from '@sveltejs/kit';
import { ImageResponse } from '@ethercorps/sveltekit-og';
import Card from '$lib/Card.svelte';

export const GET: RequestHandler = async ({ url }) => {
  const title = url.searchParams.get('title') ?? 'SvelteKit';

  return new ImageResponse(
    { component: Card, props: { title } },
    { width: 1200, height: 630 }
  );
};

Make the component root define width: 100% and height: 100%. If the component uses a <style> block, inject that CSS into the image-rendering path as required by the package’s component guide; ordinary browser stylesheets are not automatically available to a server renderer.

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.

Accept dynamic data safely

Query parameters make the endpoint useful for per-article cards, but they also make it an untrusted input boundary. Validate length and allowed values before inserting text into the template. Escape user-provided strings if you build raw HTML, or pass them as component props. Keep the endpoint dynamic when titles or user data arrive at request time; do not prerender a route whose image changes for every request.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Capture the exact rendered Svelte element in the browser

Use this path for a download button, a dashboard tile, or any case where CSS, loaded fonts, animations and current UI state matter. Call SnapDOM from an event handler or inside onMount. SvelteKit can render a page on the server, but there is no browser layout there to capture.

Wait for the visual state, not only Svelte’s DOM update

tick() waits for pending Svelte DOM updates. It does not wait for a fetch request, image decoding, web-font loading or a transition. Await each of those operations before invoking the capture library.

<script lang="ts">
  import { onMount, tick } from 'svelte';
  // Import SnapDOM according to the version installed in your project.
  import { snapdom } from 'snapdom';

  let card: HTMLDivElement;
  let ready = false;

  onMount(async () => {
    await loadCardData();
    await tick();
    await document.fonts.ready;
    await Promise.all(
      Array.from(card.querySelectorAll('img')).map((img) =>
        img.complete
          ? Promise.resolve()
          : new Promise((resolve) => {
              img.addEventListener('load', resolve, { once: true });
              img.addEventListener('error', resolve, { once: true });
            })
      )
    );
    ready = true;
  });

  async function saveCard() {
    if (!ready) return;
    const result = await snapdom(card);
    const blob = await result.toBlob();
    const href = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = href;
    a.download = 'card.png';
    a.click();
    URL.revokeObjectURL(href);
  }

  async function loadCardData() {
    // Replace with your fetch and state assignment.
  }
</script>

<div bind:this={card} class="card">...</div>
<button disabled={!ready} on:click={saveCard}>Download PNG</button>

Keep capture-only styles on the element or in a class that is present when the capture runs. If the design contains a transition, wait for its completion or temporarily disable it; otherwise the image can contain an intermediate frame. Cross-origin images may require appropriate CORS headers or embedding as data URLs.

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

Use a headless browser when JavaScript is part of the image

Server-side Satori/Resvg is intentionally browser-free and efficient, but it does not execute application JavaScript or implement every CSS feature. A browser capture is the safer choice for charts that render after hydration, pages that require interaction, and layouts depending on browser APIs.

// scripts/capture.mjs
import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1200, height: 630 }, deviceScaleFactor: 2 });
await page.goto('http://localhost:5173/share-card', { waitUntil: 'networkidle' });
await page.waitForSelector('[data-capture-ready="true"]');
await page.screenshot({ path: 'share-card.png', fullPage: false });
await browser.close();

Install Playwright and its browser binaries in the environment that runs this script. Serverless platforms may not include those binaries or permit the required system libraries, so confirm the deployment runtime before committing to this design.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Make assets and fonts deterministic

  • Server images: do not assume a browser-relative path such as ./logo.png exists. Import small local images as Vite inline data URLs, convert larger files to data URLs or ArrayBuffers when appropriate, or provide a public absolute URL.
  • Fonts: load the exact font files explicitly before rendering. A fallback font changes line breaks and can move every element in the card.
  • Remote images: ensure the renderer can reach them at request time. A private URL, expiring URL or blocked host produces a missing image.
  • CSS: test flexbox, gradients, filters, grid and other advanced rules in the actual renderer. “Valid CSS” does not guarantee support in Satori’s subset.

Prerender, cache or render per request

Prerender stable cards

Set export const prerender = true when all image inputs are known at build time. SvelteKit can generate those images during the build, which removes request-time rendering.

Keep changing cards dynamic

Use a normal +server.ts request handler for titles, prices, user names or other values that change after deployment. Validate parameters and return an appropriate error instead of producing a misleading fallback image.

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

Cache repeated requests

Open Graph crawlers and social previews may request the same URL repeatedly. Cache by a stable key containing every visual input and the renderer version. Invalidate the key when the template, font or asset changes; otherwise an old image can survive a content update.

Common failures and fixes

Symptom Likely cause Fix
Blank or transparent output The root has no dimensions or the background is transparent. Set explicit width and height on the root and a background color when transparency is not intended.
Text wraps differently from the browser Missing font or a renderer-supported CSS difference. Embed/load the intended font and simplify unsupported layout rules; compare the output in the target runtime.
Logo or photo is missing server-side A relative path or inaccessible remote URL. Use a Vite data URL, an ArrayBuffer/data URL, or a reachable absolute URL.
Capture runs before content appears tick() completed, but fetches, images, fonts or transitions did not. Await the data promise, document.fonts.ready, image load events and transition completion.
Works locally, fails in deployment The adapter cannot launch a browser, lacks binaries, or has different network access. Use the browser-free OG path where possible, or verify Playwright binaries, libraries and outbound access in the deployment environment.
Dynamic route serves stale artwork A prerendered or overly broad cache key. Remove prerendering for changing inputs and include every visual parameter in the cache key.

Or skip the browser setup

ScreenshotNeo is the first screenshot API to try when you need a rendered URL without maintaining Playwright: it produces clean shots, bills only clean shots, and its paid plans start at $5.

One GET request returns PNG, JPEG, WebP or PDF. Cookie and consent banners are accepted and 60+ known consent platforms, newsletter popups and chat widgets are removed before capture. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and each response reports the result in X-Page-Verdict and X-Billed headers.

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

See the ScreenshotNeo API documentation for parameters and response handling. The same request in Python:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
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)

And in 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}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));

For SvelteKit cards that must match a browser exactly, use ScreenshotNeo’s controls for full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or a custom viewport, retina scale, PDF paper size/margins/landscape/page ranges, custom CSS and JavaScript, click-before-capture, hide selectors, waits for a selector, delay or network idle, ad/tracker/request/resource blocking, custom headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, image resizing, chosen cache TTL, signed links for public <img> tags, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which eases migration. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

The Free plan includes 1,000 shots per month with no card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000 and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is on every plan. Create a free ScreenshotNeo account to start.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

FAQ

Can SvelteKit convert arbitrary HTML to an image during SSR?

Only through a renderer such as SvelteKit OG. SSR itself creates HTML; it does not provide a browser layout or pixels.

Should an Open Graph endpoint be prerendered?

Prerender it when every input is fixed at build time. Keep it request-time when titles or other visual data change.

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

Why does the server image differ from Chrome?

Satori supports a defined HTML/CSS subset and does not execute browser JavaScript. Use a browser capture for full layout fidelity.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

What must be ready before a browser capture?

Wait for Svelte updates, application data, image decoding, web fonts and any transitions that affect the final frame.

Frequently Asked Questions

Can I return JPEG instead of PNG?

Yes. Use the image format supported by the renderer or screenshot service you select, and verify that your response headers and file extension match the returned bytes.

How do I capture only one Svelte element?

Bind the element with Svelte’s bind:this and pass that DOM node to your browser capture library, or use a screenshot API’s CSS-selector capture option.

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

Is a 1,200 × 630 card mandatory for Open Graph?

No. It is the documented example size; choose dimensions that fit the social destination and your design.

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.