HUGO · PAGE PARAMS TO SOCIAL CARDS

Keep Hugo static and still give every page a unique OG image.

Generate images in a prebuild step, publish them as ordinary static files, and let a single Hugo partial produce complete Open Graph and Twitter metadata. No runtime function and no public API key are required.

Define a small frontmatter contract

Most pages need only a title and description. Add optional fields for a template, accent color, or image override when a section needs distinct art direction. Keeping the card fields explicit makes the build reproducible and avoids scraping already-rendered HTML.

--- title: "Shipping a faster documentation site" description: "What changed in our Hugo build pipeline." author: "Docs team" ogTemplate: "article" ogAccent: "#2563eb" ---

Generate images in a Node prebuild

A small Node script can read Hugo content files or a JSON manifest, call the template API with OGSHOT_API_KEY in a header, and write results to static/og/. Hugo copies that directory into the final site unchanged.

const query = new URLSearchParams({ title: page.title, author: page.author || "Your team", site: "example.com", accent: page.ogAccent || "#2563eb", }); const response = await fetch(`https://ogshot.dev/v1/template/article?${query}`, { headers: { "x-api-key": process.env.OGSHOT_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); await fs.writeFile(`static/og/${page.slug}.png`, Buffer.from(await response.arrayBuffer()));

Run the script before hugo --minify in local production builds and CI. Keep a manifest hash of title, author, accent, template, and design version so unchanged pages do not need a network call. Identical requests are also cached by ogshot and cache hits are not metered.

Add one reusable head partial

Create layouts/partials/social-meta.html and include it from the document head. Hugo's absURL function turns the static asset path into the absolute URL social crawlers expect.

{{- $image := printf "og/%s.png" .File.ContentBaseName | absURL -}} <meta property="og:title" content="{{ .Title }}"> <meta property="og:description" content="{{ .Description }}"> <meta property="og:image" content="{{ $image }}"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="630"> <meta name="twitter:card" content="summary_large_image">

Allow intentional overrides

Some homepages, launches, or reports deserve a hand-designed card. Support an images frontmatter value first, then fall back to the generated slug path. That preserves Hugo theme conventions while giving ordinary pages automatic coverage.

For sites that cannot add a Node prebuild, generate HMAC-signed template URLs during deployment instead. The signed URL guide shows how to keep the secret in CI while emitting a safe, tamper-resistant image URL into the final HTML.

Raw API keys never belong in a Hugo template or config.toml committed to a public repository. Use CI secrets for build-time calls.

Verify the built URL, not just the PNG

After deployment, paste a representative article into the free inspector. It checks the actual live tags and image response, which catches incorrect baseURL settings, relative paths, missing production files, and dimensions likely to crop poorly.

Related guides: Eleventy, Docusaurus, and the screenshot API.

HUGO · STATIC AT THE EDGE

Generate the first article card.

Start free, keep the result static, and pay nothing for cached repeats.