Astro

OG images in
Astro

`<OgImage>` in the head, every URL signed during the build.

Where it plugs in

The integration signs each image URL while Astro builds, without a single request to the API — a collection of a thousand posts builds as fast as an empty one. Each image is rendered on the first crawler hit and cached after that.

src/pages/blog/[...slug].astro

---
// npm i @shareglint/astro
// astro.config.mjs: integrations: [shareglint()] - reads SHAREGLINT_ACCOUNT_ID
// and SHAREGLINT_SIGNING_SECRET; every URL is signed during the build.
import { getCollection } from 'astro:content';
import OgImage from '@shareglint/astro/OgImage.astro';
import Layout from '../../layouts/Base.astro';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({ params: { slug: post.slug }, props: { post } }));
}

const { post } = Astro.props;
---

<Layout title={post.data.title}>
  <OgImage
    slot="head"
    template="blog-og"
    fields={{
      title: post.data.title,
      author: post.data.author,
      date: post.data.pubDate.toISOString().slice(0, 10),
      site: 'yourblog.com',
    }}
  />
  <slot />
</Layout>

Without the package

The same thing as one plain HTTP call — no dependency to install.

src/pages/blog/[...slug].astro

---
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Base.astro';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({ params: { slug: post.slug }, props: { post } }));
}

const { post } = Astro.props;

const res = await fetch('https://shareglint.com/v1/images?wait=true', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${import.meta.env.SHAREGLINT_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    template: 'blog-og',
    modifications: {
      title: post.data.title,
      author: post.data.author,
      date: post.data.pubDate.toISOString(),
      site: 'yourblog.com',
    },
  }),
});

const { url: ogImage } = await res.json();
---

<Layout title={post.data.title} ogImage={ogImage}>
  <slot />
</Layout>
The trap

Astro does not put `.env` into `process.env` while it reads `astro.config.mjs`. Export the variables in the shell or in CI, or pass them through `loadEnv` — otherwise the build warns and `<OgImage>` has no account to sign for.

What comes back

With ?wait=true the finished image arrives on the same connection — usually in about a second.

{
    "id": "img_01m08s3ez1zcv28h335g9923bw",
    "status": "completed",
    "url": "https://cdn.shareglint.com/renders/img_01m08s3ez1zcv28h335g9923bw.png",
    "duration_ms": 912
}

What it costs

A hundred images a month free, then $9 for two thousand. The same post rendered twice returns the existing URL and uses no quota — so rebuilding your site costs nothing.

Other frameworks