OntoProvider

The client-side React provider — injects <link rel="alternate"> tags so AI clients can discover your Markdown variant, and auto-generates JSON-LD structured data based on per-route page types.

Distinct from the middleware. The middleware serves Markdown to crawlers at the edge; OntoProvider tells crawlers (and model integrations like SearchGPT) where to look and what the page is. Both pieces compound — install both for best coverage.

What it does

OntoProvider mounts inside your App Router root layout and emits two things on every page:

What it emitsWhere it goesWhy it matters
<link rel="alternate" type="text/markdown" href="…?format=md">Document <head>Standard discovery surface for AI clients that honor content-negotiation alternates (Anthropic and OpenAI both look here).
<script type="application/ld+json">Document <head>JSON-LD structured data scoped to the active route's pageType (scoring → Methodology, about → Organization, etc).

Both injections happen on every navigation because the provider readsusePathname() — it's a true client component, so it tracks route changes without re-mounting the document.

Setup

Add the provider to your root layout, wrapping the entire app. The provider lives at @ontosdk/next/provider.

tsxapp/layout.tsx
import { OntoProvider } from '@ontosdk/next/provider';
import ontoConfig from '../onto.config';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <OntoProvider baseUrl="https://example.com" config={ontoConfig}>
      <html lang="en">
        <body>{children}</body>
      </html>
    </OntoProvider>
  );
}
Wrap <html>, not its children. The provider needs to be above the <head> so React reconciles its <link> / <script> emissions into the document head. Placing it inside <body> will still render but the metadata won't appear in the head where crawlers look.

Props

PropTypeRequiredDescription
baseUrlstringYesAbsolute origin of your site (e.g. https://example.com). The provider uses this to construct the full alternate URL: baseUrl + pathname + ?format=md. Trailing slashes are stripped.
configOntoConfigNoThe same config object exported from onto.config.ts. When provided, the provider matches the current pathname against config.routes and emits JSON-LD for the matched route's pageType. Omit if you only want the alternate link.
childrenReactNodeYesYour app tree, including <html> and <body>.

Page types & schemas

When config is provided and the current pathname matches a config.routes[] entry, the provider emits a JSON-LD schema scoped to the route's pageType:

pageTypeJSON-LD schema emittedWhen to use
'scoring'Methodology + Article (AIO scoring weights, criteria, scale)Pages that publish a scoring formula, ranking method, or quantitative framework you want AI to cite accurately.
'about'Organization + AboutPage (pulls from config.organization)Your /about page or any page describing your company. Requires config.organization to be filled in.
'default'None (only the alternate link emits)Everything else — landing pages, blog posts, docs.

Routes not listed in config.routes implicitly get 'default'. Add specific entries only for the routes whose pageType matters for AI grounding.

Relationship to onto.config

OntoProvider and onto.config.ts are designed to ship together. The config is the static source of truth (route map, organization details, sections for llms.txt); the provider is the runtime that reads it on each navigation and emits the right tags.

You can use the provider without a config — pass only baseUrl and you'll still get the alternate-link discovery surface. You can use the config without the provider too — the build CLI consumes it to generate llms.txt. But the JSON-LD injection specifically requires both.

See /sdk/configuration for the config-file reference.

Verify it works

After deploying:

StepCommandExpected
1curl -s https://yourdomain.com | grep alternateOne line with rel="alternate" type="text/markdown" pointing at ?format=md
2curl -s https://yourdomain.com | grep -A2 application/ld+jsonA <script type="application/ld+json"> block if the route is in config.routes with a non-default pageType
3Browser DevTools → Elements → search for application/ld+jsonSchema renders with the expected @type (Methodology, Organization, etc)
The AIO scorer rewards both signals — installing OntoProvider typically lifts insights.json_ld_present from false to true, worth +20 points on the score.

Gotchas

GotchaFix
Provider rendered but link/script don't appear in <head>You probably wrapped <body> children instead of <html>. Move it up one level.
JSON-LD never appearsConfirm config is passed AND the current pathname matches a config.routes[].path entry exactly (case-sensitive, no trailing slash). Routes are not pattern-matched today.
Stale schemas after route changeThe provider re-runs on every pathname change via usePathname(). If schemas don't refresh, you're probably caching at the CDN — add Cache-Control: no-store on the HTML response or use a per-route cache key.
TypeScript: "cannot find module '@ontosdk/next/provider'"Update to @ontosdk/next ≥1.6.0. The /provider subpath export was added in 1.6.0.