Frontend Development

Handling SEO Metadata in React Nextjs Applications

Handling SEO Metadata in React Nextjs Applications

In this post we will show how to add metadata tags to Nextjs 14 application pages to enhance SEO appearance.

 

 

 

Search engine optimization or SEO is a term refers to how search engines crawl and index your website. One of the factors that make your website appear and be indexed on search engines related to whether you applied the corresponding metadata for seo.

In this tutorial i suppose that you are using Next v14.

Nextjs provides us to add the metadata tags in easy steps depending on weather you are using the pages router or the app router.

 

Using the pages router

If you are using the pages router, you can add the metadata tags using the <Head> component available in Nextjs:

pages/posts.js

import Head from "next/head";


export default function Posts() {

    return (
        <>
            <Head>
                <title>Posts page</title>
                <meta name="description" content="Posts page description" />
                <meta name="keywords" content="posts, blog, articles, blogpost" />
            </Head>

            <main>
                <h2>Posts page</h2>
            </main>
        </>
    )
}

export async function getServerSideProps() {

    return {
        props: {}
    }
}

The <Head> component in Nextjs makes it simple to append elements to the head of the document such as title, meta, scripts and so on. As shown i added a <title> tag for the page title and the meta tags for description and keywords.

 

Open Graph Meta Tags

In the same way you can add facebook related og: tags which enhance the way the webpage when shared in facebook:

<meta property="og:title" content="Posts page" />
<meta property="og:description" content="Posts page description" />
<meta property="og:image" content="<image url>" />
<meta property="og:url" content="<post url>" />

 

 

Twitter Meta Tags

<meta name="twitter:site" content="Site name" />
<meta name="twitter:title" content="Posts page" />
<meta name="twitter:description" content="Posts page description" />
<meta name="twitter:image" content="<image url>" />

Favicon Metadata

This metadata tag displays the favicon.ico icon on the webpage tab on the browser

<link rel="icon" href="/favicon.ico?ac4fc4&ac4fc4" />

 

Loading External Scripts

If you have third-party javascript files and need to load these scripts in the document head, there are couple of ways:

  • Using <script> tag in the head like so:
<script src="/path/to/file.js?ac4fc4&ac4fc4"></script>
  • Using <Script /> component in the main <app /> component. This is more recommended method over the first method:

_app.js

import Script from "next/script";

export default function App({ Component, pageProps }) {
  return (
      <>
        <Component {...pageProps} />
        <Script src="/path/to/file.js?ac4fc4&ac4fc4" />
      </>
  );
}

I imported <Script /> from next/script. The <Script /> component provides features to load scripts before or after document finished loading, you can learn more about it in Nextjs docs.

 

Structured Data

You can add structured data for rich snippets in search results using JSON-LD format:

<script type="application/ld+json">
    {`
      {
        "@context": "https://schema.org",
        "@type": "Article",
        "headline": "Post title",
        "image": "Post image url",
        "publisher": {
          "@type": "Organization",
          "name": "Webmobtuts"
        }
      }
    `}
  </script>

 

Dynamic Metadata in Pages Router

To display dynamic metadata in a pages router, typically in a server component you have to write your data fetching logic in getServerSideProps() function.

An example of this when have a post details page in a blog application:

pages/post/[id].js

import Head from "next/head";
import {useState} from "react";


export default function PostDetails(props) {
    const {post_data} = props;

    const [post, setPost] = useState(post_data.data || null);

    return (
        <>
            <Head>
                <title>{post.title}</title>
                <meta name="description" content={post.content} />
                <meta property="og:title" content={post.title} />
                <meta property="og:description" content={post.content} />
                <meta property="og:image" content={post.image} />
                <meta property="og:url" content={post.url} />
                <meta name="twitter:site" content="My Blog" />
                <meta name="twitter:title" content={post.title} />
                <meta name="twitter:description" content={post.content} />
                <meta name="twitter:image" content={post.image} />
                <link rel="icon" href="/favicon.ico?ac4fc4&ac4fc4" />
            </Head>

            <main className={styles.main}>
                <h2>{post.title}</h2>
                <p>{post.content}</p>
            </main>
        </>
    )
}

export async function getServerSideProps(context) {
    const id = context.params.id;
    
    // Post detail endpoint, typically this from your backend app
    const post_data = await fetch(process.env.URL + `/api/post/${id}`).then(res => res.json());

    return {
        props: {
            post_data
        }
    }
}

 

Using the App Router

If your application is using the App Router instead of the Page Router, nextjs provide us another method by utilizing the Metadata Api to define the application metadata.

This method works by exporting a Metadata object from page.js or layout.js files.

app/blog/page.js

export const metadata = {
    title: 'Blog Home Page',
    description: 'Blog page description',
}

export default function Blog() {
    return (
        <div>
            <h2>Blog home page</h2>
        </div>
    )
}

As shown this method is more elegant than the pages router as we only exported a metadata const with the required metadata for the page.

If the page you want to add the metadata to requires setting the metadata dynamically, instead of exporting a metadata object like above, you have to export generateMetadata() function:

app/blog/[id]/page.js

export async function generateMetadata({params, searchParams}, parent) {
    const id = params.id

    const data = await fetch(process.env.URL + `/api/post/${id}`).then(res => res.json());

    const post_data = data.data;

    return {
        title: post_data.title,
        description: post_data.content,
        openGraph: {
            url: post_data.url,
            title: post_data.title,
            description: post_data.content,
            siteName: 'My Blog',
            type: 'website',
            images: [

            ]
        },
        twitter: {
            card: 'summary_large_image',
            title: post_data.title,
            description: post_data.content,
            images: [

            ]
        }
    }
}

export default async function Page({ params, searchParams }) {
    const id = params.id

    const data = await fetch(process.env.URL + `/api/post/${id}`).then(res => res.json());
    const post_data = data.data;

    return post_data && post_data && (
        <div>
            <h2>{post_data.title}</h2>
            <p>{post_data.content}</p>
        </div>
    )
}

In this page when the user visits <app_url>/blog/2 for example it will fetch post details by id. In the generateMetadata() function we capture the post id using params.id.

Next we are making data fetching logic using fetch() API. The function should return an object of metadata as shown above like title, description, openGraph, twitter, etc the same way as metadata object. You can check all the available keys returned by this function at Nextjs metadata docs.

By inspecting and checking the metadata in the browser developer tools:

metadata inspect

 

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments