Content Negotiation
Product, collection, and search pages serve structured markdown to AI agents via Accept header content negotiation.
Content Negotiation
Product, collection, and search pages serve structured markdown when clients send Accept: text/markdown. Browsers continue to receive HTML; AI agents and crawlers get clean, parseable markdown from the same URL.
This is a built-in feature that requires no configuration.
How it works
Browsers that don't send Accept: text/markdown are unaffected — the rewrite only fires when the header matches.
Testing
The Vary: Accept header ensures CDNs cache markdown and HTML responses separately.
What's included in the markdown
The markdown representation includes:
- Product pages — handle, brand, category, pricing, options, variants, specs, images, tags, and SEO metadata
- Collection pages — collection metadata, description, applied filters, available filters, products, pagination, image, and SEO metadata
- Search pages — query metadata, active collection filter, applied filters, available filters, products, and pagination state
Key files
| File | Purpose |
|---|---|
next.config.ts | Rewrite rules matching Accept: text/markdown |
app/products/md/[handle]/route.ts | Product markdown route handler |
app/collections/md/[handle]/route.ts | Collection markdown route handler |
app/search/md/route.ts | Search markdown route handler |
lib/markdown/product.ts | productToMarkdown() converter |
lib/markdown/collection.ts | collectionToMarkdown() converter |
lib/markdown/search.ts | searchResultsToMarkdown() converter |
lib/markdown/catalog.ts | Shared product/filter/pagination formatting helpers |
lib/markdown/utils.ts | Formatting helpers (prices, tables, escaping) |
Multi-locale
If you have enabled Shopify Markets, the rewrite fires before locale routing — no additional configuration is needed. Pass a ?locale= query parameter to the markdown endpoint for locale-specific pricing and collection/search context.