OG tags in Gatsby
OG tags are meta tags for making a webpage compatible with the open graph protocol. They’re commonly used by social networking sites such as Facebook and Twitter to turn a simple link into rich content. For example, check out this tweet. Here’s how to turn your blog links into rich content like the tweet.
Add a SEO component
Most gatsby starters already have a Seo component which uses react-helmet to set appropriate meta tags in the document head. The docs also have a guide in case you don’t have a Seo component for your blog. These tags look like following in the document head (which you may also check by opening the HTML inspector on this page):
<meta property="og:title" content="OG tags in Gatsby" />
<meta
property="og:description"
content="A comprehensive guide on implementing open graph tags in GatsbyJS."
/>Tweak for Twitter cards
react-helmet does the heavy lifting of rendering these tags in the document head. Here’s my Seo component which is a tweaked version of the default Seo component that comes with the starter. The important bits are highlighted. Note that this post has been updated for Gatsby v3 and uses the recommended gatsby-plugin-image approach.
// src/components/Seo.jsx
import React from 'react';
import Helmet from 'react-helmet';
import { useStaticQuery, graphql } from 'gatsby';
function Seo({ description, lang, meta, title, ogImage: ogImageProp }) {
const { site, ogImageDefault } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
siteUrl
}
}
ogImageDefault: file(absolutePath: { regex: "/assets/og-image/" }) { childImageSharp { gatsbyImageData(layout: FIXED, height: 630, width: 1200) } } }
`,
);
// use defaults if blog post did not provide any const metaDescription = description || site.siteMetadata.description; // the image url has to be an absolute url with http:// or https:// // relative links do not work const ogImage = ogImageProp || site.siteMetadata.siteUrl.concat( ogImageDefault.childImageSharp.gatsbyImageData.images.fallback.src, ); const ogTitle = title || site.siteMetadata.title;
return (
<Helmet
htmlAttributes={{
lang,
}}
title={ogTitle}
titleTemplate={title && `%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: ogTitle,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: 'og:image',
content: ogImage,
},
{ name: `twitter:card`, content: `summary_large_image`, }, {
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: ogTitle,
},
{
name: `twitter:description`,
content: metaDescription,
},
{ name: 'twitter:image', content: ogImage, }, ].concat(meta)}
/>
);
}For twitter:image OG tag, the recommended dimensions are 1200 * 630 pixels. I created a default image at /content/assets/og-image.png and retrieved it in the component with the graphql query. Using childImageSharp ensures the image is optimized. An important thing to note is the og-image tag should have a http:// or https:// url. Relative links will not work everywhere. A simple trick to do this is prefixing the siteUrl to the image source.
The remaining tags that would be needed are twitter:card as summary_large_image, twitter:title and twitter:description. A complete list of tags is available on the open graph protocol website.
Twitter has a card validator which is helpful for debugging any bugs or issues with the meta tags.
Add OG image for blog posts
The Seo component above already takes care of picking a default OG image in case the blog post template provides none. Using similar approach, for blog posts:
// src/templates/BlogPost.jsx
import React from 'react';
import { Link, graphql } from 'gatsby';
import Layout from '../components/Layout';
import Seo from '../components/Seo';
import ThemeProvider from '../components/ThemeProvider';
import ThemeContext from '../components/ThemeContext';
const BlogPost = ({ data, pageContext, location }) => {
const post = data.markdownRemark;
const siteTitle = data.site.siteMetadata.title;
const { previous, next } = pageContext;
return (
<ThemeProvider>
<section css={{ height: '100%', minHeight: '100vh' }}>
<ThemeContext.Consumer>
{({ theme }) => (
<Layout location={location} title={siteTitle}>
<Seo
title={post.frontmatter.title}
description={post.frontmatter.description || post.excerpt}
ogImage={data.site.siteMetadata.siteUrl.concat( post.frontmatter.ogImage.childImageSharp.gatsbyImageData .images.fallback.src, )} />
{/* rest of the stuff here */}
</Layout>
)}
</ThemeContext.Consumer>
</section>
</ThemeProvider>
);
};
export const pageQuery = graphql`
query BlogPostBySlug($slug: String!) {
site {
siteMetadata {
title
author
siteUrl
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
excerpt(pruneLength: 160)
html
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
ogImage { childImageSharp { gatsbyImageData(layout: FIXED, height: 630, width: 1200) } } }
timeToRead
}
}
`;
export default BlogPost;I’ve added a new field in the frontmatter of my markdown files called ogImage (highlighted graphql query) which points to the OG image path for the blog post. The image source is then prefixed by the siteUrl. For example the frontmatter for this post looks like:
title: 'OG tags in Gatsby'
description: 'A comprehensive guide on implementing open graph tags in GatsbyJS.'
date: 2019-08-09
categories: ['gatsby']
ogImage: ./og-image.pngSummary
To summarize this blog post here’s what I did:
- Added a
Seocomponent which sets the appropriatemetatags. - Included the OG image in the graphql query. The final url should be prefixed by the
siteUrlwhich begins withhttp://orhttps://. - Added the OG images for blog posts in frontmatter and included the field in the graphql query.
Related
Personal blog of Divyanshu Maithani. I’m a software engineer working mostly on frontend. I also create programming videos with my friend. In my spare time I play music and DoTA.
You may follow me on twitter or join my newsletter for latest updates.