Bridging the Gap between Gatsby and Open Graph Images

June 15th, 2020 · 4 mins read

Derive and generated Images for the Open Graph Protocol directly from React Components within your Gatsby Project.

David Leitner

An introduction on how to derive Open Graph Images directly from react components during build time, without all the ceremony. This allows the creation of Cover Images for Social Media with full GraphQL query support and smooth integration into your Gatsby build pipeline.

...

The Open Graph Protocol

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:


Twitter Card Metadata for this post provided by the Open Graph Protocol.

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 usual process of adding Open Graph Images to Gatsby Pages

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.



An improved process of adding Open Graph Images to Gatsby Pages

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 a context.

Usage during page creation

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.

Further Information:

David Leitner
TwitterGithubLinkedinXing
David Leitner ist Geschäftsführer und Engineering Lead bei SQUER Solutions und beschäftigt sich mit der Architektur, Konzeption und Umsetzung von Web Anwendungen in Front- und Backend. Seit 2016 hat David den Begriff MicroFrontends maßgeblich mitprägte und seine Ideen und Erfahrungen auf internationalen Konferenzen prolongiert. Er ist außerdem Co-Host des Podcasts DeveloperMelange, unterrichtet an der FH Technikum Wien in Post-Diploma Kursen zu Software Architektur und initiiert die CodeCrafts Conference in Wien. Er ist Autor zahlreicher Fachartikel und häufiger Vortragender.

March 25 & 26, 2021 · Vienna

Wir sind stolzer Host einer Konferenz rund ums Thema Softwareentwicklung.