Skip to content

Astro

Generate Astro OG Images with VectorFast Render

Add on-brand Open Graph images to an Astro site with VectorFast Render, signing image URLs or calling the REST API at build time, with caching notes and server-only secrets.

Published 2026-10-30 · Markdown version

VectorFast Render is in early access. Billing is not connected yet, and API keys are issued to waitlist members as access opens. Join the waitlist

Short answer: in your Astro layout, compute the og:image URL in the component frontmatter, which runs at build time (or on the server in SSR). Either call POST /v1/renders with your API key or sign a /i/blog-post.png URL with your signing secret. Secrets read in frontmatter stay on the server; only the finished URL reaches the HTML.

This guide uses the blog-post template (1200×630). Any template works the same way.

Before you start

  • A VectorFast Render API key (see the quickstart).
  • Declare it as a server secret so it is never bundled for the browser. With astro:env (Astro docs, read 2026-10-30, say secret server variables are not included in the final bundle):
astro.config.mjs
import { defineConfig, envField } from 'astro/config'

export default defineConfig({
  env: {
    schema: {
      VECTORFAST_API_KEY: envField.string({ context: 'server', access: 'secret' }),
      VECTORFAST_BRAND_KIT: envField.string({ context: 'server', access: 'secret', optional: true }),
    },
  },
})

Plain import.meta.env works too: variables without the PUBLIC_ prefix are only available in server code.

Option 1: call the REST API at build time

src/lib/og-image.ts
import { VECTORFAST_API_KEY, VECTORFAST_BRAND_KIT } from 'astro:env/server'

export async function ogImageUrl(params: { title: string, excerpt?: string, category?: string, author?: string }): Promise<string | null> {
  const response = await fetch('https://vectorfast.ai/v1/renders', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${VECTORFAST_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ template: 'blog-post@1', width: 1200, height: 630, brand_kit: VECTORFAST_BRAND_KIT, params }),
  })
  if (!response.ok)
    return null
  const render = await response.json() as { url: string }
  return render.url
}
src/layouts/Post.astro
---
import { ogImageUrl } from '../lib/og-image'

const { title, description, category } = Astro.props
const image = await ogImageUrl({ title, excerpt: description, category })
---
<html lang="en">
  <head>
    <title>{title}</title>
    <meta name="description" content={description} />
    <meta property="og:title" content={title} />
    {image && <meta property="og:image" content={image} />}
    {image && <meta property="og:image:width" content="1200" />}
    {image && <meta property="og:image:height" content="630" />}
    <meta name="twitter:card" content="summary_large_image" />
  </head>
  <body><slot /></body>
</html>

In a static build, each page calls the API once per build. Rebuilding with the same content returns the same cache key, so VectorFast answers from cache (cached: true) and does not render again; once billing is connected, those hits cost nothing. The URL in your HTML is immutable and safe to cache forever.

During a build with many pages, stay under 60 requests per 60 seconds per key: render pages in batches, or reuse URLs you stored from earlier builds.

Option 2: sign URLs locally

Signing is a local HMAC, so builds make no network calls and the image is rendered the first time a crawler fetches it.

Not available yet

Per-key signing secrets are not issued in early access. Until they are, use option 1; its url is the same kind of signed URL.

Copy signRenderUrl from Signed URLs into src/lib/sign-render-url.ts, declare VECTORFAST_SIGNING_SECRET in the astro:env schema the same way as the API key, and use it in the frontmatter:

src/layouts/Post.astro
---
import { VECTORFAST_SIGNING_SECRET } from 'astro:env/server'
import { signRenderUrl } from '../lib/sign-render-url'

const { title, description } = Astro.props
const image = signRenderUrl({
  template: 'blog-post',
  width: 1200,
  height: 630,
  params: { title, excerpt: description },
}, VECTORFAST_SIGNING_SECRET)
---
<meta property="og:image" content={image} />

If you pass an account brand kit, pin its version (brand: 'bk_…@3'); signed URLs reject unpinned account kits.

Caching summary

WhereWhat is cachedFor how long
VectorFast edge cache and R2The rendered image, by cache keyUntil the template, params, or brand kit version change
Browsers and crawlersThe image URL responseOne year (immutable)
Your buildNothing; each build asks again, and VectorFast answers from cache—

Astro's own options

Astro does not include an OG image renderer; community integrations built on Satori render PNGs during the build, which keeps everything in the repository and costs nothing per image. VectorFast Render is the better fit when the same branded cards are needed outside the site, when an AI agent should make them, or when you want a single brand kit (with a logo traced from a PNG) shared across projects.

FAQ

Does this work with Astro's SSR adapters? Yes. The frontmatter then runs on each request on your server; the API key or signing secret still stays server-side.

What if the build cannot reach the API? The helper returns null and the page renders without og:image. Add a static fallback image if you prefer.

Can I preview without spending credits? POST /v1/previews renders a watermarked preview that never spends credits, useful while designing the copy.