website_config, override them per page, or use metadata templates to build values from resolved CMS content, route parameters, and query parameters.
The favicon is not page metadata — it is a current website setting, not part of
website_config or a page’s metadata. See Site favicon.Set site defaults
Thewebsite_config singleton holds metadata shared by the whole site. Its default export must call defineWebsiteConfig directly with an inline object.
website_config
titleTemplate applies when a page supplies a title. Every %s is replaced with the page title, so Introducing Cactal becomes Introducing Cactal | Acme Journal. Site metadata must be static and cannot contain {{ ... }} template tokens because it has no page query or request context.
Without authored metadata, Cactal uses the website name as the title and an empty description.
Set static page metadata
Addmetadata directly to the top-level definePage object. Page values override site defaults.
pages/about
About us | Acme Journal when the site-level title template above is present.
Build metadata from CMS content
Page metadata strings can contain{{ ... }} tokens. Cactal runs the page’s declared CMS queries first, then resolves metadata and renders the page. A query’s key becomes the template’s root name.
pages/post
posts is the CMS collection slug, post is the page query key, and field keys such as seo_title and cover come from the collection schema. depth: 1 makes one level of referenced CMS items available to the page and to metadata templates.
Available references
The first path segment can be any page query key, not only
post. A list query exposes its result object under the same key, but metadata templates do not support array indexing. Prefer a get query for metadata about one detail page.
Reference paths use dot notation and identifier-like segments. Bracket access, numeric indexes, and query parameter names containing characters such as - are not supported. The unsafe path segments __proto__, constructor, and prototype are rejected.
Template syntax
Templates work in string values anywhere inside page metadata, including nested Open Graph data, alternate URLs, and JSON-LD.
Fallback terms may be dotted references or double-quoted JSON string literals. The fallback operator is intentionally narrow: it does not execute JavaScript.
null and missing values advance to the next term; empty strings, 0, and false count as resolved values.
When one token occupies the entire string, Cactal preserves the resolved value’s native type. This is useful for values inside structured data:
{{ post.fields.cover.url }} or {{ post.fields.brochure.url }}.
Missing values
Metadata resolution is best effort at request time:- A missing reference advances through its fallback chain.
- If no term resolves, Cactal omits that value rather than failing the page.
- Omitting a page value reveals the corresponding site or platform default.
- An unresolved array entry is removed; an unresolved object property is omitted.
- Invalid social images and non-object or non-serializable JSON-LD entries are omitted without breaking unrelated metadata or page rendering.
Metadata reference
Top-level fields
Robots
index and follow emit their positive or negative forms. The boolean fields prefixed with no emit a directive only when true. maxSnippet and maxVideoPreview must be integers greater than or equal to -1; maxImagePreview is none, standard, or large.
Setting the effective robots.index to false excludes a route from Cactal’s generated sitemap. A site-level false therefore produces an empty sitemap unless a page overrides it with true.
Open Graph
Each image requires
url and can include secureUrl, alt, type, width, and height.
Twitter/X
When Twitter metadata has no image, Cactal uses the first Open Graph image. It also selects
summary_large_image when it derives that image and no card was set. Explicit Twitter values always win.
Alternate links and canonical URLs
languages, media, and types are maps from the corresponding hreflang, media, or type attribute to a URL. The top-level canonical field is a convenient alternative to alternates.canonical; when both are present, the top-level field wins.
Metadata URLs must be absolute http or https URLs, or site-relative paths beginning with /. Cactal rejects unsafe schemes, protocol-relative URLs such as //cdn.example.com/image.png, control characters, and relative paths without a leading slash.
If a published page has no explicit canonical, Cactal uses its full requested HTTPS URL, including query parameters. Draft previews do not emit canonical links.
Structured data
structuredData accepts an array of JSON objects and renders each as a separate <script type="application/ld+json">. Values must be JSON serializable: strings, finite numbers, booleans, null, arrays, and plain objects. Functions, undefined, BigInt, Date objects, circular references, and unsafe keys are rejected.
Cactal safely serializes JSON-LD so values containing HTML or </script> cannot break out of the script element. Template tokens can appear in any string nested inside a structured-data object.
Inheritance and rendering
Cactal resolves final metadata in this order:- Platform defaults, including the website name as the title.
- Static metadata from
website_config. - Metadata from the matched page or custom not-found page.
- Page metadata template tokens using resolved CMS and request data.
- The inherited
titleTemplate, if the page supplies a title. - Open Graph and Twitter fallbacks.
robots, openGraph, twitter, and alternates merge by nested field so a page can override one setting without repeating the whole site object. Arrays such as keywords, openGraph.images, and structuredData replace the inherited array when supplied.
All metadata text and HTML attributes are escaped before rendering. Invalid URLs are omitted. Draft previews additionally force noindex, nofollow, suppress canonical links, and remove og:url, even if the source requests otherwise.
Generated crawler files
Cactal owns the crawler files for every website. On a published host:/robots.txtallows all crawlers and points to the host’s/sitemap.xml./sitemap.xmllists every indexable static route.- An indexable dynamic route is listed when Cactal can enumerate it from published CMS items.
metadata.robots object controls a page’s <meta name="robots"> directives and sitemap inclusion. It does not customize the contents of /robots.txt. Cactal combines site and page metadata before deciding whether a route is indexable, so either level can supply robots.index.
Dynamic CMS routes
Cactal can enumerate a dynamic route when all of these conditions are true:- The route contains exactly one path parameter.
- Exactly one page
getquery looks up an item byslugorid. - That lookup value is bound to the same path parameter with
param.path(...).
pages/post
posts produce /blog/<slug> entries. A dynamic route is omitted when it uses a list query, has multiple path parameters, has no matching get query, or has more than one matching lookup. The page remains routable even when Cactal cannot infer its sitemap URLs.
See Build pages with CMS data for the complete query API and request-parameter behavior.
Timestamps, large sites, and caching
Each sitemap entry includes<lastmod>. Static routes use the published deployment timestamp, while CMS-backed dynamic routes use the item’s updatedAt timestamp.
A sitemap with at most 50,000 URLs is returned directly from /sitemap.xml. Larger sites receive a sitemap index whose entries point to /sitemap-1.xml, /sitemap-2.xml, and additional shards of at most 50,000 URLs each.
Sitemap responses are publicly cacheable for up to one hour. A recently published deployment or CMS update can therefore take up to an hour to appear to a client or intermediary holding a cached response.
Draft protection and reserved paths
Draft hosts always return crawler-safe behavior regardless of authored metadata:- Every preview response includes
X-Robots-Tag: noindex, nofollow. /robots.txtreturnsDisallow: /./sitemap.xmland sitemap shard paths return404.
/robots.txt, /sitemap.xml, and /sitemap-<n>.xml are reserved platform paths. They cannot be page routes or redirect sources. Use metadata to control page indexing instead of trying to replace these generated files.
Source requirements
Cactal statically extracts metadata so it can validate, persist, and resolve it without executing user-authored metadata code. BothdefinePage and defineWebsiteConfig therefore require a direct default export and inline metadata:
- Imported or local metadata objects
- Object or array spreads
- Computed or duplicate keys
- Template literals using backticks
- Functions or function-valued metadata
- Calls, concatenation, or other JavaScript expressions
- Non-JSON values such as
undefinedornew Date()
POST /v1/websiteSourceCode/head/check before publishing. Invalid source shapes and template syntax return a framework diagnostic with the page id and metadata path, such as $.metadata.openGraph.images[0].url.
Edit metadata through the API
You can upsert the whole source file or use the semantic metadata endpoint.PATCH /v1/websiteSourceCode/metadata with a page replaces that page’s complete metadata object and rewrites only that property in source.
The endpoint does not add CMS queries. The target page must already declare every query referenced by the new metadata.
Set CMS-driven page metadata
page from the same endpoint to edit static site defaults. It creates website_config when needed and rejects template tokens. Both modes replace the entire metadata object, so send every field you want to keep. The endpoint requires the current edit lease and returns metadata, metadataChanged, version, and changed.
Troubleshooting
Next steps
Edit source code
Acquire a lease, update source or metadata semantically, validate, and publish.
Manage CMS content
Create the collections and fields used by dynamic metadata.
Build pages with CMS data
Declare typed CMS queries, bind route parameters, and render results.
Configure routes and redirects
Define clean paths, matching behavior, and redirect migrations.
Preview drafts
Review metadata safely on the protected draft host.
Source code concepts
Understand page files, website config, versions, and publishing.