SEO with Gatsby and React-Helmet

Photo by MIXU
Photo by MIXU

React-Helmet is a way of managing all of the changes that are made to the head of an HTML document. With this component you can control the head using their react component. This allows you to add attributes to their component that will be added to the static HTML pages that Gatsby generates.

React-Helmet features all of the tags used in the head tag like title, base, meta, lang, link, script, noscript, and style tags.

How to install React-Helmet for Gatsby In your main gatsby directory just run this command to install react-helmet and react-helmet gatsby

npm install gatsby-plugin-react-helmet react-helmet

Then just add the plugin into your plugins array in gatsby-config.js

plugins: [`gatsby-plugin-react-helmet`]

I prefer having my Helmet object wrapped into another object so that I can control the usage of it. I created a seo.js file

const Seo = ({ description, lang, meta, title, image, pageKeywords, ogType, article, url}) => {
  ...
})

Inside of that seo container, I run a query to get the basic details about my site:

  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            keywords
            siteUrl
            imageUrl
            author {
              name
            }
            social {
              twitter
            }
          }
        }
      }
    `
  )

Then inside the container, I conditionally use the site data as backup if the attributes that I’m using from the parameters do not exist:

  const metaDescription = description || site.siteMetadata.description;
  const defaultTitle = site.siteMetadata?.title;
  const author = site.siteMetadata?.author?.name;
  const siteImage = image || {width: 941, height: 529, src: `${site.siteMetadata.siteUrl}${GenericLogo}`};
  const keywords = pageKeywords || site.siteMetadata.keywords;

Once I have some basic variables set up, then I export the Helmet component by:

  return (
    <Helmet
      htmlAttributes={{
        lang
      }}
      link={[...]}
      meta={[...]}
      ...
    />
  )

Then to use the Seo component, for a relatively static page:

  <Layout>
    <Seo title="All blog posts" />
  </Layout>

For one of my dynamically generated blog pages I use:

<Layout>
  <Seo
    title={post.frontmatter.title}
    description={post.frontmatter.description || post.excerpt}
    ogType="article"
    pageKeywords={tags}
    url={`${data.site.siteMetadata.siteUrl}${post.fields.slug}`}
    article={[
      {
        property: `article:published_time`,
        content: post.frontmatter.date,
      },
      {
        property: `article:modified_time`,
        content: post.frontmatter.modified_date || post.frontmatter.date,
      },
    ]}
  />
</Layout>

Metadata

Adding metadata to your helment component is really easy. You just add props and content to an array:


  let articleData = []
  if (article) {
    articleData = article;
  }

  return (
    <Helmet
      meta={[
        {
          name: 'viewport',
          content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0'
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:image`,
          content: siteImage.src
        },
        {
          name: `og:url`,
          content: url,
        },
      ].concat(meta, articleData)}
    />
  )

This is how you can setup your open graph, facebook, and twitter metatags. I’m adding another array from article data to allow invidual blog posts to set additional meta tags

Favorite Link Icons

To handle the favicons, you can define the link in the helmet component as an array of icon objects:

  import FavIcon64x64 from '../images/favicon-64x64.png'
  import FavIcon32x32 from '../images/favicon-32x32.png'
  import FavIcon16x16 from '../images/favicon-16x16.png'
  ...

  return (
    <Helmet
      link={[
        {
          rel: "icon",
          type: "image/png",
          sizes: "16x16",
          href: FavIcon16x16
        },
        {
          rel: "icon",
          type: "image/png",
          sizes: "32x32",
          href: FavIcon32x32
        },
        {
          rel: "shortcut icon",
          type: "image/png",
          href: FavIcon64x64
        }
      ]}
    />
  )

Handling the title

The way that I’m handling the title is a little different. I check to see if the title is the homepage and if it is then I use the defaultTitle from the gatsby config, otherwise I use the page title with the site name at the end.

  let pageTitle = title;
  let titleTemplate = null;
  if (title === "Home") {
    titleTemplate = defaultTitle;
    pageTitle = defaultTitle;
  } else {
    titleTemplate = defaultTitle ? `%s | ${defaultTitle}` : null;
  }
  return (
    <Helmet
      title={pageTitle}
      titleTemplate={titleTemplate}
    />
  )

So then when I define the title of a blog post, it will show up as Blog Post Title | Jelani Harris which is the seo that I want for my pages.


This post is apart of the series: Gatsby

A series about how I'm implementing this blog with Gatsby.

Profile picture

Written by who lives and works in Wisconsin building useful things, and thinks that pineapple on pizza is okay. You should follow them on Twitter