Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

SEO Plugin

NPM

This plugin allows you to easily manage SEO metadata for your application from within your Admin Panel. When enabled on your Collections and Globals, it adds a new meta field group containing title, description, and image by default. Your front-end application can then use this data to render meta tags however your application requires. For example, you would inject a title tag into the <head> of your page using meta.title as its content.

As users are editing documents within the Admin Panel, they have the option to "auto-generate" these fields. When clicked, this plugin will execute your own custom functions that re-generate the title, description, and image. This way you can build your own SEO writing assistance directly into your application. For example, you could append your site name onto the page title, or use the document's excerpt field as the description, or even integrate with some third-party API to generate the image using AI.

To help you visualize what your page might look like in a search engine, a preview is rendered on page just beneath the meta fields. This preview is updated in real-time as you edit your metadata. There are also visual indicators to help you write effective meta, such as a character counter for the title and description fields. You can even inject your own custom fields into the meta field group as your application requires, like og:title or json-ld. If you've ever used something like Yoast SEO, this plugin might feel very familiar.

Core features

  • Adds a meta field group to every SEO-enabled collection or global
  • Allows you to define custom functions to auto-generate metadata
  • Displays hints and indicators to help content editor write effective meta
  • Renders a snippet of what a search engine might display
  • Extendable so you can define custom fields like og:title or json-ld
  • Soon will support dynamic variable injection

Installation

Install the plugin using any JavaScript package manager like Yarn, NPM, or PNPM:

1
pnpm add @payloadcms/plugin-seo

Basic Usage

In the plugins array of your Payload Config, call the plugin with options:

1
import { buildConfig } from 'payload';
2
import { seoPlugin } from '@payloadcms/plugin-seo';
3
4
const config = buildConfig({
5
collections: [
6
{
7
slug: 'pages',
8
fields: []
9
},
10
{
11
slug: 'media',
12
upload: {
13
staticDir: // path to your static directory,
14
},
15
fields: []
16
}
17
],
18
plugins: [
19
seoPlugin({
20
collections: [
21
'pages',
22
],
23
uploadsCollection: 'media',
24
generateTitle: ({ doc }) => `Website.com — ${doc.title}`,
25
generateDescription: ({ doc }) => doc.excerpt
26
})
27
]
28
});
29
30
export default config;

Options

collections

An array of collections slugs to enable SEO. Enabled collections receive a meta field which is an object of title, description, and image subfields.

globals

An array of global slugs to enable SEO. Enabled globals receive a meta field which is an object of title, description, and image subfields.

fields

A function that takes in the default fields via an object and expects an array of fields in return. You can use this to modify existing fields or add new ones.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
fields: ({ defaultFields }) => [
6
...defaultFields,
7
{
8
name: 'customField',
9
type: 'text',
10
}
11
]
12
})
13
}
uploadsCollection

Set the uploadsCollection to your application's upload-enabled collection slug. This is used to provide an image field on the meta field group.

tabbedUI

When the tabbedUI property is true, it appends an SEO tab onto your config using Payload's Tabs Field. If your collection is not already tab-enabled, meaning the first field in your config is not of type tabs, then one will be created for you called Content. Defaults to false.

generateTitle

A function that allows you to return any meta title, including from document's content.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
generateTitle: ({ doc }) => `Website.com — ${doc?.title}`,
6
})
7
}

All "generate" functions receive the following arguments:

ArgumentDescription
collectionConfigThe configuration of the collection.
collectionSlugThe slug of the collection.
docThe data of the current document.
docPermissionsThe permissions of the document.
globalConfigThe configuration of the global.
globalSlugThe slug of the global.
hasPublishPermissionWhether the user has permission to publish the document.
hasSavePermissionWhether the user has permission to save the document.
idThe ID of the document.
initialDataThe initial data of the document.
initialStateThe initial state of the document.
localeThe locale of the document.
preferencesKeyThe preferences key of the document.
publishedDocThe published document.
reqThe Payload request object containing user, payload, i18n, etc.
titleThe title of the document.
versionsCountThe number of versions of the document.
generateDescription

A function that allows you to return any meta description, including from document's content.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
generateDescription: ({ doc }) => doc?.excerpt,
6
})
7
}

For a full list of arguments, see the generateTitle function.

generateImage

A function that allows you to return any meta image, including from document's content.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
generateImage: ({ doc }) => doc?.featuredImage,
6
})
7
}

For a full list of arguments, see the generateTitle function.

generateURL

A function called by the search preview component to display the actual URL of your page.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
generateURL: ({ doc, collectionSlug }) =>
6
`https://yoursite.com/${collectionSlug}/${doc?.slug}`,
7
})
8
}

For a full list of arguments, see the generateTitle function.

interfaceName

Rename the meta group interface name that is generated for TypeScript and GraphQL.

1
// payload.config.ts
2
{
3
// ...
4
seoPlugin({
5
interfaceName: 'customInterfaceNameSEO',
6
})
7
}

Direct use of fields

There is the option to directly import any of the fields from the plugin so that you can include them anywhere as needed.

1
import { MetaDescriptionField, MetaImageField, MetaTitleField, OverviewField, PreviewField } from '@payloadcms/plugin-seo/fields'
2
3
// Used as fields
4
MetaImageField({
5
// the upload collection slug
6
relationTo: 'media',
7
8
// if the `generateImage` function is configured
9
hasGenerateFn: true,
10
})
11
12
MetaDescriptionField({
13
// if the `generateDescription` function is configured
14
hasGenerateFn: true,
15
})
16
17
MetaTitleField({
18
// if the `generateTitle` function is configured
19
hasGenerateFn: true,
20
})
21
22
PreviewField({
23
// if the `generateUrl` function is configured
24
hasGenerateFn: true,
25
26
// field paths to match the target field for data
27
titlePath: 'meta.title',
28
descriptionPath: 'meta.description',
29
})
30
31
OverviewField({
32
// field paths to match the target field for data
33
titlePath: 'meta.title',
34
descriptionPath: 'meta.description',
35
imagePath: 'meta.image',
36
})

TypeScript

All types can be directly imported:

1
import {
2
PluginConfig,
3
GenerateTitle,
4
GenerateDescription
5
GenerateURL
6
} from '@payloadcms/plugin-seo/types';

You can then pass the collections from your generated Payload types into the generation types, for example:

1
import { Page } from './payload-types.ts';
2
3
import { GenerateTitle } from '@payloadcms/plugin-seo/types';
4
5
const generateTitle: GenerateTitle<Page> = async ({ doc, locale }) => {
6
return `Website.com — ${doc?.title}`
7
}

Examples

The Templates Directory contains an official Website Template and E-commerce Template which demonstrates exactly how to configure this plugin in Payload and implement it on your front-end.

Screenshots

image

Next

Form Builder Plugin