Automatically Generate Social Sharing Images

Matías Hernández

Banner Image for Jam

Promoting your content on social media is an important part of the publishing process, but as anyone who has attempted to share their work online knows, social media is a black hole of content. It's really easy to publish, and then see your work lost in the endless stream of tweets and posts. But by sharing images or "Open Graph Images" for your content, you can stand out more!

These images are the ones shown as a previews in your followers' timelines, for example:

Creating a share image for each post is a significant burden, and can slow down the publishing process, but there is good news. You can automate this, and get beatiful social image cards with just a bit of upfront effort.

Before starting with this tutorial, we need to have a plan, and identify our outcomes. By the end of this article, we want to be able to automatically generate social media images by using the Cloudinary transformation API. This process will be part of a utility function that we can use in the Gatsby build process to generate the images for each article. We will asume that you have a running site using Gatsby, sourcing content from markdown or mdx, and that you have some knowledge of the gatsby-node API.

The result will be something like this. Obviously, it will depend of the template image that you use.

The text content of this image is automatically generated by Cloudinary transformation by adding a text overlay for the title, and for the tags.

Cloudinary transformations

Cloudinary has a powerful transformation API that allows users to manipulate images in different ways with simple url parameters. One of those manipulations is the ability to add text overlays.

You can use all of these features by creating a free Cloudinary account, and storing your social image there.

Cloudinary offers a collection of transformations to add overlays. You can combine these parameters to place a piece of text anywhere in an image. The most simple example is to use the l_text transformation that tells Cloudinary to add a text overlay.

Step 1: Add a text overlay transformation

https://res.cloudinary.com/matiasfha/image/upload/co_white,l_text:roboto_84:This is the example text/example_social_card.jpg

Here, we just used the image's Cloudinary url, example_social_card.jpg``, hosted under the account matiasfha` (or your cloud name in case you created your Cloudinary account) and we passed a transformation that is marked by using forward slashes.

The transformation part here is l_text:roboto_84:This%20is%20%20the%20example%20text This is composed by

  • l_text the text overlay transformation.
  • :roboto_84 the font family and font size we want to use.
  • This%20is%20%20the%20example%20text is a url encoded version of the text that we can use to write into the overlay.
  • co_white this sets the color of the text.

You can see more information about the text overlay transformation in this page. There, you can learn more about the styling parameters, use of custom fonts, line spacings, and other text related definitions.

Step 2 Position the text overlay

Next, we'll position the text in the place we need. To do that, we will add a few more transformations to this overlay.

First, we will set the origin position of the text to some corner of the image so we can then "translate" it by using the x and y axis. This is done by setting the gravity parmater.

g_south_west this can be read as "Set the gravity to south west point", or "put the origin of the image at the bottom left corner".

If we add that to the url, we get this:

https://res.cloudinary.com/matiasfha/image/upload/g_south_west,co_white,l_text:roboto_84:This%20is%20the%20example%20text/example_social_card.jpg

Now, to position this overlay, we will use pixels. Therefore, it's a good idea to define the size of the working canvas by limiting the width and height of the image. The most frecuently recommended size for a social sharing image (og:image) is 1200x627 pixels (1.91/1 ratio). To implement this, we will use another transformation for the image itself.

https://res.cloudinary.com/matiasfha/image/upload/w_1200,h_627,c_fill,q_auto,f_auto/g_south_west,co_white,l_text:roboto_84:This%20is%20the%20example%20text/example_social_card.jpg

