Edge middleware
Decides, per request, who gets Markdown. Agents get the page's prebuilt .md; everyone else gets your page, untouched.
What it does
[02]A known agent's user-agent, an
Accept: text/markdownheader, or?onto. Anyone else goes straight through.Sent to Onto without waiting — only when a site key is set.
The prebuilt
/.onto/pricing.md, fetched from your own site. No file, and the page is served as usual.Serve Pro and above, when you've written some for the route. This step waits for Onto.
Try a request
[03]- Asking for Markdown — user-agent matches GPTBot (OpenAI)
- Note the visit — sent without waiting
- Fetch /.onto/pricing.md from your own site
- Add your context — asked, but Free gets nothing back
HTTP/1.1 200 Content-Type: text/markdown; charset=utf-8 Cache-Control: no-store, must-revalidate Vary: User-Agent, Accept X-Onto-Trace: GPTBot/1.2 (+https://openai.com/gptbot) X-Onto-Bot: GPTBot (OpenAI) X-Onto-Matched: true
# Pricing > Plans and what each includes **Source:** /pricing …
Set it up
[04]npx onto-next init writes this for you. If you already had a middleware.ts, it's left alone — call ontoMiddleware(req, ontoConfig) from yours.
import { NextRequest } from 'next/server';
import { ontoMiddleware } from '@ontosdk/next/middleware';
import ontoConfig from './onto.config';
export const middleware = (req: NextRequest) => ontoMiddleware(req, ontoConfig);
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
],
};Passing the config is what lets it answer /llms.txt itself. Paths under /_next and anything with a file extension are always passed through.
Who counts as an agent
[05]A match is any entry appearing in the user-agent, ignoring case; the longest match names the bot. Link-preview fetchers like facebookexternalhit are on the list too, so they receive Markdown.
What it reads
[06]ONTO_API_KEYYour site key. Without it nothing is recorded and no context is added — Markdown is still served.ONTO_API_URLWhere visits and context requests go. Defaults to https://api.buildonto.dev; ONTO_DASHBOARD_URL still works.