By Kowdja
SEO Analyzer adds focus‑keyphrase analysis, on‑page SEO checks, readability guidance, metadata previews, per‑entry content scores, and a site‑wide SEO dashboard to Strapi 5. Analysis is advisory and never blocks saving or publishing.
released July 17, 2026
npm install @kowdja/strapi-plugin-seo-analyzerSEO Analyzer adds focus-keyphrase analysis, on-page SEO checks, English readability guidance, metadata previews, Content Manager scores, and a snapshot-based audit dashboard to Strapi 5.
The plugin is advisory: analysis never prevents saving or publishing.
Global score, analysis coverage, priority queue, recurring issues, and the full content inventory in one place.

An at-a-glance SEO health widget on the Strapi home page.

A per-entry SEO score column and editor sidebar, right where you edit content.

>=5.50.1 <6npm install @kowdja/strapi-plugin-seo-analyzer
npx @kowdja/strapi-plugin-seo-analyzer initThe initializer safely installs src/components/shared/seo.json when it does
not exist. It never overwrites an existing component. Add shared.seo to each
eligible content type as a non-repeatable component field named seo.
Enable the plugin in config/plugins.js:
module.exports = ({ env }) => ({
'seo-analyzer': {
enabled: true,
config: {
siteUrl: env('WEBSITE_URL'),
resolver: {
enabled: Boolean(env('SEO_ANALYZER_RESOLVER_URL')),
url: env('SEO_ANALYZER_RESOLVER_URL'),
secret: env('SEO_ANALYZER_RESOLVER_SECRET'),
timeoutMs: 2000,
},
},
},
});Rebuild the admin after installation:
npm run build
npm run developinterface SeoAnalyzerConfig {
analyzerVersion?: string;
maxSecondaryKeyphrases?: number;
siteUrl?: string;
siteHostnames?: string[];
seoComponentUid?: string;
seoField?: string;
analysisPayloadLimit?: number;
resolver?: {
enabled?: boolean;
url?: string;
secret?: string;
timeoutMs?: number;
retrySavedAnalysis?: boolean;
};
migration?: { importLegacySeoStore?: boolean };
inventory?: {
syncOnStartup?: boolean;
batchSize?: number;
concurrency?: number;
};
}Defaults use shared.seo, the root field seo, a 2 MB analysis limit, ten
secondary keyphrases, a disabled resolver, and a background inventory sync of
25 documents per batch.
The SEO Analyzer menu opens a local content-quality dashboard. It includes a global score, current-analysis coverage, active problems, missing focus keyphrases, score distribution, category averages, a priority queue, recurring issues, and a filterable content inventory. Titles and scores open the matching Content Manager entry and locale.
The global score is the arithmetic average of current, complete, scored published documents in the selected scope. It is a content-optimization score; it does not measure rankings, traffic, backlinks, crawl health, or Search Console performance. Draft content is available through the status filter.
SEO Analyzer also registers an optional native SEO health widget. Existing Strapi home layouts are not changed: add the widget from the homepage's Add widget control. It is visible only to users with SEO Analyzer access.
At startup, the plugin indexes existing SEO-enabled content in the background.
This never blocks Strapi startup, saves, or publication. Administrators with
the run-backfill permission can restart the scan from the dashboard.
siteUrl and siteHostnames classify absolute links. Root-relative links are
always internal. Without site identity, absolute links are not assumed to be
internal.
Local focus-keyphrase, content, link, image, and readability checks work without a frontend. Checks that require rendered metadata return N/A and are excluded from scoring. They do not become failures.
The resolver is a framework-neutral authenticated HTTP endpoint. Its public
request and response types are exported from
@kowdja/strapi-plugin-seo-analyzer/types. A Nuxt example is included under
examples/nuxt-resolver.
Remote resolver URLs must use HTTPS. HTTP is accepted for localhost only. Unsaved document content is sent to the configured endpoint during live analysis. The plugin sends no content elsewhere and collects no telemetry.
Resolver failures produce provisional analysis and never block publication.
The plugin registers these admin actions:
plugin::seo-analyzer.readplugin::seo-analyzer.analyzeplugin::seo-analyzer.manage-settingsplugin::seo-analyzer.run-backfillAssign actions to non-super-admin roles in the Strapi administration panel. Snapshots have no public Content API routes.
Applicable checks receive 0, 3, 6, or 9 points. N/A checks are excluded. The overall score weights Focus Keyphrase at 40%, Page SEO at 40%, and Readability at 20%. Secondary keyphrases do not affect the overall score.
English is the only language with linguistic readability scoring in 1.x. Unsupported languages receive N/A rather than a penalty.
For an existing installation that previously used plugin store name seo,
enable the importer for one verified deployment:
migration: { importLegacySeoStore: true }The importer is opt-in, idempotent, does not overwrite populated settings, and
records a completion marker. Remove the option after verifying mappings and
role permissions. Existing shared.seo content is not rewritten. The snapshot
table keeps the collection name seo_analysis_snapshots.
Back up the database before schema upgrades. Removing the npm package does not
delete shared.seo content or the seo_analysis_snapshots table. Remove those
explicitly only after confirming they are no longer needed.
See CONTRIBUTING.md. For local package development use npm run watch:link
or build the package and install it through a file: dependency.
MIT. See LICENSE, NOTICE.md, and UPSTREAM.md.
Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.
Submit
