The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Generate an Open Graph (OG) image in Deno by rendering a card template to SVG with Satori, then rasterizing that SVG to PNG with Resvg. Supply a font explicitly, use a 1200 × 630 canvas, and return the result with Content-Type: image/png. Generate known cards at build time; use a Deno HTTP endpoint with caching when the image depends on request-time data.
How the Deno OG image pipeline works
An OG image is the preview image a social platform or messaging app may fetch when someone shares a page. For a text-heavy card, use separate tools for layout and rasterization: Satori lays out JSX-like content and produces SVG; Resvg converts the SVG into PNG bytes. This division matters because Deno’s documented OffscreenCanvas implementation does not provide a 2D or WebGL drawing context, so it is not a drop-in renderer for a designed card.
- Build a card template using Satori’s supported layout and styling subset.
- Load a font and pass its bytes, family, weight, and style to Satori.
- Render at 1200 × 630 to get an SVG string.
- Pass the SVG to a Resvg build compatible with the Deno runtime and obtain PNG bytes.
- Return the bytes as an image response, then cache the response using a key tied to the card’s content and design.
This Satori-to-Resvg sequence is also used by astro-og-images, whose documentation describes SVG rendering followed by PNG rasterization and a 1200 × 630 default, and by the dynamic Satori guide. Check the current package documentation when selecting imports and versions: the sources establish the pipeline, but do not establish a particular current Deno package version or a universal Resvg import path.
Choose build-time or runtime generation
| Approach | Best fit | Trade-offs to plan for |
|---|---|---|
| Build time | Titles, descriptions, and themes are known during a static build. | Images deploy as ordinary static assets and avoid rendering on a share request. A content change requires regenerating and redeploying the affected image. |
| Runtime endpoint | The card depends on request-time data, such as a slug, profile, or user-submitted title. | Fonts and the compatible Resvg/WebAssembly assets must be available at runtime. First-generation latency and repeated work make caching important. |
A useful decision rule: if the card content changes only when the site is built, prefer build-time generation. If it must reflect current data without a rebuild, use a runtime endpoint and cache rendered results. The Deno Deploy example migo describes SVG rendering, PNG rasterization, and caching as immutable assets; it demonstrates the pattern, not a performance guarantee for your own workload.
Recommended Free Tools
#1 Best Overall
Implement a runtime image endpoint
The following is the implementation shape: create a Satori element, provide font data, rasterize the generated SVG, and return PNG bytes from a Deno handler. Keep the Satori and Resvg imports aligned with the package versions and runtime target you deploy; adapters and WebAssembly loading differ, so do not assume a Node-only package entry point will work unchanged in Deno Deploy.
1. Prepare a font
Bundle a font file with the project or fetch it from a trusted source during deployment, then make its bytes available as an ArrayBuffer or byte array. Pass those bytes to Satori with a matching family name and weight. An explicit font avoids relying on an unspecified system font and helps keep line breaks stable between local and deployed renders. If your chosen loader returns a typed array, use the data form expected by your installed Satori version.
2. Render a card to SVG and PNG
This illustrative TypeScript handler shows the stages and response contract. The functions that load the font and invoke Resvg are deliberately isolated because the exact WebAssembly initialization and imports depend on the compatible Resvg build you choose.
Rank #2
import satori from "satori";
import { h } from "preact";
const fontBytes = await Deno.readFile("./fonts/Inter-Bold.ttf");
async function renderPng(title: string): Promise<Uint8Array> {
const svg = await satori(
h(
"div",
{
style: {
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
padding: 72,
backgroundColor: "#101827",
color: "#ffffff",
fontSize: 64,
fontWeight: 700,
},
},
h("div", { style: { color: "#9db4ff", fontSize: 24 } }, "ITECHGUIDES"),
h("div", { style: { marginTop: 24 } }, title),
),
{
width: 1200,
height: 630,
fonts: [
{
name: "Inter",
data: fontBytes,
weight: 700,
style: "normal",
},
],
},
);
// Implement this with the Resvg package/build supported by your target.
// It must return PNG bytes from the SVG string.
return await rasterizeSvgWithResvg(svg);
}
Deno.serve(async (request) => {
const url = new URL(request.url);
const title = url.searchParams.get("title") ?? "A Deno OG image";
const png = await renderPng(title);
return new Response(png, {
headers: {
"content-type": "image/png",
"cache-control": "public, max-age=300",
},
});
});
The sample intentionally makes the rendering boundary explicit rather than claiming one Resvg API works across all Deno targets. Implement rasterizeSvgWithResvg with the package entry point and WebAssembly setup supported by your deployment environment, and verify the output locally and after deployment. The short cache lifetime is only an example for mutable query-driven cards; use a longer-lived immutable response when the URL identifies fixed content.
3. Add real content, themes, and cache identity
In production, derive the card data from a validated route or record rather than accepting arbitrary HTML or unrestricted content in a public query parameter. Construct a deterministic cache key from all fields that affect pixels—such as title, subtitle, theme, and template version. If the inputs are content-addressed, use an immutable URL and an immutable cache policy. When the template changes, change its version in the key or URL so old cached images do not linger under the new design.
Design details that prevent broken cards
- Size: Render a 1200 × 630 image. Keep essential text and logos away from the outer edge so cropping or interface overlays are less likely to obscure them.
- Layout: Satori supports a CSS/layout subset, not the full browser layout engine. Prefer explicit flexbox-style composition and test every property the template uses.
- Fonts: Bundle or deliberately fetch font files. Missing font data can produce fallback glyphs and changed line wrapping. Test non-Latin titles with the actual glyph coverage your font supplies.
- Long or empty data: Set limits for titles and subtitles, decide how to wrap or shrink long text, and provide a meaningful fallback for missing values. Test those cases before exposing the endpoint.
- Remote images: Validate image URLs, restrict where the server can fetch from, and apply timeouts. Handle an unavailable image with a fallback rather than failing the entire OG response.
- Public access: Social crawlers generally fetch OG images anonymously. Do not put secrets or authenticated data in the public URL or depend on a viewer’s session to render the image.
Use Deno Web APIs for image data, not as a card-layout substitute
Deno’s Web Platform API reference documents OffscreenCanvas and createImageBitmap() for image decoding and PNG encoding. However, the documented implementation returns null for getContext("2d"), getContext("webgl"), and getContext("webgl2"). That means these APIs may help with image data workflows, but they do not replace Satori for laying out a text-rich card in the documented environment. Confirm current support for the specific Deno runtime and deployment target you use.
Rank #3
Return and cache the image correctly
Set Content-Type: image/png on the response and make the image URL stable for the same card content. Choose cache headers based on whether a URL can ever produce different pixels: mutable content needs revalidation or a controlled TTL; a versioned, content-addressed URL can be cached as immutable. Include the template version in the cache identity so design changes trigger a new image. These policies reduce repeat rendering, but do not remove the need to plan for cold starts, font loading, or WebAssembly asset availability.
For static sites, generate the PNGs in the build and serve them as static assets. For runtime generation, monitor the endpoint’s errors and latency in your own deployment; the cited examples describe architectures, not comparative latency, cost, or reliability measurements.
Troubleshooting Deno OG image generation
The endpoint throws while importing or initializing Resvg
Likely cause: the selected package build expects a different runtime, native support, or WebAssembly loading method. Fix: choose a Resvg build documented for the target, follow its Deno/WASM initialization instructions, and test a minimal SVG-to-PNG conversion before adding the full template. Ensure required WASM assets are included and resolvable in deployment.
Rank #4
The image is blank or the response is not a valid PNG
Likely cause: the endpoint returned SVG text or an error body while advertising PNG, or rasterization failed. Fix: inspect the response status and bytes, log failures server-side, and verify that the rasterization step returns PNG bytes before creating the response. Keep the declared content type consistent with the actual payload.
Text is clipped, wraps unexpectedly, or has missing glyphs
Likely cause: Satori’s supported CSS differs from browser CSS, font bytes or weight metadata are wrong, or the font lacks the needed characters. Fix: simplify the layout to supported flexbox properties, load the intended font explicitly, and test long and non-Latin examples against the deployed output.
A missing background image makes the whole request fail
Likely cause: an external host is slow, unavailable, or rejects the runtime request. Fix: validate and constrain remote URLs, set a fetch timeout, and render a fallback card if an optional image cannot be obtained.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
Changes do not appear after a template update
Likely cause: the old image is still cached at the same URL. Fix: include a deterministic template version in the URL or cache key and use the matching cache policy for mutable versus immutable content.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your goal is to capture an existing page rather than design a branded OG card, ScreenshotNeo provides a website screenshot API and MCP server. For your own generated OG endpoint, the same API can capture its rendered page for inspection; it does not replace the Satori-and-Resvg image-generation pipeline above.
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 request options. Its clean-shot workflow accepts consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Free tools Windows power users keep installed
One-click scans. No signup required.
Frequently Asked Questions
Can Deno’s OffscreenCanvas draw the whole OG card?
Not in the documented implementation: its 2D and WebGL context requests return null. Use a layout renderer such as Satori for the card.
Should I generate every image when a page is requested?
Only when the card depends on data that must be current at request time; otherwise generate it during the build and serve the PNG as a static asset.
Quick Recap
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.