We just added a new transformation between the forward slashes. `/w_120,h_627,c_fill,q_auto,f_auto This means that we want an image with

  • w_1200 1200px of width
  • h_627 627px of height
  • c_fill that will automatically fill the size
  • q_auto with automatic quality
  • f_auto and automatic format

Now, let's go back to the text overlay, and position the text in a better place. To do that, we will use the X and Y offsets. This is done by just adding x_<number>,y_<number>, where <number> is a value in pixels, used to move the overlay to some place.

https://res.cloudinary.com/matiasfha/image/upload/w_1200,h_627,c_fill,q_auto,f_auto/x_480,y_254,g_south_west,co_white,l_text:roboto_84:This%20is%20the%20example%20text/example_social_card.jpg

Step 3 Manage text overflow

What happen if the text is too long?

The text overlay will overflow. We can control that by setting a width for the overlay so the text will wrap, and not overflow. This is done by just using the w_<number> transformation on the overlay.

https://res.cloudinary.com/matiasfha/image/upload/w_1200,h_627,c_fill,q_auto,f_auto/w_600,x_480,y_254,g_south_west,co_white,l_text:roboto_84:This%20is%20th%20example%20text%20And%20now%20is%20too%20long/example_social_card.jpg

And now we are done! We have an image that has automatic text overlay on it. Now we need to transform that url into a reusable utility function that we can add to the Gatsby build process.

Create a utility function

Step 1: Identify our needs

The first step is to identify what we need, and what parameters we will require.

The url is composed by at least 2 of the following transformations: the base url, the cloud name, and the file name.

https://res.cloudinary.com/matiasfha/image/upload/w_1200,h_627,c_fill,q_auto,f_auto/w_600,x_480,y_254,g_south_west,co_white,l_text:roboto_84:This%20is%20the%20example%20text/example_social_card.jpg

  • base url: https://res.cloudiunary.com
  • cloud name: matiasfha
  • image transformation [w_1200,h_627,c_fill,q_auto,f_auto](https://res.cloudinary.com/matiasfha/image/upload/w_1200,h_627,c_fill,q_auto,f_auto/w_600,x_480,y_254,g_south_west,co_white,l_text:roboto_64:This%20is%20the%20example%20text%20but%20now%20is%20too%20long/example_social_card.jpg)
  • text overlay transformation `[w_600,x_480,y_254,g_south_west,co_white,l_text:roboto_64:This%20is%20the%20example%20text%20but%20now%20is%20too%20long]-
  • image file: example_social_card.jpg

Here, the variable parts can be:

  • the cloud name
  • the image file name
  • the text used in the text overlay
  • the text width
  • the text position
  • the text color, font family and font size

For simplicity, we will use the cloud name and the text content as variables.

Step 2: Create a utility function

Now, let's create the function:

1const createSharingImage = ({ cloudName, text }) => {
2
3}

What will this function return?

Since we need a url to load the image, it will only return a string:

1const createSharingImage = ({ cloudName, text }) => {
2 return imageUrl
3}

And, what will the function do?

The function will recreate the image url based on the pieces that we define within the url.

1const createSharingImage = ({ cloudName, text }) => {
2 const imageTransformations = []
3 const textTransformations = []
4 const baseUrl = `https://res.cloudinary.com/${cloudName}/image/upload/`
5 return imageUrl
6}

Let's see what each of these transformation variables will contain. We will use an array-like shape when writing them because it's more readable than a collection of text parameters.

Step 3: Define the image transfromations

The first variable is the content for the image transformation, a collection of strings that we will join with as a comma separated string. This shape allows us to add more transformations if we are required.

