Skip to main content
FEATURE 11 / 11

Docs that crawlers and agents can actually read.

A runtime-rendered app under hash routes is invisible to AI crawlers and one page to Google — the structural weakness of the whole category. ApiGlow answers it twice: every route announces itself while the app runs, and apiglow bake writes the static HTML and Markdown mirror that search engines and agents fetch without running a line of JavaScript.

docs.example.com/op/addPet.html · baked
A baked HTML snapshot of an operation page: title, description, the link back to the interactive documentation, and the operation's parameters as plain static content. A baked HTML snapshot of an operation page: title, description, the link back to the interactive documentation, and the operation's parameters as plain static content.

REAL SCREENSHOT, SHOWN AT 1:1

Every route announces itself.

From the first install, with zero configuration, the app manages the document head on every route change: a per-route <title> (“addPet — Petstore”), a meta description derived from the route’s own content, and a JSON-LD block per page — APIReference on endpoints, TechArticle on guides and scenarios, WebSite on the home view. Views no type honestly fits emit none: a wrong type is worse than silence.

One command writes the crawler's copy.

AI crawlers run no JavaScript, and Google reads every #/… route as one URL. apiglow bake — a companion CLI inside the same npm package — reads the exact config your host page inlines and writes what the crawlers need: an HTML snapshot and a Markdown mirror per operation, guide and scenario, a sitemap.xml, and llms.txt / llms-full.txt as served files. Deploy the tree next to the app page; the reader’s install stays one script tag.
The whole SEO story, one command
apiglow bake --config apidoc.config.json \
  --site-url https://docs.example.com/ --out public/

Honest pages, not cloaking.

Each snapshot is real static content: canonical to itself, an alternate link to its Markdown twin, JSON-LD, zero scripts — and one prominent link back into the interactive app. No redirect, no hydration, no user-agent sniffing. It is not a prerender and not static-site generation: it is the app’s export layer written to disk, fed by the same generators as the in-app “Copy page”, so the mirror cannot drift from the product.

Agents get files they can fetch.

Baked, llms.txt follows the llmstxt.org convention and links the served Markdown mirrors; every section of llms-full.txt carries a Source: line to its page; and each scenario publishes its Arazzo recipe — the same file a CI runner executes unchanged. The in-browser generation of the AI surface keeps working without a bake; the bake is what turns those downloads into URLs.

Or stay out of the index entirely.

Internal documentation opts out with one key: seo: { index: false } injects a noindex robots meta before first paint. The config states its own limit — it is a request to well-behaved crawlers, not a protection; docs that must not be read need an auth wall. And the bake refuses to run on a noindex config: publishing a mirror of a page that asks not to be found is a contradiction it treats as a hard error.

The mirror degrades where Node has no DOM.

The bake runs in Node (≥ 24), so raw HTML inside Markdown prose is escaped rather than rendered in snapshots, and a docs page carried by a host-page element (contentId) cannot be baked at all — it is named in the warnings and dropped from the sitemap rather than linked dead. The sitemap carries no <lastmod>, and robots.txt stays yours. Re-run the bake when the schema or the prose changes — in practice, from the CI job that already deploys the site.

See it in the live demo.