Although there are some excellent packages to automatically generate Twitter cards with Gatsby, like gatsby-remark-twitter-cards, some articles might have more success with custom thumbnail images. For example, without image:
With image:
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 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:
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.
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:
---
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
.
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 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.
...
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.
<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.
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:
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.
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
.
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.
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.
{
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.
Top comments (6)
I don't think this will work. According to
twittercommunity.com/t/not-whiteli... the "crawler and validator cannot execute Javascript and the tags must be static".
Gatsbyjs renders all of this statically. You can test this is working on any page of my site using the official card validator too cards-dev.twitter.com/validator. You can also see it working with one of my tweets: twitter.com/codyapearce/status/123...
It works because of this code part on your page:
Twitterbot will use something like this to crawl the site:
curl -v -A Twitterbot https://codinhood.com/post/visualizing-apple-deaths
.The
window
will not be available there. You can see that in the curl response, because there you have a duplicate slash character in you URL.You are right
It's better to fetch site's domain from siteMetadata in the GraphQL query instead of using window.location.origin.
Another thing I notice if that if you test it with your the same twitter account that is in the meta tags, it doesn't display the image, it took me a while to notice this until I test it with a different twitter account, I hope it helps.