4.9 KiB
| title | aliases | tags | sources | created | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| SEO Plugin |
|
|
|
2026-05-15 | 2026-05-15 |
@payloadcms/plugin-seo adds a managed meta field group (title, description, image) to collections and globals, with auto-generate functions and a real-time search-engine preview.
Installation
pnpm add @payloadcms/plugin-seo
Basic Setup
import { seoPlugin } from '@payloadcms/plugin-seo'
buildConfig({
plugins: [
seoPlugin({
collections: ['pages'],
uploadsCollection: 'media',
generateTitle: ({ doc }) => `Website.com — ${doc.title}`,
generateDescription: ({ doc }) => doc.excerpt,
}),
],
})
Options Reference
| Option | Type | Description |
|---|---|---|
collections |
string[] |
Collection slugs to enable SEO on |
globals |
string[] |
Global slugs to enable SEO on |
uploadsCollection |
string |
Upload collection slug for the image subfield |
tabbedUI |
boolean |
Append an SEO tab (default: false) |
fields |
fn |
Extend or override the default meta fields |
generateTitle |
fn |
Return a custom meta title from doc data |
generateDescription |
fn |
Return a custom meta description from doc data |
generateImage |
fn |
Return a custom meta image from doc data |
generateURL |
fn |
Return the canonical URL shown in the preview |
interfaceName |
string |
Rename the generated TypeScript/GraphQL interface |
fields — adding custom fields
seoPlugin({
fields: ({ defaultFields }) => [
...defaultFields,
{ name: 'ogTitle', type: 'text' },
],
})
Generate function arguments
All generate* functions receive the same argument object:
| Arg | Description |
|---|---|
doc |
Current document data |
req |
Payload request (user, payload, i18n) |
locale |
Active locale |
collectionSlug / globalSlug |
Slug of the owning collection/global |
id |
Document ID |
publishedDoc |
The published version |
hasPublishPermission / hasSavePermission |
User permission flags |
tabbedUI Note
When tabbedUI: true, the plugin appends an SEO tab. If your collection has no existing tabs field as its first field, Payload creates a Content tab automatically.
If you need sidebar/top-level fields alongside
tabbedUI, define the first field astype: 'tabs'yourself — don't let Payload auto-create the Content tab.
Direct Field Imports
Import fields individually for fine-grained placement:
import {
MetaTitleField,
MetaDescriptionField,
MetaImageField,
PreviewField,
OverviewField,
} from '@payloadcms/plugin-seo/fields'
MetaImageField({ relationTo: 'media', hasGenerateFn: true })
MetaDescriptionField({ hasGenerateFn: true })
MetaTitleField({ hasGenerateFn: true })
PreviewField({
hasGenerateFn: true,
titlePath: 'meta.title',
descriptionPath: 'meta.description',
})
OverviewField({
titlePath: 'meta.title',
descriptionPath: 'meta.description',
imagePath: 'meta.image',
})
You still need the plugin registered in
buildConfigto configure the generation functions. Direct imports don't inherit plugin config automatically.
Override character limits via minLength/maxLength on individual field components, or titleOverrides/descriptionOverrides on OverviewField.
TypeScript
import type { GenerateTitle, GenerateDescription, GenerateURL } from '@payloadcms/plugin-seo/types'
import type { Page } from './payload-types'
const generateTitle: GenerateTitle<Page> = async ({ doc }) =>
`Website.com — ${doc?.title}`
Key Takeaways
- Plugin adds
meta.title,meta.description,meta.imagefields to enabled collections/globals - "Auto-generate" buttons call your custom
generate*functions — great for AI-assisted or rule-based SEO - Real-time search-engine preview and character counters help editors write effective meta without leaving the Admin Panel
- Extend meta fields with
og:title,json-ld, or any custom field via thefieldsoption tabbedUI: truewraps fields in a tab — requires the first field to already be atabsfield to avoid an unwanted Content tab auto-creation- Direct field imports give placement flexibility but still require the plugin to be registered for
generate*functions to work - All
generate*functions share the same argument shape — usereq.payloadfor DB lookups or third-party AI calls
Related
- wiki/payloadcms/plugins
- wiki/payloadcms/plugin-search
- wiki/payloadcms/plugin-nested-docs
- wiki/payloadcms/collection-config
- wiki/payloadcms/fields-tabs
- wiki/payloadcms/custom-components
Sources
raw/plugins__seo.md— https://payloadcms.com/docs/plugins/seo