Guide: Path-based overrides (seopath)¶
The seopath contrib app lets editors override SEO metadata for any URL path
through the Django Admin, with no code change required after initial setup. Use
it for marketing pages, landing pages, and any URL whose SEO needs to change
without a deployment.
When to use seopath¶
Use seopath when:
- A page is rendered by a third-party view you cannot modify.
- A non-technical editor needs to update a page title or description without a code deployment.
- You want to add a custom robots directive, canonical redirect, or JSON-LD block to an arbitrary URL.
- The same URL serves different SEO per site or per language.
For models you own, prefer SeoModelMixin or SeoModelFieldsMixin. seopath
is a URL-keyed override, not a replacement for model-level metadata.
Installation¶
Adding an override in Admin¶
Navigate to SEO Suite — Path rules → SEO path rules in the Django Admin and click Add SEO path rule.
| Field | Purpose |
|---|---|
| Path | The URL path, e.g. /about/ or /products/ |
| Site ID | Leave blank to apply to all sites |
| Language | Leave blank to apply to all languages |
| Title | Overrides the page title |
| Description | Overrides the meta description |
| Keywords | Overrides meta keywords |
| Robots | Overrides the robots directive |
| Canonical | Overrides the canonical URL |
| OG image | Overrides the social sharing image |
| Extra JSON-LD | Additional JSON-LD objects |
The path must be an exact match including the trailing slash (if your site uses one consistently). Leave any metadata field blank to defer to lower-priority sources.
Specificity rules¶
When multiple rows match the current path, the most specific row wins:
- Matching
site_idandlanguage: score 3 - Matching
site_idonly: score 2 - Matching
languageonly: score 1 - No
site_id, nolanguage(applies to all): score 0
The highest-scoring row is used; the other rows are ignored.
Example: A/B testing a landing page title¶
Create two rows for the same path and toggle between them by updating the title field directly in the Admin, no deployment needed:
| Path | Site ID | Language | Title |
|---|---|---|---|
/landing/summer/ |
(blank) | (blank) | Summer Sale — Up to 50% Off |
Change the title at any time; the next request picks up the new value.
If caching is enabled (SEO_SUITE["CACHE_TTL"] > 0), note that path-based
rows are not automatically invalidated on save. You may need to clear the
cache manually or set a short TTL.
Using seopath with model-backed pages¶
seopath runs at priority 30, which is below the object layer (priority
40). This means a SeoPath row for /articles/my-article/ is overridden by
the Article model's own get_seo_metadata().
To make a SeoPath row win over the model, you have two options:
- Set the field on the
SeoModelFieldsMixincolumns instead (those also run at priority 40, and the column layer merges on top of the convention layer). - Set the field in the view layer (priority 50) by using
SeoViewMixinwith a customget_seo_metadata.
If you specifically need path-based overrides to trump model fields on your own
models, the cleanest solution is usually to add SeoModelFieldsMixin columns
and let editors fill them in directly on the model's Admin page.
Multi-site and multilingual setup¶
For a multi-site project, create separate SeoPath rows per site:
| Path | Site ID | Language | Title |
|---|---|---|---|
/about/ |
1 | About Us | |
/about/ |
2 | About Our UK Team | |
/about/ |
1 | fr | À propos de nous |
The resolver picks the most specific match for the current site_id and
language. The site ID is determined by django.contrib.sites (if installed),
settings.SITE_ID, or a custom SEO_SUITE["SITE_ID_RESOLVER"] callable.