Guide: Site-wide defaults¶
The SEO_SUITE["DEFAULTS"] and SEO_SUITE["SITE_DEFAULTS"] settings are a
baseline layer of metadata that every page inherits. Higher-priority providers
(model fields, views, path rules) override them field by field.
Global defaults¶
Add SEO_SUITE to settings.py. Any key you set is deep-merged with the
built-in defaults, so you only need to specify what you want to change:
SEO_SUITE = {
"DEFAULTS": {
"title_suffix": " | My Blog",
"robots": "index,follow",
"og": {
"type": "website",
"site_name": "My Blog",
},
},
}
The built-in global defaults (applied unless you override them):
| Field | Built-in value |
|---|---|
title_suffix |
"" (no suffix) |
robots |
"index,follow" |
og.type |
"website" |
CANONICAL_DOMAIN and HTTPS¶
By default, canonical URLs are built from the request's Host header. Use
CANONICAL_DOMAIN to enforce a specific domain regardless of the request:
SEO_SUITE = {
"CANONICAL_DOMAIN": "www.example.com",
"FORCE_HTTPS_CANONICAL": True, # default: True
}
With CANONICAL_DOMAIN set, all canonical URLs use https://www.example.com
even in local development or behind a reverse proxy that doesn't pass the
correct Host header.
FORCE_HTTPS_CANONICAL upgrades any http:// canonical to https:// even
when CANONICAL_DOMAIN is not set.
Per-site defaults (multi-site projects)¶
When django.contrib.sites is installed (or SITE_ID is set), you can
provide different defaults per site:
SEO_SUITE = {
"DEFAULTS": {
"title_suffix": " | My Network",
"og": {"site_name": "My Network"},
},
"SITE_DEFAULTS": {
1: {
"title_suffix": " | My Blog",
"og": {"site_name": "My Blog"},
},
2: {
"title_suffix": " | My Shop",
"og": {"site_name": "My Shop"},
},
},
}
The site-specific block (priority 20) merges on top of the global defaults
(priority 10) using the same field-by-field logic. You can also use None as
a key in SITE_DEFAULTS to apply a default to all sites that don't have a
specific entry:
"SITE_DEFAULTS": {
None: {"robots": "noindex"}, # applies when no site-specific match
1: {"robots": "index,follow"},
},
How site ID is resolved¶
The current site ID is determined by the following fallback chain:
SEO_SUITE["SITE_ID_RESOLVER"]— a callable that receives the request and returns an integer site ID. Use this for custom logic (subdomain routing, request-header-based selection, etc.).django.contrib.sites.shortcuts.get_current_site(request)— ifdjango.contrib.sitesis installed.settings.SITE_ID— if defined.None— single-site, no per-site defaults apply.
Custom resolver example:
# myapp/utils.py
def my_site_id_resolver(request):
if request.get_host().startswith("shop."):
return 2
return 1
DEFAULT_SCHEMA_PROFILES¶
Add JSON-LD schema profiles to every page site-wide:
These profiles run at the global defaults layer (priority 10). Per-model and per-view profiles accumulate alongside them. JSON-LD blocks are never replaced by higher-priority layers.
Caching resolved metadata¶
For high-traffic sites, enable resolved-payload caching. The cache key is per-object (model + PK + generation counter), so stale values are invalidated automatically on save and delete:
SEO_SUITE = {
"CACHE_TTL": 300, # seconds; 0 = disabled (default)
"CACHE_BACKEND": "default", # any Django cache alias
"CACHE_KEY_PREFIX": "seosuite:v1",
}
Only resolutions with a stable object identity (model instance with a PK) are cached. List pages and model-less views are not cached here.