➡️ This post was originally published on the SQUER Blog:
https://squer.at/blog/bridging-the-gap-between-gatsby-and-open-graph-images
Gatsby has become my go-to for building static web sites, mainly due to the combination of the React ecosystem with optimized SEO and great performance. But, when it comes to content-heavy web apps, the Open Graph Protocol offers an additional boost for your Gatsby project, as it provides the needed metadata to publish the best of your content on social media, or for SEO in general:
For example, the image you see on Twitter or LinkedIn next to a posted link, is usually provided by the Open Graph Protocol. But the more you work with Gatsby and the Open Graph Protocol, the more you find out that things are not that easy, as they could or should be.
The problem
Usually the Open Graph Images are created manually during the content creation. This has two downsides:
- You have a tooling gap, in terms of that you are building your content with Markdown and React templates at build time. But still, your Open Graph Images are being created manually with tools like Photoshop.
- Open Graph Images easily run out of sync with the content, as they are not updated automatically on changes of the Markdown file.
The solution
A solution for both problems is to integrate the creation of Open Graph images into the Gatsby build pipeline, by providing a template for your actual page, and one for your Open Graph Image.
On each change of the content, both the corresponding page and the Open Image are recreated by the usage of the given template.
Use a Gatsby Plugin: Open Graph Images
I created a Gatsby Plugin (gatsby-plugin-open-graph-images) for exactly this purpose. Once it is installed and configured in your gatsby-config.js
(
plugins: ["gatsby-plugin-open-graph-images"]
), it exposes a simple createOpenGraphImage() method which hooks into the Gatsby build pipeline:
const { createOpenGraphImage } = require("gatsby-plugin-open-graph-images");
exports.createPages = async ({ actions }) => {
const { createPage } = actions;
const openGraphImage = createOpenGraphImage(createPage, {
path: "/og-image/index.png", // (1)
component: path.resolve(`src/templates/index.og-image.js`), // (2)
size: {
width: 400,
height: 50,
}, // (3)
context: {
description: "a image created with gatsby-plugin-open-graph-images",
},
});
};
There are two important parts within this snippet:
-
First of all, it creates an image under the given path (1), with a given size (3). The image is therefore available as
https://yourdomain.com/og-image/index.png
. With a library like react-helmet you can add this image to your header:
<Helmet>
<meta property="og:image" content={domain + "/og-image/index.png"} />
<meta property="og:image:width" content="400" />
<meta property="og:image:height" content="50" />
</Helmet>
Please keep in mind, that the Open Graph Protocol requires an absolute URI, which contains the domain.
-
And secondly, it makes it possible to define a React component from which the Open Graph Image is then derived. This gives us all the feature we know from
createPage()
, like providing data as a GraphQL query, or providing acontext
.
Usage during createPage()
As described above, the creation of Gatsby pages and the corresponding Open Graph images usually goes hand in hand. Thus, a common use case is to use createOpenGraphImage()
within createPage()
.
const result = await graphql(`
{
allArtistsJson {
nodes {
id
name
}
}
}
`)
result.data.allArtistsJson.nodes.forEach(({ name, id }) => {
createPage({
path: `artists/${id}`,
component: path.resolve(`src/templates/artist.js`),
context: {
id: id,
ogImage: createOpenGraphImage(createPage, { // 1
path: `og-images/artists/${id}.png`,
component: path.resolve(`src/templates/artist-og-image.js`),
context: { id }
})
}
});
});
As createOpenGraphImages
(1) returns a metadata object, we can easily pass this as context to the created page. The usage in the page can then rely on the context information:
const ArtistPage = ({ data, pageContext }) => {
return (
<>
<Helmet>
<meta property="og:image" content={domain + pageContext.ogImage.path}/>
<meta property="og:image:width" content={pageContext.ogImage.size.width}/>
<meta property="og:image:height" content={pageContext.ogImage.size.height}/>
</Helmet>
...
</>
);
};
Conclusion
This approach of deriving Open Graph images from React components and integrating their creation into the Gatsby build pipeline helped us to increase consistency and to improve our velocity. I hope that the idea and the plugin will serve you as well.
Top comments (2)
May I know whats the content of the src/templates/artist-og-image.js? I am trying to create a blog with dynamic og and hoping this can help me. Thanks!
This is awesome! I have been looking into implementing this feature down the line on my portfolio/blog. Thanks for making the process easier!