Auto generate social media share images

How to create social share images with code so you never have to bug your designers again.

Gav McKenzie
Author
Gav McKenzie
Published
Mar 22, 2024
Topics
How-to, Industry, Engineering

Making images for websites is tough when you’re a developer. Usually, you have to grab hold of a friendly designer and badger them to make a nice image for you. Yesterday, I plugged together a nice technique for auto-generating images for this blog, so I thought I would write it up.

An example header box for an Etch blog post

Our blog header is a coloured box with three emojis inside it.

The colour of the box is generated using a combination of the topics in the article, selected from a pre-defined range. This gives some continuity to article colours while keeping the selection and maintenance minimal. Drive the design from the content.

The emojis are images, powered by the openmoji library. We use a script to run through all the emoji in the openmoji npm package and generate full SVGs that live in our static assets folder.

I shared an article from our blog in Slack the other day and noticed that it was always using the same share card image. Bit boring right? It would be nice if we had fresh images for each article so it didn’t always look the same.

We started off by creating an SVG canvas that would serve as the blog post image.

<svg viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="1200" height="630" fill="#ffffff" />
[..emojis]
</svg>

Next up, we added the blog header background. Our blog posts are powered by MDX using frontmatter. the front matter gives us access to the meta info for each post. What we are interested in is the topics.

We feed the topics into our colormap function and use that colour directly in the SVG. Our base colours are a bit stronger than the one used in the blog header so we add some transparency onto the hex colour to tone it down.

const color = colorFromTags(meta.tags);
return `
<svg viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="1200" height="630" fill="#ffffff" />
<rect x="0" y="0" width="1200" height="630" fill="${
colorMap[color]
}33" />
[...emojis]
</svg>`
`

Look at the awesome blue box we get.

A box with a blue background

Next, we need to add the emojis.

It would be awkward to use the emoji SVG paths directly in the image because they already have predefined coordinate values, so we cheat a bit and use the SVG <image> tag which lets us reference the SVGs like regular images. We could use a URL here, but that would mean either needing the local server running or pointing at production and Josh (Our security expert) has it too locked down for anything like that.

The answer is to base64 encode the SVG. I wouldn’t normally recommend this with SVGs as they are a bit heavy when encoded like this, but because we will re-process this later, it doesn’t matter.

We loop through the emojis from the article meta and pop them out into the SVG with a bit of coordinate juggling to get everything to sit nicely.

const svg = `<svg viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="1200" height="630" fill="#ffffff" />
<rect x="0" y="0" width="1200" height="630" fill="${
colorMap[color]
}33" />
${emojis
.map(
(emoji: string, i: number) =>
`<image x="${
150 + i * 300
}" y="165" width="300" height="300" href="data:image/svg+xml;base64,${emoji}" />`
)
.join('')}
</svg>`;

Now we have a sweet share card SVG!

Three emojis on a blue background

The problem is that most platforms do not support SVG share images so the last thing we do is run that through an SVG-to-image converter to flip this from an SVG to a JPEG and optimise its quality slightly for download speeds.

svg2img(
svg,
{ format: 'jpg', quality: 75 },
function (_error, buffer) {
fs.writeFileSync(path.join(outputPath, fileName), buffer);
}
);

This script runs as part of our CI process and quickly generates up-to-date social sharing images without the need for any manual involvement from any team members. If we ever decide to update the brand colours, the script will automatically update all of our blog-sharing images as well, giving us awesome, on-brand, share cards that are future-friendly.

The final generated social media share image