🔔 This article was originally posted on my site, MihaiBojin.com. 🔔
When a user shares a web link, most applications parse a standard set of meta tags 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 and Facebook's Open Graph Protocol.
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:
And here's how my site's homepage is rendered:
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, I was pretty new to GatsbyJS 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:
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/
.
Get a link to a processed image
import { getImage, getSrc } from 'gatsby-plugin-image';
// ...
const img = getImage(image);
const imgSrc = SITE_URL + getSrc(img);
Create an SEO component
Ok, I'll admit, Gatsby does have good SEO support, including some general advice on social cards.
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:
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,
});
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),
});
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?
Testing social sharing card rendering
To test your feature, use the following tools:
Bonus: social sharing buttons
No site would be complete without a feature to allow users to share content on social media easily!
I found an excellent tutorial for integrating social sharing buttons.
It goes a little bit like this:
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.)
Include the component on your pages
<ShareButtons
url={SITE_URL + location.pathname}
title={...}
description={...}
tags={[...]}
/>
And here is the result:
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; I send one out every few weeks!
Top comments (0)