All Articles

How to improve your Next.js site's SEO (Part2)

 —  #Next.js #SEO #MetaTags #OpenGraphProtocol

This is the second part of our journey toward making our site visible or being discovered by the world. In case you missed it please check out (Part1).

Are you wondering how to make your content more clickable, shareable, and noticeable on social media?

Open Graph meta tags are the solution.

What are Open Graph Meta Tags?

Open Graph meta tags control how URLs are displayed when shared on social media.The implications for SEO are significant. Think of Right Open Graph Meta Tags as conversion rate optimisation for social exposure. We know from experience and studies that the right data, including optimised images, helps content to spread, which often leads to increased links and mentions and that's what we want.

The OG meta tags are part of Facebook’s Open Graph protocol and are also used by other social media sites, including LinkedIn and Twitter (if Twitter Cards are absent).

You can find them in the <head> section of a webpage. Any tags with og: before a property name are Open Graph tags.

Knowing exactly which social meta tags to include can be confusing even to experienced webmasters. I should point out that there are many tools which will provide you with templates but if you would like to understand a bit more and get your feet wet by implementing it by yourself,keep reading.

Facebook lists 17 OG tags in their official documentation, plus dozens of object types.

Let's go through the most important ones and Open Graph syntax


The title of your page

<meta property="og:title" content="title of your current page" />
  • Focus on value, and clickability.
  • Keep it short to prevent overflow. There’s no official guidance on this, but 40 characters for mobile and 60 for desktop is just about ideal.


Url of your content. It has to be an absolute URL.

<meta property="og:url" content="" />

Use the canonical URL( guys are amazing at explaining all SEO-related stuff).In regards to canonical URL and it's importance especially when you have duplicate content published on different platforms. It helps consolidate all connected data, such as likes, across all the duplicate URLs posted.


The URL of an image for the social snippet.

Note that this is perhaps the most essential Open Graph tag because it occupies the most social feed real estate.

<meta property="og:image" content="" />
  • Use custom images for “shareable” pages (e.g., homepage, articles, etc.).There are some great libraries that help you generate og:image on a fly.
  • Use your logo or any other branded image for the rest of your pages.
  • Use images with a 1.91:1 ratio and minimum recommended dimensions of 1200x630 for optimal clarity across all devices.
  • Use tools like to see your implementation.
  • Bear in mind when it comes to Twitter cards(which we will discuss later), the path to the image has to be absolute. It makes a bit of ball ache to test it in development.


The type of object you’re sharing. (e.g., article, website, etc.)

<meta property="og:type" content="article" />
  • Use article for articles and website for the rest of your pages.


A brief description of the content.

<meta property="og:description" content="Learn about SEO in Next.js Step by step guide." />
  • Complement the title to make the snippet as appealing and click-worthy as possible.
  • Keep it short and descriptive. Max amount of characters is 160.

These are just the essential meta tags to get us going. There are plenty of resources for making it appealing. Clickable titles, shareable images which grab attention,still content is the king.

Let's jump into implementation and get the attention of Tech Twitter and increase of the visibility of our site through it. ( please see below how our Open Graph tags will look on Facebook and other social sites. We do not want to forget them.)

Twitter Card,here we come.

To get started with Twitter Card

<meta name="twitter:card" content="summary" />

The card type,PROVIDED VIA CONTENT ATTRIBUTE,will be one of “summary”, “summary_large_image”, “app”, or “player”.

The difference? “summary_large_image” will put an image above (see the picture further down)(if you define one) about other Twitter card meta tags. "summary" will put the image on the left side. I should point out a tiny version of it.

Each card has built-in content attribution, which surfaces appropriate Twitter accounts for the content as specified by you. Users will be able to follow and view the profiles of attributed accounts directly from the card( they are not required btw). There are two kinds of attribution:

<meta name="twitter:site" content="@justasemicolon" /> <meta name="twitter:creator" content="@mikeGajdos81" />

When it comes to Twitter image for your card( I should mention there are some other types for the card, not just image. Check the docs).Regardless of the type, Twitter requires an absolute path to the content.

<meta name="twitter:image" content="" />

Twitter card tags look similar to Open Graph tags and are based on the same conventions as the Open Graph protocol. When using Open Graph protocol to describe data on a page, it is easy to generate a Twitter card without duplicating tags and data. When the Twitter card processor looks for tags on a page, it first checks for the Twitter-specific property, and if not present, falls back to the supported Open Graph property. This allows for both to be defined on the page independently and minimises the amount of duplicate markup required to describe content and experience.

It is time to put our custom <metaTag> to work. As per the previous article (Part1), the approach is identical. The content of our meta tags which is shared among all pages and does not need to be dynamic can go into either _document.js or top-level _app.js component for anything else we extend the flexibility of our component by accepting more props. This is our Meta.js

//component/meta/Meta.js import React from "react"; import Head from "next/head"; import { useRouter } from "next/router"; const Meta = ({ title, description, ogImage, ogType, url }) => { const { asPath } = useRouter(); return ( <Head> <meta name="keywords" content={keywords} /> <meta name="description" content={description} /> <meta charSet="utf-8" /> <title>{title}</title> <meta property="og:title" content={title} /> <meta property="og:description" content={description} /> <meta property="og:image" content={`${url}${ogImage}`} /> <meta property="og:url" content={`${url}${asPath.replace("/", "")}`} /> <meta property="og:type" content={ogType} /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:creator" content="@gajdos81" /> <meta name="twitter:title" content={title} /> <meta name="twitter:description" content={description} /> <meta name="twitter:image" content={`${url}${ogImage}`} /> </Head> ); }; Meta.defaultProps = { title: "justasemicolon", keywords: "portfolioSite web development, programming", description: "Portfolio and blog webiste focused on web development", ogImage: "images/defaultOpenGraphImageWithText.jpg", ogType: "website", url: "", }; export default Meta;

Let's walk through the code.

We added some additional default props as a fallback. Most importantly, the default URL prop of our site is to construct absolute path for images. We will combine it with the usage of next/router to make our absolute path dynamic. Now our component can be imported whenever we need it and it is flexible to adjust our meta tags based on a route and content.

Navigate to your individual blog post route

//pages/blog/[slug].js import React, { useEffect } from "react"; import ArticleTemplate from "../../components/blogPost/article"; import Meta from "../../components/meta/meta"; import { getAllArticles, getArticleBySlug } from "../../utils/contentFetchers"; const Article = ({ post }) => { //.... other custom logic.....// return ( <> <Meta title={post.title} description={post.description} ogImage={post.ogImage} ogType="article" /> <ArticleTemplate post={post} /> </> ); }; export async function getStaticProps({ params }) { const post = getArticleBySlug(params.slug, [ "title", "date", "tags", "description", "content", "ogImage", "coverImage", ]); return { props: { post, }, }; } export async function getStaticPaths() { const posts = getAllArticles(); return { paths: => { return { params: { slug: post.slug, }, }; }), fallback: false, }; } export default Article;

Now we have Open Graph tags implemented in our custom <meta> Tag component.

You can test in either Twitter card validator for the Twitter version of it or use

Let's see what it looks like :

That's it,folks.

I would like to emphasise an amazing source of inspiration and guidance for this post. Please check out

If you find it helpful or if there are any improvements or any mistakes, please reach out on Twitter, any feedback will be massively appreciated.