Configuring social sharing cards in GatsbyJS
Tags: socialsharingcards, tutorial, introductory, twitter
Published: 2021-08-12 04:57:49

---
title: Configuring social sharing cards in GatsbyJS
published: true
date: 2021-08-11 22:00:00 UTC
tags: SocialSharingCards,Tutorial,Introductory,Twitter
series: Building a developer blog with GatsbyJS
canonical_url: https://MihaiBojin.com/personal-site/social-sharing-cards
---

![Photo: Social media apps](https://MihaiBojin.com/static/697c8dcd2f260c25e73f4835bde8fe9d/eed2b/nathan-dumlao-kLmt1mpGJVg-unsplash.jpg)<figcaption>"Photo by <a href="https://unsplash.com/@nate_dumlao?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nathan Dumlao</a> on <a href="https://unsplash.com/s/photos/twitter?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>"</figcaption>

🔔 This article was originally posted on my site, [MihaiBojin.com](https://MihaiBojin.com/personal-site/social-sharing-cards?utm_source=DevTo&utm_medium=organic&utm_campaign=top-promo "MihaiBojin.com"). 🔔

* * *

When a user shares a web link, most applications parse a standard set of [meta tags](https://www.w3schools.com/tags/tag_meta.asp) and use the provided information to render a 'card', including an image, a title, and a summary.

A few competing standards exist; the most relevant are Twitter [Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started) and Facebook's [Open Graph Protocol](https://ogp.me/).

When the necessary meta tags are missing, applications such as Twitter, Facebook, Whatsapp, Signal, Telegram, etc., will be unable to render the card. In such cases, they will either display the link as-is or try to infer some parts of the card metadata; in the latter case, your mileage may vary.

* * *

Here's an example of a site without social sharing cards metadata:

[![Screenshot of a shared link to a page without social card metadata](https://MihaiBojin.com/static/5ec94c0a59244b23316a52c9723e2d3e/e9c9b/without-card.png "Missing card meta-data, inferred title and summary")](https://MihaiBojin.com/static/5ec94c0a59244b23316a52c9723e2d3e/e9c9b/without-card.png)

  

And here's how my site's homepage is rendered:

[![Screenshot of a rendered Twitter card](https://MihaiBojin.com/static/3cd93860f5b308b164a6c4e766ef8018/379c3/with-card.png "Twitter card with front image, title, summary, and link")](https://MihaiBojin.com/static/3cd93860f5b308b164a6c4e766ef8018/379c3/with-card.png)

Since I wanted my site to display correctly in as many apps as possible, I provided both Open Graph and Twitter Card tags!

* * *

I use Gatsby for my site, and unfortunately, it does not have native support for social cards. Also, [when I implemented this feature](https://twitter.com/mihaibojin/status/1396612428075606027), I was pretty new to [GatsbyJS](https://www.gatsbyjs.com/) and had to figure out how to load files and process images through GraphQL (childImageSharp, gatsbyImageData, GatsbyImage, StaticImage).

It was rough, to say the least (unclear documentation, competing advice for Gatsby v2 and v3, and my general lack of knowledge).

Fortunately, I prevailed! Here's how:

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#load-any-image-via-graphql)Load any image via GraphQL

```
  const { myImage } = useStaticQuery(graphql`
    query {
      myImage: file(relativePath: { eq: "name-of-file.jpg" }) {
        childImageSharp {
          gatsbyImageData(layout: CONSTRAINED)
        }
      }
    }
  `);
```

This works with images placed under `src/images/`.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#get-a-link-to-a-processed-image)Get a link to a processed image

```
import { getImage, getSrc } from 'gatsby-plugin-image';

// ...

const img = getImage(image);
const imgSrc = SITE_URL + getSrc(img);
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#create-an-seo-component)Create an SEO component

Ok, I'll admit, Gatsby does have good SEO support, including some [general advice on social cards](https://www.gatsbyjs.com/tutorial/seo-and-social-sharing-cards-tutorial/).

This formed the basis of my configuration, although I had to heavily customize it!

I configured the SEO component to accept a number of inputs:

```
function SEO({ title, description, lastUpdated, tags, image, imageAlt, absoluteURL }) {
  const img = getImage(image);
  const imgSrc = SITE_URL + getSrc(img);

  let meta = [];

  //...
  return (
    <Helmet
      htmlAttributes={{prefix: 'og: http://ogp.me/ns#'}}
      title={title}
      meta={meta}
      //...
    />
  );
}

Seo.propTypes = {
  title: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  lastUpdated: PropTypes.string.isRequired,
  tags: PropTypes.arrayOf(PropTypes.string),
  image: PropTypes.object.isRequired,
  imageAlt: PropTypes.string.isRequired,
  absoluteURL: PropTypes.string.isRequired,
};
export default SEO

```

And generated the required meta tags:

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#generate-twitter-card-meta-tags)Generate Twitter Card meta tags

```
meta.push({
  name: "twitter:card",
  content: "summary_large_image",
});
meta.push({
  name: `twitter:title`,
  content: title,
});
meta.push({
  name: `twitter:description`,
  content: pageDescription,
});
meta.push({
  property: `twitter:image`,
  content: imgSrc,
});
meta.push({
  name: `twitter:image:alt`,
  content: imageAlt,
});
```

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#generate-open-graph-meta-tags)Generate Open Graph meta tags

```

meta.push({
  property: `og:type`,
  content: `website`,
});
meta.push({
  property: `og:url`,
  content: absoluteURL,
});
meta.push({
  property: `og:title`,
  content: title,
});
meta.push({
  property: `og:description`,
  content: pageDescription,
});
meta.push({
  property: `og:image`,
  content: imgSrc,
});
meta.push({
  name: `og:image:alt`,
  content: imageAlt,
});
meta.push({
  property: `og:updated_time`,
  content: lastUpdated,
});
meta.push({
  property: "og:image:width",
  content: parseInt(img.width),
});
meta.push({
  property: "og:image:height",
  content: parseInt(img.height),
});
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#bringing-it-all-together)Bringing it all together

And that was that! All that was left was for me to send all the required variables via my page layouts, e.g.

```
<Seo title="My article" description="Short summary of my article" etc="...">
```

But is it working?

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#testing-social-sharing-card-rendering)Testing social sharing card rendering

To test your feature, use the following tools:

- [Twitter card validator](https://cards-dev.twitter.com/validator)
- [Facebook sharing debugger](https://developers.facebook.com/tools/debug/)

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#bonus-social-sharing-buttons)Bonus: social sharing buttons

No site would be complete without a feature to allow users [to share content on social media easily](https://twitter.com/mihaibojin/status/1403468240047706129)!

I found an [excellent tutorial for integrating social sharing buttons](https://www.codewithlinda.com/blog/social-share-buttons-with-react-share/).

* * *

It goes a little bit like this:

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#create-a-component-and-import-media-from-react-share)Create a component and import media from react-share

```
import {
  TwitterShareButton,
  TwitterIcon,
} from 'react-share';

const ShareButtons = ({
  title,
  url,
  tags,
  twitterHandle,
}) => {

  // remove any non-alphanumeric characters
  const hashtags = tags.map((t) => t.replace(/[^a-zA-Z0-9]+/g, ''));

  return (
    <>
      <TwitterShareButton
        title={title}
        url={url}
        via={twitterHandle}
        hashtags={hashtags}
      >
        <TwitterIcon size={40} round={true} />
      </TwitterShareButton>
    </>
  );
};
```

(Of course, the above is greatly simplified and only displays Twitter. For my site, I defined more.)

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#include-the-component-on-your-pages)Include the component on your pages

```
<ShareButtons
  url={SITE_URL + location.pathname}
  title={...}
  description={...}
  tags={[...]}
/>
```

* * *

And here is the result:

[![Screenshot of social sharing buttons](https://MihaiBojin.com/static/8614555ce644b0409e1d0651f8a8f073/1a144/social-sharing-buttons.jpg "Social sharing buttons on my site")](https://MihaiBojin.com/static/8614555ce644b0409e1d0651f8a8f073/f5df4/social-sharing-buttons.jpg)

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#conclusion)Conclusion

I hope you found this short tutorial helpful! As I'm writing it now, it feels pretty straightforward, but at the time, I struggled for hours trying to piece together confusing or incomplete information from various articles and blogs.

Hopefully, this can help you avoid my experience and integrate your social sharing features much faster!

In an ideal world, Gatsby would have come with better, out-of-the-box, social sharing features!

Maybe one day...

* * *

If you liked this article and want to read more like it, [please subscribe to my newsletter](https://motivated-founder-807.ck.page/db1cf284bf "newsletter link"); I send one out every few weeks!