Eleventy

OG images in
Eleventy

An async filter that returns the image URL inside the template.

Where it plugs in

Eleventy supports async filters, so you can fetch the image URL directly in the template. The built-in cache in `eleventy-fetch` means the next build does not touch the API at all.

.eleventy.js

const EleventyFetch = require('@11ty/eleventy-fetch');

module.exports = function (eleventyConfig) {
  eleventyConfig.addAsyncFilter('ogImage', async (title, author) => {
    const response = await EleventyFetch('https://imageapi.dev/v1/images?wait=true', {
      duration: '1y',           // same post = same image
      type: 'json',
      fetchOptions: {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.IMAGE_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          template: 'blog-og',
          modifications: { title, author, site: 'yourblog.com' },
        }),
      },
    });

    return response.url;
  });
};

// In the template:
// <meta property="og:image" content="{{ title | ogImage(author) }}">
The trap

`eleventy-fetch` caches by URL, not by request body. With POST, add the title to the cache key (a query parameter works) — otherwise every post gets the same image.

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.imageapi.dev/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