← Back to blog

Programmatically generate webpage preview images

∙ 5 min

One of my son's drawings

Here’s a summary of how I automagically generate my preview images for each page on my website.

What are meta tags

Image meta tags make your the preview to URLs on Facebook, X, LinkedIn, Slack, Teams or wherever else look good. Technically speaking, there are other meta tags like description and title that need to be available on the webpage to make the preview look good. Don’t neglect those or think the image is more important.

There are countless articles online that describe what meta tags are, and specifically what Open Graph (OG) meta tags are.

Meta tags are found in the head of your markup. The head houses mostly metadata about the page as opposed to the content of the page itself. Therefore the head is generally not visible in the browser unless you inspect the page’s source. The content is found in the body.

Screenshot of Typora

It’s in the head that you need to specify the URL of the preview image that will be auto-generated when posting to platforms like social media or messenger apps. Two are specifically interesting:

<meta property="og:image" content="{insert URL here}">
<meta name="twitter:image" content="{insert URL here}">

Aspect ratio and size

The aspect ratio and sizes of the OG and X preview images are different (at least they were as of today). I suggest keeping up to date with this as many platforms will change this from time to time. X should also fall back to using the OG image meta tag if the X image meta tag isn’t explicitly defined.

A quick search with your favorite search engine should lead you to some authoritative website that spell out the current aspect ratios and sizes.

What you really don’t want is for a social media platform or messaging app to go and try to fetch a preview image on its own, in the case where you neither define an OG image tag nor a X image tag.


Cloudinary's website

From Wikipedia:

[Cloudinary] provides a cloud-based image and video management services. It enables users to upload, store, manage, manipulate, and deliver images and video for websites and apps.

I store all images on this site on Cloudinary, and that lets magic things happen. I can manipulate swathes of images with a small URL modification in my source code. This is done by inserting transform syntax in the middle of the Cloudinary image URL.

Each page on this website has a main image (particularly my blog posts, and more on my image choices here: About my images). And if a main image isn’t explicitly declared, I’ve coded my HTML head to fall back to my homepage’s main image.

This is where I use Cloudinary to manipulate the page’s main image to fit the 120:120 px X and 1200:630 px OG specifications. I use the ar (aspect ratio) transform, I make sure the images crop with the c_crop transform, and then I scale the image down to the required height (and therefore width) with the h transform. All this without ever creating a new image by hand…it’s all derived on the fly from the source image. Transformation URL API reference →

<meta property="og:image" content=".../ar_1.905,c_crop/h_1200...">
<meta name="twitter:image" content=".../ar_1,c_crop/h_120/...">

A final touch

X preview images are small and square, and the page title and description show up pretty prominently. So things look good out of the box. For example:

But I wasn’t happy with the OG preview images being rendered in LinkedIn and Slack, for example. I wanted to overlay the page title on the preview image and decrease the image opacity. Automatically. Without creating the preview image myself.

I barely scratch the surface of what Cloudinary can do, but one great trick is being able to overlay text, images or really anything on another image.

I want to change this…

The resized preview image without text overlay and at full opacity

into this…

A fully rendered preview image with text overlay

<meta property="og:image" content=".../o_50/c_fit,l_text:Roboto_200_extrabold_center:{insert title}...">

I use the o transform to turn up the opacity and the l_text transform to overlay text on a new layer.

Note: You have to transform the page title string into a URL-encoded string. For example, you can’t pass an empty space into the URL. You have to transform it into %20. I can’t possibly prescribe how to do that here because every website framework will be different. Search engines are your friends here.


This is where things gets really great. For those running a multilingual site, you’re painfully familiar with the fact that pages, images and workflows explode in number and complexity with every language you add to your site. But with this programmatic approach to preview image creation, as long as the metadata string (in this case, the post title) are included in the localization process, the preview images create themselves.

Note: You should remember that many characters used in non-English languages can’t be passed in the URL without some encoding, and also that titles can be dramatically longer in some languages. So implement checks to make sure your text doesn’t break your preview image (eg. overflowing off the side, of expanding vertically past the image boundaries).

A series of multilingual preview images
The translations here are output of raw machine translation to illustrate this use case.

Closing thoughts

This workflow somewhat follows the DRY methodology in programming: Don’t Repeat Yourself. If you can programmatically derive images from a single source image, why wouldn’t you? You can change things in the future with a keystroke, and things are templatized and consistent. If you’re running a large website, scalable thinking upfront will likely pay dividends when business requirements or branding inevitably changes.

← Back to blog


X →

LinkedIn →