How to generate path-specific static OG images using Astro
OG images are awesome. I was talking with some friends about the right of first refusal, which they had never heard of.Being the good friend I am, I send them this link, via WhatsApp and was greeted by the following sight:
How cool is this? My friends did not even have to visit the page to get to known what that right of first refusal means. One downside of this, might be that you will have less traffic. I believe that the upside of this, having an additional communication channel of showing why your page might be of interest, is worth it.
With the release of Astro 2.0, a framework to build super quick websites, mainly useful if you want to make a static site such as a blog, and the awful state of my personal site, this was a perfect storm for another side project - I swear I will finish this one - with the aim of updating my personal site and having page-specific OG images.
Vercel saves the day once again?
I quickly stumbled upon Vercel’s OG Image generation library and this blog post by Thomas Ledoux using Vercel OG image generation to an Astro project, which can generate different OG images using HTML and even Tailwind(!) on the fly.
We could use this to make custom OG images for pages on our blog in the following way:
- Create a base layout for the OG images that accepts parameter and uses those parameters in layout.
- Create an API endpoint, which consumes query paraemeters and uses them to generate a parameter-based OG image, mentioned in (1). e.g.
/api/og
, using query parametertext
. - Set the
meta
og-image
tags of all pages equal to the API endpoint in (2) with the correct query parameters. E.g. imagine we have some page for which we want the OG-image to say Hello World!, we should add themeta
og-image
tag to refer to${YOUR_URL}/api/og?text=Hello%20World
. - Done!
This does exactly what I wanted, but it needs to run a serverless function on the background. Once you build your site and you do not have a serverless function running on the background, your site will not have any OG images, withstanding page specific OG images.
Serverless < Static
I like static sites. The idea of a site just living their best life and not needing any server to function just makes me happy. That is why I wanted to have a similar experience as using vercel’s image generation library, but my whole site being static.
That does mean that I cannot simply link the API endpoint, as the API endpoint will be dead when I build my site. If we think about it, we do not need the API endpoint to be active at all times, we only need them to generate the OG images that are mentioned by our pages. Using this insight, we can achieve our hopes and dreams of static page specific OG images by the following procedure:
- Change all
meta
og-image
tags to refer to e.g.${YOUR_URL}/assets/Hello%20World.png
- Make a custom Astro Integration which uses the
astro:build:done
hook to do the following:- Create an
assets/og
directory. - Loop over all created files and find which assets are referred
- Create the referred to assets inside the
assets/og
folder exactly as how they are called
- Create an
- Use your custom Astro integration to your
astro.config.mjs
file. - Use
npm run build
to build your static site andnpm run preview
to look at the build site and see if the assets are all working correctly.
That’s it! I found this astro integration which does something very similar, but they are using puppeteer to screenshot the generated OG images rather than using the packages behind Vercel’s OG image library (i.e. satori and resvg).
OG image hell
It worked, static page-specific OG images! Well, it worked to the extent that the html my pages generated were correctly linking to the OG image generated that belonged to that page. However, using tools such as https://www.opengraph.xyz/, Facebooks debug tool for OG images and just some tests on WhatsApp/Twitter/Facebook, I came across the following problems:
- WhatsApp wouldn’t show any image at all
- Facebook would only show the og-image which I made for the index of my site, but not page-specific ones.
I’m still trying to solve these problems, but if I know more I will let you know :-)