How to add metatags to your headless Drupal project

Blog
Posted on
Adding meta tag to headless Drupal

We are building our Next.js based starter kit for Rocketship. As we're going for full feature parity, one of the important but often overlooked features is full support for metadata. In this blogpost, we’ll show you how to get your meta tags working in your Next.js application.  

As you might know, our Rocketship install profile supports meta tags out of the box. This includes common meta tags like title and description but also Open Graph meta tags for social media. If you want, you can even add schema.org definitions.

Even if you aren’t using Rocketship you can set it up yourself by installing the Meta tag module and some of its submodules.

I'll take you through all the steps:

  1. Check if Drupal provides data
  2. Expose the metatag
  3. Rebuild cache
  4. Create a separate component
  5. Dynamically create tags
  6. Some considerations when implementing this
Metatags

Check if Drupal provides data

The assumption is that you already have a Drupal site running the latest version of Rocketship install profile or a similar setup. We also assume that you have a Next.js website running already that gets its data for a node page from JSON:API. If you do not yet, we recommend you get started with the documentation provided here.

The first step is making sure that Drupal actually provides the data on the JSON:API rest endpoint. By default the metatag property will be null:

{  
jsonapi:
{ 
version: "1.0",
meta:
{
links:
{
self:
{
href: "http://jsonapi.org/format/1.0/"
}
}
}
},
data:
{
type: "node--page",
id: "cdbca976-6504-4b0a-8f66-e8fbc02fa2d3",
links:
{
self:
{
href: "https://dropsoliddxp.docker.localhost:444/jsonapi/node/page/cdbca976-6504-4b0a-8f66-e8fbc02fa2d3?resourceVersion=id%3A1551"
}
},
attributes:
{
drupal_internal__nid: 42,
drupal_internal__vid: 1551,
langcode: "en",
revision_timestamp: "2022-09-22T15:26:58+00:00",
revision_log: null,
status: true,
title: "Why Dropsolid",
created: "2021-10-08T14:47:34+00:00",
changed: "2022-09-22T15:26:58+00:00",
promote: false,
sticky: false,
default_langcode: true,
revision_translation_affected: true,
breadcrumbs:
[
{
uri: "internal:#",
title: "Why Dropsolid",
options: [ ]
}
],
metatag: null,
node_keeper: false,
alias_keeper: false,
keeper_machine_name: null,
path:
{
alias: "/why-dropsolid",
pid: 49,
langcode: "en"
},
publish_on: null,
unpublish_on: null,
content_translation_source: "und",
content_translation_outdated: false,
field_description: "We believe that with an open DXP you can have it all. Freedom, flexibility and peace of mind. All while still using your own stack. Learn more!",
field_meta_tags: null,
field_page_display_canonical: [ ],;

Partial output of https://example.com/jsonapi/node/page/[some-uuid]

Expose the metatag

Luckily some people have been trying to make it work. When you apply the following patch, you can expose the meta tag data.

The patch adds a computed field to certain entities called metatag_computed. This field will generate the structure for the metadata when the entity is requested. To make the data available on the entity a normalizer is used.

It will look like the following:

{
jsonapi:
{
version: "1.0",
meta:
{
links:
{
self:
{
href: "http://jsonapi.org/format/1.0/"
}
}
}
},
data:
{
type: "node--page",
id: "cdbca976-6504-4b0a-8f66-e8fbc02fa2d3",
links:
{
self:
{
href: "https://dropsoliddxp.docker.localhost:444/jsonapi/node/page/cdbca976-6504-4b0a-8f66-e8fbc02fa2d3?resourceVersion=id%3A1551"
}
},
attributes:
{
drupal_internal__nid: 42,
drupal_internal__vid: 1551,
langcode: "en",
revision_timestamp: "2022-09-22T15:26:58+00:00",
revision_log: null,
status: true,
title: "Why Dropsolid",
created: "2021-10-08T14:47:34+00:00",
changed: "2022-09-22T15:26:58+00:00",
promote: false,
sticky: false,
default_langcode: true,
revision_translation_affected: true,
breadcrumbs:
[
{
uri: "internal:#",
title: "Why Dropsolid",
options: [ ]
}
],
metatag:
[
{
tag: "link",
attributes:
{
rel: "canonical",
href: "https://dropsoliddxp.docker.localhost:444/jsonapi/node/page/cdbca976-6504-4b0a-8f66-e8fbc02fa2d3"
}
},
{
tag: "link",
attributes:
{
rel: "shortlink",
href: "https://dropsoliddxp.docker.localhost:444/node/42"
}
},
{
tag: "meta",
attributes:
{
name: "referrer",
content: "origin"
}
},
{
tag: "meta",
attributes:
{
name: "rights",
content: "©2023 Dropsolid.io. All rights reserved."
}
},

Partial output of https://example.com/jsonapi/node/page/[some-uuid]

Rebuild cache

Don’t forget to rebuild your cache in Drupal after applying the patch. Now that we have this data we can make sure that our Next.js application is showing this data so it can be picked up by search engines.

We’ll start by adding a Head component to the component that has the entity data. In our starter kit, that would be the [...slug].tsx. If you want to read more about the Head component, do check here.

…
import Head from "next/head";


export default function EntityPage({
 entity,
 additionalContent,
 menus,
}: EntityPageProps) {
 return (
   
       // Add your metatags here
     {entity.type === 'node--page' && (
       
     )}
   
 );
}

Partial code of [...slug].tsx

Create a separate component

You could add the metatags here manually or write some code to loop over the output, instead we’ll make a separate component to render the tags.

In my case, I’ve named the component EntityMetatags and it takes an array of metatags exactly as Drupal provides them to us through the API.

import * as React from "react";


export function EntityMetatags({ metatags, ...props }){
 return (
   <>
     {metatags.map((metatag,index) => {
       const Tag = metatag.tag
       // Check if we are dealing with a normal tag or structured data.
       if(!metatag.attributes?.schema_metatag){
         return 
       }
     })}
   
 );
}

Full code of entity–metatags.tsx

Dynamically create tags

In this component we loop over the metatags that are provided and we dynamically create tags with their attributes. The metatags array also contains the schema.org metadata that can’t be added as a meta tag. At the end of the blog post we’ll talk a bit more about how you would go about doing that.

So now to actually render the metatags in your next.js application just add your newly created component to the Head component.

…
import Head from "next/head";


export default function EntityPage({
 entity,
 additionalContent,
 menus,
}: EntityPageProps) {
 return (
   
     {entity.type === 'node--page' && (
       
     )}
   
 );
}

Partial code of [...slug].tsx

When you open the website in the browser and inspect our code you should see the meta tags that are configured in Drupal in the head of your Next.js application:

Code

Some considerations when implementing this

SEO-wise you are fully covered when Next.js is running in Server side rendering mode. On the initial load of the page, the DOM will contain these metatags so the search bot doesn’t have to make additional passes to execute your JavaScript.
You’ll see that some of the data contain URLs. In some cases, you’d want to show the domain of your Next.js application instead of your Drupal application. We recommend either configuring your default tags to match this front-end domain or, in case of a multisite, using a token in Drupal with additional logic or rewriting the domain in your front-end application.

For the schema.org metadata, you currently need to rebuild the JSON output based on what was passed. If you are interested to see how we did that, do leave a comment via the contactform.

We can already give you a tip: don’t use the Next/Script component in Next/Head component. Rather use the strategy property of the Script component to get the script tag printed in the head of your Next.js application. If you want to read more about the Script component do check here.

Do come back in the future as we bring out more of these articles.