Skip to content

Preview a template in the browser

Every template can be opened as an HTML page instead of an image. Replace the file extension in the URL with .debug:

/blog/my-post/assets/og-image.png → the image
/blog/my-post/assets/og-image.debug → the preview page

The preview page renders your JSX with the browser’s engine, scaled down to fit the window, on a dark background so the image edges are visible. Hot reload works, so you can keep the page open while you edit the template.

Astro only serves a dynamic route for the params returned by getStaticPaths, in dev as well as in build. If your route lists ["png"] or relies on the default ["png", "jpg"], the .debug URL returns 404.

Add "debug" to the image types in dev only, so preview pages never end up in your build output:

src/pages/blog/[slug]/assets/[__image].[__type].ts
export const getStaticPaths = async () => {
const posts = await getCollection("blog");
return getStaticPathsForAssets(
modules,
posts.map((post) => ({ slug: post.id })),
import.meta.env.DEV ? ["png", "debug"] : ["png"],
);
};

Routes with prerender = false need no change: any type reaches the handler.

The default scale is 0.5, so a 1200×630 image shows as 600×315. Set debugScale in the template’s config to change it:

export const config: AssetImageConfig = {
width: 1200,
height: 630,
debugScale: 0.75,
};

Use 1 to see the image at its real size.

The colour around the preview comes from debugBackground in configure():

src/lib/assets.ts
configure({
debugBackground: "#ffffff",
// ...
});

The browser is not Takumi. Expect small differences in text wrapping, line height and font fallback. Emoji render with the browser’s own emoji font, not the configured provider. Always check the actual .png before shipping a design.