---
title: Addressing, head and SEO
description: site, base, head, seo, jsonLd, structuredData, analytics and redirects.
---

## `site` and `base`

<ParamField name="site" type="string">
  Absolute deployment origin, e.g. `"https://docs.example.com"`. No path, query or
  fragment — a path belongs in `base`. **Never inferred.**
</ParamField>

<ParamField name="base" type="string">
  Mount path with a leading slash, e.g. `"/docs"`.
</ParamField>

Setting `site` is what enables `sitemap-index.xml`, `robots.txt` and absolute URLs in
`llms.txt`. Without it those outputs are simply not written.

Setting `base` prefixes every internal link and asset reference — but the built files
still sit at the root of the output directory, so the mount path must exist in the tree
you actually serve. See [Deploy](/docs/ship/deploy).

## `head`

<ParamField name="head.meta" type="object[]">
  Meta tags to inject.
</ParamField>

<ParamField name="head.link" type="object[]">
  Link tags to inject: `rel`, `href`, optional `type`.
</ParamField>

**Data only.** There is no `head.script`, no `head.raw` and no `head.style`. `head` cannot
be turned into a script-injection surface, which is what makes a multi-tenant build safe
to run on someone else's content.

A root-relative `href` is base-prefixed; an absolute `http(s)` URL is passed through
verbatim. For stylesheets use `customCss`, not a `head.link`.

## `seo`

<ParamField name="seo.title" type="string" default="name">
  Page title base.
</ParamField>

<ParamField name="seo.description" type="string">
  Meta description.
</ParamField>

<ParamField name="seo.ogImage" type="path">
  Open Graph image.
</ParamField>

<ParamField name="seo.ogType" type="string">
  Open Graph type, e.g. `"website"`.
</ParamField>

<ParamField name="seo.ogSiteName" type="string">
  Open Graph site name.
</ParamField>

<ParamField name="seo.ogLocale" type="string">
  Open Graph locale, e.g. `"en_US"`.
</ParamField>

<ParamField name="seo.twitter" type="string">
  Twitter card handle.
</ParamField>

<ParamField name="seo.robots" type="string">
  Robots directive.
</ParamField>

There is no `seo.canonical`: canonical URLs derive from `site` and `base`, and a
hand-written override is the standard way to point every page at one wrong URL.

## `jsonLd` and `structuredData`

<ParamField name="jsonLd" type="object[]">
  Site-level schema.org blocks, copied verbatim onto every page.
</ParamField>

<ParamField name="structuredData" type="boolean" default="true">
  Site-wide switch for automatic per-page `TechArticle`/`Article` plus `BreadcrumbList`
  emission.
</ParamField>

The two are independent: `jsonLd` is what you wrote, `structuredData` is what Reed derives.
Turning `structuredData` off does not remove your `jsonLd`. There is no per-page
frontmatter equivalent of the switch.

## `analytics`

<ParamField name="analytics.provider" type="string">
  A provider from Reed's own registry.
</ParamField>

<ParamField name="analytics.options" type="object">
  Provider-specific options.
</ParamField>

A registry of known providers, not a place to paste a script tag. If your provider is not
in the registry, it is not configurable here — by design, for the same reason `head` takes
no scripts.

## `redirects`

<ParamField name="redirects[].source" type="string" required>
  Site-root-relative path, without the `base` prefix — Reed adds it.
</ParamField>

<ParamField name="redirects[].destination" type="string" required>
  Site-root-relative path, or an absolute `http(s)` URL.
</ParamField>

<ParamField name="redirects[].permanent" type="boolean" default="true">
  `true` emits a 301, `false` a 302.
</ParamField>

Two entries with the same normalized `source` are a schema error rather than a silent
last-one-wins.
