Use Front Matter Images for Twitter Card Images in GatsbyJS
Tags: gatsby, beginners, react
Published: 2020-02-08 01:06:48


Although there are some excellent packages to automatically generate Twitter cards with Gatsby, like [gatsby-remark-twitter-cards](https://github.com/alessbell/gatsby-remark-twitter-cards), some articles might have more success with custom thumbnail images. For example, without image:

![Twitter card without image](https://codinhood.com/static/8f06cec7122cb18600f0d82dd9783e7b/a4cd0/no-image-twitter.png)

With image:

![Twitter card with image](https://codinhood.com/static/7c9041114967db7ceff189a29bb6dd70/1bcd6/full-card.png)

This tutorial will show a simple way to add thumbnail images for Twitter cards to your Gatsby blog.

## Setup

The method described below requires a few packages like `react-helmet`, `gatsby-source-filesystem`, `gatsby-transformer-remark`, `gatsby-remark-images`, and `gatsby-transformer-sharp`. Luckily, the [gatsby-starter-blog](https://github.com/gatsbyjs/gatsby-starter-blog) template comes with all of these packages preinstalled and configured so we will use this template to illustrate. First set up a new repo using `gatsby new` according to the documentation:

```shell
gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
```

Everything is already set up and configured so there's nothing else we need to do to get started.

## Adding the image and front matter property

Our goal is to define an image in the front matter of one of our posts and pass that data to the `blog-post` template and finally to the `SEO` component where it will be added to the appropriate meta tags.

The `gatsby-starter-blog` stores blog articles in the `content/blog` folder. At this point, we can add an image to the `hello-world` folder or use the image, `salty_egg.jpg`, that comes with the template.

![Blog Structure](https://codinhood.com/static/89e5e9edd51f3a56a0bd9250abbe327f/c2b99/structure.png)

Open `content/blog/hello-world/index.md` and add a new front matter property named `thumbnail` with a string that points to the image file:

```shell
---
title: Hello World
date: "2015-05-01T22:12:03.284Z"
description: "Hello World"
thumbnail: './salty_egg.jpg'
---
```

## Accessing the thumbnail image in the blog-template

Next, we need to access the thumbnail image within the `blog-post` template and pass it to the SEO component. Go to `src/templates/blog-post.js` and scroll down to the `pageQuery` variable at the bottom of the file. Notice that we're grabbing the front matter data `title`, `date`, and `description`. To grab the `thumbnail` property we need to add the following right below `description`.

```jsx
export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      html
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
        description
        thumbnail {
          childImageSharp {
            sizes(maxWidth: 600) {
              ...GatsbyImageSharpSizes
            }
          }
        }
      }
    }
  }
`;
```

[Sharp](https://github.com/lovell/sharp) will process the image and provide various sizes that are smaller than the `maxWidth` we pass into `sizes`.

Next, go to the `BlogPostTemplate` component within the same file. Our goal is to pass the `thumbnail` to the `SEO` component within this template, so first pull the `thumbnail` property from the `markdownRemark` data and `frontmatter` object.

```jsx
...
const BlogPostTemplate = ({ data, pageContext, location }) => {
  const post = data.markdownRemark
  const siteTitle = data.site.siteMetadata.title
  const { previous, next } = pageContext
  const thumbnail = post.frontmatter.thumbnail // <---
  ...
}
```

Then pass the thumbnail into the `SEO` component below the `title` and `description` props.

```jsx
<SEO
  title={post.frontmatter.title}
  description={post.frontmatter.description || post.excerpt}
  thumbnail={thumbnail}
/>
```

## Passing Thumbnail in Meta Tags

The final step is to set the image in the twitter `meta` tags within the `seo` component. Open `src/components/seo.js` and pull in the thumbnail property.

```jsx
const SEO = ({ description, lang, meta, title, thumbnail }) => {
```

The `twitter:image` meta tag requires the full URL for the thumbnail image. We can get the image `src` from the `thumbnail` object which will look something like this:

![Thumnail object structure](https://codinhood.com/static/89e1e3a3d245cdb31f3dbd3850ee45c4/14e05/image-object.png)

Create a variable to hold the `src` string, but make sure to check that there actually is a `thumbnail` for that article as well. Otherwise, Gatsbyjs will crash on articles that do not have thumbnails because it will be looking for childImageSharp of an `undefined` object.

```jsx
const imageSrc = thumbnail && thumbnail.childImageSharp.sizes.src;
```

Now that we have the location of the image on the site, we need to add the full domain to the `imageSrc` string to create the full URL for the image. We can get the domain origin from the window object: `window.location.origin`. However, Gatsby builds often throw errors when `window` is `undefined` in that environment. So we need to do a quick check to make sure window is not `undefined`.

```jsx
let origin = "";
if (typeof window !== "undefined") {
  origin = window.location.origin;
}
```

Next, we can create the full URL for the image by concatenating the two variables.

```jsx
const image = origin + imageSrc;
```

Finally, add the twitter meta tag, `twitter:image`, to the array of tags with the `content` property pointing to the `image` variable defined above.

```jsx
{
  name: `twitter:image`,
  content: image,
},
```

## Conclusion

Now when you add a custom thumbnail to a blog post and share the link on Twitter the thumbnail will display with the card. Additionally, you can test how your cards will display by using the [Twitter Card Validator](https://cards-dev.twitter.com/validator).