Payload CMS SEO Plugin: Boosting Your Site's Search Ranking

In today’s digital landscape, having a strong online presence is essential, and SEO plays a crucial role in driving organic traffic to your site. For users of Payload CMS, the SEO plugin offers a powerful and easy-to-use toolset that simplifies the process of optimizing your content for search engines.
In this article, I'll cover the following:
- How Payload's SEO plugin works
- Various ways to configure and use the plugin
- How Next.js and Payload SEO plugin can be used to manage SEO optimization.
- How the SEO plugin can help you improve your site’s visibility.
Whether you're a developer or a content creator, mastering this plugin will give you a significant edge in the competitive world of search rankings.
What is Payload CMS SEO plugin?
The SEO plugin to easily manage the key information fields, that's needed by sites to improve SEO ranking and your application's social presence using tools like Open Graph which is fully supported in Next.js
The plugin supports the following features:
- Automatically adds SEO fields to Collections.
- Provides components that can be used to manually add key fields.
- Built-in SEO validation to make sure fields are properly formatted.
- Organizes SEO meta information in a consistent location across Collections.
- Optional automatic tab placement in the Admin UI.
The plugin consistently manages SEO meta fields in your documents and is accessible in query responses, for example.
Example of SEO meta JSON object in query response
{
"meta": {
"title": "Your web page title",
"description": "Your page description",
"image": {
"id": 1,
"alt": "Sales promo Ad",
"updatedAt": "2025-03-24T01:59:26.370Z",
"createdAt": "2025-03-24T01:59:26.363Z",
"url": "/api/media/file/sales-promo-ad.png",
"thumbnailURL": null,
"filename": "sales-promo-ad.png",
"mimeType": "image/png",
"filesize": 133396,
"width": 1374,
"height": 942,
"focalX": 50,
"focalY": 50
}
}
}
Having the key meta fields in one place makes it easier to maintain and optimize pages.
Installing Payload CMS SEO Plugin
To install the SEO plugin, simply run the following command.
pnpm add @payloadcms/plugin-seo
Once installed, the plugin can be registered in the main config as follows:
import { buildConfig } from 'payload'
import { seoPlugin } from '@payloadcms/plugin-seo'
export default buildConfig({
plugins: [
seoPlugin({
}),
],
});
SEO Plugin Configuration Overview
Now that the plugin is installed, there's various ways the plugin can be configured to manage SEO fields.
The primary configuration options include:
- Allow the plugin to automatically add and manage the SEO fields.
- Manually use built-in components to add the SEO fields yourself.
The plugin allows for flexibility and can mix and match both options as needed.
Automatically add SEO fields
The automatic approach is the default method and relies on defining the collections to be managed.
The following code does the following:
- Defines the pages Collection to be managed.
- Uses media as the upload media source for images.
- Sets tabbedUI to true, so the Admin section will show the SEO fields in tabs.
For example:
{
collections: [
{
slug: 'pages',
fields: []
},
{
slug: 'media',
upload: {
},
fields: []
}
],
plugins: [
seoPlugin({
collections: ['pages'],
uploadsCollection: 'media'
tabbedUI: true
}),
]
}
In this example the tabbedUI is set to true, and will do the following:
- If the very first field in the Collection fields array is a tabs field, it will add a new tab called SEO and put the SEO fields on that tab.
- If the first field in the array is not a tabs field, it will create a tabs field, with two tabs. One labeled Content for any fields found and the second labeled SEO, for the SEO fields.
- If the tabbedUI is false (by default), it simply appends the SEO field group after any other fields.
SEO Plugin with Tabs Example
Here's a more complete example for the pages Collection. It defines the following:
- A tabs field group with a heroImage and content.
- A slug field set to appear on the right sidebar.
The plugin will detect the tabs field is first in the array and add a new SEO tab.
This is a pretty useful feature to quickly organize fields and make the Collecton Admin UI more manageable.
Pages collection with tabbedUI sample
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
type: 'tabs',
tabs: [
{
fields: [
{
name: 'heroImage',
type: 'upload',
relationTo: 'media',
required: true
},
{
name: 'content',
type: 'richText',
editor: lexicalEditor(),
label: 'Content',
required: true,
},
],
label: 'Content',
},
],
},
{
name: 'slug',
label: 'Slug',
type: 'text',
admin: {
position: 'sidebar',
},
},
],
}
Here's the rendered Admin UI form. The form now has two tabs as expected with all of the SEO meta fields inside.
I'll populate the fields with some sample data to show how the data is returned.
Running a query on the pages Collection will return a response with the meta group field added in the data.
Sample SEO meta JSON
{
"id": 2,
"heroImage": {
"id": 6,
"alt": "Music and Arts Festival",
"url": "/api/media/file/music-and-arts-1.png",
"thumbnailURL": null,
"filename": "music-and-arts-1.png",
"mimeType": "image/png",
"filesize": 5324640,
"width": 2546,
"height": 1422,
"focalX": 50,
"focalY": 50
},
"content": {
"root": {
"type": "root",
"format": "",
"indent": 0,
"version": 1,
"children": [
{
"type": "paragraph",
"format": "",
"indent": 0,
"version": 1,
"children": [
{
"mode": "normal",
"text": "The annual River City Arts & Music Festival is just around the corner, promising a vibrant celebration of creativity and rhythm. Set to take place on April 15th at the beautiful Riverside Park, this year’s festival will feature live performances by local bands, stunning visual art displays, and hands-on workshops for all ages.",
"type": "text",
"style": "",
"detail": 0,
"format": 0,
"version": 1
}
],
"direction": "ltr",
"textStyle": "",
"textFormat": 0
}
],
"direction": "ltr"
}
},
"meta": {
"title": "The River City Arts & Music Festival is around the corner",
"description": "The annual River City Arts & Music Festival is just around the corner, promising a vibrant celebration of creativity and rhythm. ",
"image": {
"id": 6,
"alt": "Music and Arts Festival",
"url": "/api/media/file/music-and-arts-1.png",
"thumbnailURL": null,
"filename": "music-and-arts-1.png",
"mimeType": "image/png",
"filesize": 5324640,
"width": 2546,
"height": 1422,
"focalX": 50,
"focalY": 50
}
},
"slug": "music-arts-festival"
}
So, you might be wondering why there's a heroImage on the page if there's also an upload field for the meta.image field too?
This demonstrates that the hero or a featured image could be different than the meta image.
In fact as we'll see the meta.image field can point to an etirely different media Collection that might be used for SEO specifically or social media platforms.
The plugin provides this kind of flexibility which is very useful when building more complex Collection models.
The SEO plugin allows for custom generator functions for title url and image to customize how they are set rather than relying on the field values alone.
Custom SEO generate functions
The plugin is configurable with custom generate functions. These function can be added as needed to override the default values.
- generateTitle: A function to generate and further refine the title.
- generateURL: A function to generate the url for the document.
- generateImage: A function to generate, create or even link to an existing image.
Generate functions provide a way to customize these meta field values if needed.
Examples of generate functions
const generateTitle: GenerateTitle<Page> = ({doc, collectionConfig}) => {
return doc?.meta?.title ? `${doc?.meta?.title} | Website Corp.` : 'Website Corp.'
}
const generateDescription: GenerateDescription<Page> ({ doc }) => {
return doc?.caption
}
const generateURL: GenerateURL<Page> = ({ doc }) => {
let url = 'http://localhost:3000'
return doc?.slug ? `${url}/${doc.slug}` : url
}
const generateImage: GenerateImage<Page> = async ({ doc }) => {
return doc.heroImage;
}
The generate functions just need to be added to the plugin config as needed when customization is needed.
By default, adding a corrosponding generate function for a field will set a boolean flag to show a generate link in the Admin UI form.
Example adding generate functions
{
plugins: [
seoPlugin({
collections: ['pages'],
generateTitle,
generateDescription,
generateURL,
generateImage,
uploadsCollection: 'media'
tabbedUI: true
}),
]
}
Note: Generate functions can be added as needed but they will be shared by all Collections that are managed by the plugin collections array or can be turned off by manually by adding SEO fields.
Manually add SEO fields
Now that we've seen how the SEO plugin automatically manages Collections, let's take a look at when and how to add them manually.
The SEO plugin exports all of the meta field components that it uses internally so that they can be used anywhere in your app.
Why should I manually add SEO plugin fields?
Here's some of the key reasons to use this approach:
- More flexibility over where the fields are placed and organized in the Admin UI page.
- Override the image relatedTo Collection for image upload.
- Override the a specific field component's configuration with overrides parameter.
- Override the generate function hasGenerateFn to avoid using a generate function that's defined in the plugin config.
- Or to override any of the components Field config settings, such as admin or hooks for example.
The Payload SEO plugin exports the following components for further flexibility in defining SEO meta data for your Collections:
- OverviewField: Overview of SEO status.
- MetaTitleField: Input title field.
- MetaImageField: Image selection or generate field.
- MetaDescriptionField: Input description field.
- PreviewField: Shows a preview of how the meta data looks and renders values in a card.
I'll modify the pages Collection to use custom components instead of using the automatic field injection.
Pages collection with tabbedUI sample
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
type: 'tabs',
tabs: [
{
},
{
name: 'meta',
label: 'SEO',
fields: [
OverviewField({
titlePath: 'meta.title',
descriptionPath: 'meta.description',
imagePath: 'meta.image',
}),
MetaTitleField({
hasGenerateFn: true,
}),
MetaImageField({
relationTo: 'media',
}),
MetaDescriptionField({}),
PreviewField({
titlePath: 'meta.title',
descriptionPath: 'meta.description',
}),
],
}
],
},
{
name: 'slug',
label: 'Slug',
type: 'text',
admin: {
position: 'sidebar',
},
},
],
}
These built-in components can be very flexible for just about any field arrangement and layout.
Override the Plugin SEO fields
The plugin provides a way to customize the default SEO meta fields if needed.
The plugin will set default fields internally and allows for these fields to be overriden and customized using the fields override function.
Override the default fields example
{
plugins: [
seoPlugin({
fields: ({defaultFields}) => [
...defaultFields,
],
}),
]
}
If the function is set, it'll pass a reference to the defaultFields array and then the function can modify the default fields anyway needed and even add extra custom fields.
Here's an example.
Override the default fields example
{
plugins: [
seoPlugin({
fields: ({defaultFields}) => {
return [
...defaultFields.filter((field) => field.type !== 'upload'),
MetaImageField({
relationTo: 'alt-media',
overrides: {
label: 'My Custom SEO Label'
},
}),
{
name: 'siteName',
label: 'Site name'
type: 'text',
},
]
},
}),
]
}
The SEO plugin is very flexible and is a great way to ensure that any Collection that generates web page content has the essential meta data to optimize the web page for search ranking.
Next.js and the Payload SEO Plugin
Now that Payload 3.0 is fully native Next.js, the advantages of using Payload's SEO plugin become really powerful.
Here's a basic end to end example of how the two frameworks work together to buidl SEO optimized web pages.
For a more in-depth article on SEO using Next.js Top 5 SEO Optimization Tips in Next.js 14. Next.js has great built-in support for SEO Optimization.
Building an optimized Next.js page
This page will run on the server side only and do the following:
- fetch the page data by slug
- Use the
generateMetaData()
function from Next.js to generate the header meta fields using Open Graph and X (Twitter) cards.
- Render the hero image and rich text content that was added in the previous steps.
Here's the Next.js page code.
/src/app/(frontend)/seo-demo/[slug]/page.tsx
import React from 'react'
import { Media, Page as PageType } from '@payload-types'
import { PaginatedDocs } from 'payload'
import { Metadata } from 'next'
import { RichText } from '@payloadcms/richtext-lexical/react'
const serverUrl = process.env.SERVER_URL || 'http://localhost:3000';
const getPageBySlug = async (slug: string) => {
const res = await fetch(`${serverUrl}/api/pages?[where][slug][equals]=${slug}`, {
method: 'GET',
})
const data: PaginatedDocs<PageType> = await res.json()
const page = data?.docs?.[0]
return page
}
type Props = {
params: Promise<{
slug: string
}>
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const page: PageType = await getPageBySlug(slug)
const { meta } = page;
const siteName = process.env.SITE_NAME || 'Website Name'
const url = `${serverUrl}/seo-demo/${slug}`
const title = meta?.title || ''
const description = meta?.description || ''
return {
title,
description,
openGraph: {
type: 'website',
title,
description,
url,
siteName: siteName,
},
twitter: {
title,
description,
card: 'summary_large_image',
site: siteName,
},
}
}
export default async function Page({ params: paramsPromise }: Props) {
const { slug } = await paramsPromise
const page: PageType = await getPageBySlug(slug)
const { content, heroImage } = page;
const {alt, url} = heroImage as Media
return (
<div>
<img src={`${serverUrl}${url}`} alt={alt} className="w-full object-cover"/>
<div className="p-5">
<RichText data={content}></RichText>
</div>
</div>
)
}
Accessing the SEO demo using slug
By going to the Next.js page route in dev mode at http://localhost:3000/seo-demo/music-arts-festival
will render the following web page.
Here's the page header fields with all of the meta data provided by the SEO Plugin query response.
<!doctype html>
<html lang="en">
<head>
<title>The River City Arts & Music Festival is around the corner</title>
<meta
name="description"
content="The annual River City Arts & Music Festival is just around the corner, promising a vibrant celebration of creativity and rhythm. "
/>
<meta
property="og:title"
content="The River City Arts & Music Festival is around the corner"
/>
<meta
property="og:description"
content="The annual River City Arts & Music Festival is just around the corner, promising a vibrant celebration of creativity and rhythm. "
/>
<meta property="og:url" content="http://localhost:3000/seo-demo/music-arts-festival" />
<meta property="og:site_name" content="Website Name" />
<meta property="og:image" content="http://localhost:3000/api/media/file/music-and-arts-1.png" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="Website Name" />
<meta
name="twitter:title"
content="The River City Arts & Music Festival is around the corner"
/>
<meta
name="twitter:description"
content="The annual River City Arts & Music Festival is just around the corner, promising a vibrant celebration of creativity and rhythm. "
/>
<meta
name="twitter:image"
content="http://localhost:3000/api/media/file/music-and-arts-1.png"
/>
</head>
<body></body>
</html>
In Conclusion
So we've seen how to configure and use the Payload SEO Plugin and also how to create a page to bring it all together.
This plugin can really make it easy to consistently manage SEO meta data across many Collections at a centralized place. It also puts the content management aspect on Payload which is what it was designed to do. Having a plugin to do the job makes it very convenient.
The other aspect is that it's very flexible to use for just about any Collection configuration needed.
I hope this article helped to demonstrate how to use the Payload SEO plugin effectively to help improve your page ranking.