seo
Every export of @kitr/seo, read from the published type definitions. The guide shows them in use.
@kitr/seo
cacheHeaders
function cacheHeaders(options?: {
maxAge?: number;
sMaxAge?: number;
staleWhileRevalidate?: number;
private?: boolean;
}): {
'cache-control': string;
};
A cache-control header for TanStack Start's headers route option:
headers: () => cacheHeaders({ sMaxAge: 60 }). Public unless private is set.
jsonLd
function jsonLd(data: Record<string, unknown> & {
'@type': string;
}): {
type: string;
children: string;
};
A JSON-LD script for head().scripts: scripts: [jsonLd({ '@type': 'Article', headline })].
robotsTxt
function robotsTxt(config: SeoConfig): string | null;
robots.txt text from the config, or null when robots is false. The build writes it for web platforms.
safeJson
function safeJson(value: unknown): string;
JSON for inside a <script>: <, > and & as unicode escapes so a value such as
</script><script>… from a user's title can't close the tag, and U+2028/U+2029 escaped too.
Still valid JSON: parsers read the escapes back as the same characters.
seo
function seo(input: SeoInput, context?: SeoContext): {
meta: Record<string, string>[];
links: Record<string, string>[];
};
Meta tags for a route's head(): head: (ctx) => seo({ title, description }, ctx).
Covers title, description, Open Graph, Twitter cards, canonical and robots. Pass the head
argument (or the app) as the second argument so the site name, image and origin from
config/seo.ts apply; without it only input.site does. From the head argument it also
takes the canonical URL (site.url plus the matched path) and, when the loader returned
them, title and description: head: (ctx) => seo({}, ctx).
ssrRoute
function ssrRoute(mode: SsrMode | (Partial<Record<BuildPlatformKey, SsrMode>> & {
default: SsrMode;
})): {
ssr: SsrMode;
};
Route option presets. Spread into createFileRoute(...)({ ...ssrRoute('data-only'), ... }).
A table picks the mode per platform at build time, by platform name from kitrrc.ts, then type,
then default: ssrRoute({ www: true, web: 'data-only', default: false }) renders the marketing
build on the server, other web builds data-only, and native shells on the client.
defineConfig
const defineConfig: <const C extends SeoConfig>(config: C) => C;
Types the default export of config/seo.ts. The config lives on the app (app.config.get('seo'),
set from the config that app/app.ts passes to createApp), not in this module, so two apps
in one process keep their own site defaults and seo() reads them from the app it is given.
SeoConfig
interface SeoConfig {
/** Site-wide defaults for `seo()`. */
site?: SeoSite;
/** Default rendering for routes that set no `ssr` of their own (the router's `defaultSsr`). `ssrRoute()` overrides it per route. */
ssr?: boolean | 'data-only';
/**
* Routes to prerender at build time; `crawlLinks` follows links from them. A `static` web platform
* prerenders everything. A listed route that fails to render fails the build; a crawled link only
* warns, unless `failOnError` is `true`.
*/
prerender?: string[] | {
routes: string[];
crawlLinks?: boolean;
failOnError?: boolean;
};
/** Rules for `robotsTxt()`, which the build writes to `robots.txt` unless `public/robots.txt` exists. `false` writes none. */
robots?: false | {
allow?: string[];
disallow?: string[];
sitemap?: boolean;
};
}
Options for config/seo.ts. The build reads prerender, site.url and robots; seo() reads site; the router reads ssr.
SeoInput
interface SeoInput {
/** The page title, without the site name. Default: `title` from the route's loader data. */
title?: string;
/** The page summary for search results and share cards. Default: `description` from the route's loader data. */
description?: string;
/** Share image for this page; replaces `site.image`. Use an absolute URL. */
image?: string;
/** The page's canonical URL. Default: `site.url` plus the matched path from the `head` argument, else `site.url`. */
url?: string;
/** `og:type`. Default `website`. */
type?: 'website' | 'article' | 'product';
/** Adds `robots: noindex, nofollow`. */
noIndex?: boolean;
/** Joined into a `keywords` meta tag. */
keywords?: string[];
/** Site defaults. Default: `site` from the app's `config/seo.ts`, found through the context passed as `seo`'s second argument. */
site?: SeoSite;
}
What one page passes to seo(). Every field is optional; site supplies the defaults.
SeoSite
interface SeoSite {
/** Appended to page titles (`Pricing · Acme`) and sent as `og:site_name`. */
name?: string;
/** Canonical origin (`https://example.com`). Turns on the sitemap for prerendered routes. */
url?: string;
/** Share image for pages that set none. Use an absolute URL. */
image?: string;
/** The site's X (Twitter) handle, sent as `twitter:site`. */
twitter?: string;
/** Sent as `og:locale`, such as `en_US`. */
locale?: string;
}
Site-wide values for seo() and the build: name, canonical origin, default image, handle and locale.
SeoContext
type SeoContext = object;
Where seo() finds the app for the site defaults: the argument of a route's head (its
match.context.app, which createKitrRouter puts in every route's context), a loader or
beforeLoad context, or the app itself.
SsrMode
type SsrMode = boolean | 'data-only';