page.contact.seo.title. Locale lives in Macro’s i18n layer — not inside the key — same as body content. Page identity
Macro needs a stable page slug to scope SEO keys. Resolution order:
data-macro-page on <html>
Preferred. Use a decoded slug; nested paths are fine (
blog/2026/post).<html lang="en" data-macro-page="contact">resolvePageSlug in config
Optional function when the URL shape does not match your content model.
export const macroConfig = { // ... resolvePageSlug: (pathname) => { if (pathname.startsWith('/blog/')) return pathname.slice(1).replace(/\.html$/, '') return pathname.replace(/^\/|\.html$/g, '') || 'home' }, }URL heuristic
Fallback:
/contact.html→contact,/→home.
Slugs that contain / are encoded in keys: blog/2026/macro-seo → page.blog__2026__macro-seo.seo.title.
Head markup
Mark each SEO field with data-macro-seo. Fallback text/attributes ship in HTML and are overwritten when Macro has a value.
<html lang="en" data-macro-page="contact">
<head>
<title data-macro-seo="title">Contact — Example</title>
<meta
name="description"
data-macro-seo="description"
content="Default description"
/>
<meta property="og:title" data-macro-seo="ogTitle" content="Contact — Example" />
<meta
property="og:description"
data-macro-seo="ogDescription"
content="Default OG description"
/>
<meta
property="og:image"
data-macro-seo="ogImage"
content="https://example.com/og.jpg"
/>
<link
rel="canonical"
data-macro-seo="canonical"
href="https://example.com/contact.html"
/>
<meta name="robots" data-macro-seo="robots" content="index, follow" />
</head>
<body>
<!-- page body -->
</body>
</html>Injection contract
| Name | Type | Description |
|---|---|---|
title | <title> | Written to textContent |
description | <meta> | Written to content |
ogTitle | <meta> | property="og:title" → content |
ogDescription | <meta> | property="og:description" → content |
ogImage | <meta> | property="og:image" → content (absolute https URL) |
canonical | <link> | rel="canonical" → href |
robots | <meta> | name="robots" → content |
ogImagemust resolve to an absolutehttps://URL in production HTML.- Empty canonical in Macro → the HTML fallback is left alone.
robotsvalues:index,follow·noindex,follow·index,nofollow·noindex,nofollow.
Runtime vs build
At runtime the SDK hydrates [data-macro-seo]:not([data-macro-ssr]) from GET /content/seo with the public key. For crawler-ready HTML at first byte, use Prerender (or Bake for offline exit).
Related
- Editors · SEO fields — overlay SEO tab
- Marking basics — body primitives
- API reference — Content and editor SEO endpoints