1const imageTransformations = [
2 'w_1200',
3 'h_627',
4 'c_fill',
5 'q_auto',
6 'f_auto'
7].join(', )

Step 4: Define the text transformations

Next, we have the text transformations:

1const textTransformations = [
2 'w_600',
3 'x_480',
4 'y_254',
5 'g_south_west',
6 'co_white',
7 `l_text:roboto_64:${encodeURIComponent(text)}`
8].join(',')

Step 5: Polish the final utility function

Finally, our function will just join all of these to return the image url.

https://gist.github.com/matiasfha/27fc927bfcc63416e2602aedbf73f423

Integrate this utility with Gatsby

You can use this utility function directly in any piece of code, including the post template in your Gatsby setup. Just check on the following.

Let's assume that you are using a common Gatsby setup like [gatsby-starter-blog](https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-blog).

This allows you to use markdown files to create your articles. In this instance, markdown files are stored under the content/blog folder, and the actual page build is based on the template available in /src/templates/blog-post.js.

The template uses a component named Seo, and this component uses react-helmet to create the required meta tags.

The open graph images (Facebook sharing cards and Twitter cards) are defined by a few html meta tags.

  • og:image An image URL, which should represent your object within the graph.
  • For Twitter, we need twitter:card and twitter:image.

Step 1: Update the Seo component

So, we will update the Seo component to use our createShareImageutility function.

https://gist.github.com/matiasfha/890bb2c6338bed840db618558628ff7f

We will use some of the data that already comes into the component- in this case, the title. Let's add the call to our function under defaultTitle (line 31).

1const ogImage = createSharingImage({ cloudName:'Your cloudinary cloud name', text: title })

And now, let's add the new meta tags into Helmet by adding the following at line 72:

1{
2 name:'og:image',
3 content: ogImage
4},
5{
6 name: 'twitter:image',
7 content: ogImage
8}

Step 2: Test the new social images

After saving, run your new code in development mode by calling gatsby develop in the terminal. Open any article in your browser, and check the element of the page with your developer tools. You should be able to see the new meta tags inside the <head> tag, indicating the new sharing images hosted in Cloudinary.

Let's tap into the Gatsby build process

One of the benefits of using Gatsby as a framework is the API that allows you to tap into the build process at any point.

Gatsby offers a powerful API that allows us to get all of the content used as sources through a Graphql interface.

To be able to use these APIs, you need to add or modify the nodes. This is done by using the file gatsby-node.js. It is the file where we will add the required code in order to add a new attribute to some Nodes to host these sharing images.

Let's return to our example site, created by gatsby-started-blog. We know that we have the seo.js component that allows us to manipualte the content of the header by adding new meta tags used by the search engine crawlers.

Whe we are talking about the articles in the site, the data rendered by the seo component comes from the frontmatter. So if we want to automatically add the sharing image, we need to add that attribute to the article's frontmatter.

Step 1: Manage schema definitions

To do this, we need to change or update the schema definition used by GraphQL. We will use the createSchemaCutomization API to add a field extension.

The extension that we will add will be named ogImage.

Let update the content in the gatsby-node.js file.

Since this file already uses createSchemaCustomization, we will just add more logic to it. First, let's destructure the actions argument to get access to the createFieldExtension API.

Read more about schema customization in the Gatsby docs.

1const { createFieldExtension, createTypes } = actions

Now, let's use createFieldExtension to create the extension ogImage.

1createFieldExtension({
2 name: 'ogImage',
3 extend(options, prevFieldConfig){
4 return {
5 resolve(source) {
6 return createSharingImage({ cloudName: 'matiasfha', text: source.title })
7 }
8 }
9 }
10 })

Here, we will do the call to our crateSharingImage, and will pass the data required: the cloudName (that can come from env variables), and the text that will only be in the title.

This function is extending the Node fields, and reading the data from the source node.

You can see the end result of this change in the following file in the example repository

Step 2: Use the new field extension

Now, we need to use this extension. The extensions are used in the GraphQL schema.

In the same place in the file, you will see a call to createTypes. This actually defines the GraphQL schema. Update the FrontMatter type to add the new field.

1`type Frontmatter {
2 title: String
3 description: String
4 data: Date @dateformat
5 ogImage: String @ogImage
6}

We tell Gatsby that the frontmatter of the files will have a String field/attribute named ogImage that will automatically resolve to the url created by createSharingImage.

Step 3: Update Seo component

Now, the last step is to update the seo.js component to write the new meta tags from this new data.

So, let's receive this attribute as a prop:

1const SEO = ({ description, lang, meta, title, ogImage = '' }) => {

and add this at the bottom of the Helmet call:

1{
2 name: `twitter:image`,
3 content: ogImage
4 },
5 {
6 name: `og:image`,
7 content: ogImage
8 }

Step 4: Update the post template

Finally, update the blog-post.js template, and add the ogImage` prop:

1<SEO
2 title={post.frontmatter.title}
3 description={post.frontmatter.description || post.excerpt}
4 ogImage={post.frontmatter.ogImage}
5 />

Now, run your site with gatsby develop, and you will be able to see the automatic ogImage, generated for your artilces, directly in the meta tags, or by checking the query in the GraphQL playground.

You can find a working version of this in this repository in github and also check this codesandbox

## Summary

In this article, we leveraged the power of Cloudinary image manipulation through the transformation url to automatically add text to a pre-defined image. We also wrote this as a reusable function, and then used that function inside Gatsby build system to automatically add the sharing images to our articles.

Learn More

Matías Hernández

Senior Frontend Engineer

Matías is a Chilean Software Engineer, father, host of two podcasts and egghead, and Escuela Frontend, instructor.

He focuses on front-end development and shares what he knows and learns with the community through articles and video lessons tailored to the Spanish community.

Matías host two podcasts: Café con Tech and Control Remoto, and write for different tech publications.

You can always reach him on twitter