How we Handle SEO at GraphCMS

How to handle SEO with a Headless CMS is an extremely common question we encounter. To simplify this, here’s how we handle SEO at GraphCMS.

Ronak Ganatra
Ronak Ganatra
How we Handle SEO at GraphCMS

How to handle SEO with a Headless CMS is an extremely common question we encounter. To simplify this, here’s how we handle SEO for our own website using our CMS.

To clarify, this post covers the operational aspects of implementing SEO in your projects. For a general understanding of what to consider when setting up a new project, refer to our guides on Headless CMS and SEO Best Practices and Headless CMS and SEO: Technical Best Practices.

SEO beyond website buildersAnchor

Image of Yoast within WordPress

When setting out to build websites using a combination of well-known solutions like WordPress + Yoast, getting up to speed with operationally managing SEO is a very familiar concept. Most traditional CMSs allow you to edit site metadata, such as titles and descriptions, out of the box. Since a Headless CMS has no control over the final frontends or how the content is rendered, this functionality has to be added in, ideally, once the technical foundations are set.

Why not just continue using a legacy website builder?

There are well-known SEO benefits of migrating from a Legacy CMS to a Headless CMS in regard to page performance, security, user experience, and delivering content to multiple platforms - all of which directly and indirectly impact your SEO. Since a headless CMS will not necessarily give you the plug-and-play simplicity of installing a plugin to manage SEO, you need to follow a few best practices and adjust your implementation to go beyond what monolithic CMS would offer you.

How we handle SEOAnchor

We currently maintain all the content for our website from within GraphCMS itself. We build our site using a Static Site Generator (Gatsby), and deploy new iterations to Vercel using webhooks.

All the content related to SEO is handled within GraphCMS, along with image optimizations. The nuances for structured data, redirects, our sitemap, and robots.txt are handled within the codebase, usually via Gatsby plugins.

SEO as a modelAnchor

Since the concept of simple plug-and-play plugins, like Yoast, does not exist in the Headless world, we opted to run our operational SEO as a model within GraphCMS. All the required fields are set as an SEO model, which can have relations to a variety of pages, posts, and resources. In practice, this is what our SEO model currently looks like.

SEO content model in GraphCMS

Using this approach, we enforce the correct SEO attributes in place by defining the metadata as a requirement in our data model when content creators create or edit new data.

The meta-title, description, and focus keywords are taken as text strings to reflect accordingly when the website is crawled and indexed.

Our OG Images are generated programmatically using Vercel's OG Image as a Service, although having the option to manually override each asset as a fallback option for greater control is made possible by including an asset field in the model. OG and meta info is populated to each page with each build, ensuring that all content has SEO attributes as required, and are up to date whenever the website is rebuilt.

graphcms meta tags

Pages and posts can be connected to this SEO model as required, ensuring that every piece of content has its corresponding SEO attributes attached. We’ve kept the relation optional, so if there are no tweaks needed, then the website inherits default SEO values from the page or post itself.

For certain pages (especially resources behind a lead wall), having a Boolean field for a _noindex tag (or a _nofollow, or any other SEO attributes as required) allows our content editors to exercise greater control over the content they're publishing. For even further granularity, the options are endless - we opted to include the ideal crawling frequency and sitemap priority as well.

Taking this approach at GraphCMS allows us to make sure all SEO attributes for content are easy to create, edit, and modify on the fly, and might resemble the familiarity of adding SEO attributes via plugins in the majority of legacy CMS platforms.

SEO FieldsAnchor

Now that we’ve seen how the concept of SEO as a model works, let’s get into the details of how we use them at GraphCMS.

Headless CMS SEO - meta title

Title: A Single line text string field to establish the page/post meta title.

Headless CMS SEO - meta description

Description: A Multi line text string field to establish the page/post meta description.

Headless CMS SEO - focus keywords

Keywords: A Single line text string field with multiple options to define the focus keywords.

Headless CMS SEO - priority

Priority: A Float field with values ranging from 0.0 to 1.0 to set our preferred priority per page

