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 widthh_627
627px of heightc_fill
that will automatically fill the sizeq_auto
with automatic qualityf_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 }) => {23}
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 imageUrl3}
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 imageUrl6}
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
andtwitter:image
.
Step 1: Update the Seo component
So, we will update the Seo
component to use our createShareImage
utility 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: ogImage4},5{6 name: 'twitter:image',7 content: ogImage8}
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: String3 description: String4 data: Date @dateformat5 ogImage: String @ogImage6}
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: ogImage4 },5 {6 name: `og:image`,7 content: ogImage8 }
Step 4: Update the post template
Finally, update the blog-post.js
template, and add the
ogImage` prop:
1<SEO2 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
## SummaryIn 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.