Zach’s ugly mug (his face) Zach Leat­herman

I was tired of building 474 separate pages for Open Graph Images

26 September 09, 2026

Prior blog post (if you want the full context): If I work really hard on my Open Graph Images, People will share my Blog Posts (2021 Aug)

Here’s the gist:

Open Graph images are those little pictures that show up when your site is shared on social media. […] Each individual blog post (on my website) has a dedicated Open Graph image page.

These Open Graph pages had the URL shape /web/:title/opengraph/ and there were 474 of them.

This was great from a purist’s perspective (in that the Open Graph pages were built similarly to how I build other websites) but my perspective has changed a bit. I don’t think that server rendering a static page for each of the 474 blog posts is necessary! 🫣

Now I use one /opengraph/ page that client renders (the horror!) the appropriate metadata for the Open Graph image. Client rendering here is an appropriate tradeoff for build time because this page is still going through a Chromium-based screenshot service and the ultimate deliverable is a static image. This page isn’t intended to be consumed by human beings (unless they really want to, I dunno, I’m not your dad).

Note that the caching mechanism hasn’t changed: it still lives in the screenshot service and the images aren’t being regenerated in either method.

I now use this approach on a few places and it’s made implementing Open Graph support on websites much easier to build and manage:

Importantly, there is no freeform mechanism on these pages to modify the content of the images via URL parameter. There is no ?text=… to control the title text, it’s keyed off of the local page URL and that alone. I don’t want y’all to put whatever text you want next to my picture on my website (you have to do that on your website 😘).


< Older
Use Speedlify2 to Continuously Measure Website Performance

Zach Leatherman IndieWeb Avatar for https://zachleat.com/is a builder for the web at Font Awesome and the creator/maintainer of Build Awesome (née IndieWeb Avatar for https://www.11ty.devEleventy/11ty), an award-winning open source website generator. At one point he became entirely too fixated on web fonts. He has given 89 talks in nine different countries at events like Beyond Tellerrand, Smashing Conference, Jamstack Conf, CSSConf, and The White House. Formerly part of CloudCannon, Netlify, Filament Group, NEJS CONF, and NebraskaJS. Learn more about Zach »

2 Reposts

Khalid ⚡soapdog

5 Likes

Khalid ⚡triswebFynn Ellie BeckerSimon Cox :SEO:Mastro.{js,ts}
6 Comments
  1. Robb Knight

    @zachleat This is really smart. I just nuked mine recently because I was fed up of making the ~1000 pages it needed. I'll keep this in mind if i want to do them again.

  2. Khalid ⚡

    @zachleat Jokes on you, I can make whatever OG image I want with any text I want :P

  3. Zach Leatherman

    @robb thanks! I forgot to mention in the post that it also solved some sneaky problems with seeing 404 errors if my local build requested a production URL screenshot before it was pushed! If that happens I just show a default now (better)

  4. Zach Leatherman

    @khalidabuhakmeh if it ain’t hosted on my domain it’s a deepfake (and you could do that before!)

  5. Robb Knight

    @zachleat Thats also a good point, I hit that a bunch of times and it's really annoying with Mastodon especially because it caches preview images.

  6. David Bushell ????

    i'm confused, are you generating the same 474 images every build (or worse, every request!)?

Shamelessly plug your related post

These are webmentions via the IndieWeb and webmention.io.

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)