Headless CMS SEO - changefreq

Frequency: A Dropdown enumeration field to indicate how often we change this page for an ideal recrawl.

Headless CMS SEO - noindex

noindex: A Boolean toggle to define whether or not this page should be indexed within SERPs.

Headless CMS SEO - meta image

Image: An Asset field to upload any corresponding image.

Headless CMS SEO - content relations

Relations: A Reference field to several pages and posts, to establish a one-to-one content relationship between an SEO model and its corresponding page/post.

SEO for AssetsAnchor

While we’ll roll out a new post specifically catered towards Image SEO with a Headless CMS, here’s a quick peek into how we handle our assets at GraphCMS.

Prior to any images being uploaded to the CMS, we ensure that our files have descriptive names and are pre-optimized. While it's always recommended to compress large files with services like Caesium or TinyPNG before uploading them - GraphCMS’s Assets API allows for granular transformations to resize, modify, and optimize images when being queried.

For example, this very post renders its featured image with resize=w:960,fit:crop/quality=value:75/output=format:webp/compress/ to have the final output transformed from PNG to WebP, and optimized for greater performance.

More operationally, the GraphCMS UI allows for greater flexibility in handling images and other assets for SEO. Similar to how the SEO component was explained, the asset model itself can be extended to include any attributes that you would need.

Here are a few quick wins on how to extend the asset model with custom fields:

Headless CMS Image SEO - Caption

Caption: A Rich text field to caption and credit images, and have them rendered below assets.

Headless CMS Image SEO - Resize

Resize: A Number field to set values, so your final images queried are rendered at predefined values like 25%, 50%, or 75%.

Headless CMS Image SEO - Localized Alt Text

Localized Alt Text: A Single line text field with localization enabled, to define the alt text of your images in several languages depending on your business model.

Depending on the complexity you require and the resources at hand, there are several possibilities to further expand on this depending on your use case - max dimensions, format switches, mobile-specific images - the options are endless.

Resolving SEO as a react ComponentAnchor

Finally, on the frontend, the added attributes are then compiled on the next website build prior to deploying as part of an "SEO" component.

import React from 'react';
import Helmet from 'react-helmet';
import useSiteMetadata from '../hooks/useSiteMetadata';
const SEO = ({ children, title, subTitle, meta }) => {
const {
description: metaDescription,
keywords: metaKeywords,
noindex,
title: metaTitle,
image,
} = meta || {};
const {
keywords,
title: siteTitle,
titleTemplate,
siteUrl,
defaultImage,
twitter,
} = useSiteMetadata();
const pageTitle = metaTitle || title;
const pageDescription = metaDescription || subTitle;
const pageKeywords = metaKeywords || keywords;
const ogImage = image?.url || defaultImage;
return (
<Helmet
htmlAttributes={{ lang: 'en' }}
defaultTitle={siteTitle}
titleTemplate={titleTemplate}
>
<title>{pageTitle}</title>
<meta name="description" content={pageDescription} />
<meta name="keywords" content={pageKeywords} />
<meta property="image" content={ogImage} />
<meta property="og:url" content={siteUrl} />
<meta property="og:title" content={pageTitle} />
<meta property="og:description" content={pageDescription} />
<meta property="og:site_name" content={siteTitle} />
<meta property="og:image" content={ogImage} />
<meta name="og:type" content="website" />
<meta name="twitter:site" content={`@${twitter}`} />
<meta name="twitter:title" content={pageTitle || siteTitle} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image:src" content={ogImage} />
{!!noindex && <meta name="robots" content="noindex" />}
{children}
</Helmet>
);
};
export default SEO;

And finally, when the time comes to build pages prior to deploying, the job is done for us with pages requesting any added meta attributes before our sitemap is updated using the Gatsby Sitemap Plugin.

meta: seo {
...seoData
}

It's Easy To Get Started

GraphCMS plans are flexibly suited to accommodate your growth. Get started for free, or request a demo to discuss larger projects with more complex needs