Content Negotiation — Honoring Accept: text/markdown
HTTP has let clients ask for a different representation of the same page since the 1990s. Almost no one honors it for Markdown. The sites that do give agents clean content for free.
A Standard Nobody Uses
Every browser request carries an Accept header — typically something like text/html,application/xhtml+xml,...— declaring what representation of a resource the client wants. Servers that implement real content negotiation can return different formats of the same URL depending on that header: HTML for a browser, JSON for an API client, Markdown for an agent.
In practice, almost no website honors Accept: text/markdown. Most either ignore it and return the same HTML regardless, or return a generic error. The handful of sites that do implement it give agents a meaningful win: the same URL, the same content, without any HTML tags, scripts, or layout markup to strip out first.
What a Real Implementation Returns
A conformant response to an Accept: text/markdown request looks like this (this is ainative.ax’s own homepage, live):
$ curl -H "Accept: text/markdown" https://ainative.ax/
HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
---
title: AX Audit — AI Agent Readiness Scanner
description: Score your site against 18 checks for AI-agent readiness
date: 2026-10-23
---
# AX Audit
Score how ready your website is for AI agents in under 60 seconds...Two things matter here: the Content-Type header genuinely says text/markdown (not text/htmlwith Markdown-looking text inside it), and the body includes YAML frontmatter — structured title, description, and date metadata an agent can parse without an LLM, before it even reads the body.
Implementation Pattern
The common approach: maintain a Markdown source of truth for key pages, and branch on the request’s Accept header at the routing layer to serve either the full rendered page or the raw Markdown directly.
export function middleware(request) {
const accept = request.headers.get('accept') || '';
const wantsMarkdown = accept.split(',')[0].trim() === 'text/markdown';
if (wantsMarkdown) {
return NextResponse.rewrite(new URL('/api/md/home', request.url));
}
// fall through to the normal HTML route
}Checking only the first value in a comma-separated Accept header (rather than scanning for text/markdownanywhere in the string) matters — a browser’s default header often lists many types, and naively matching a substring would misfire on a request that merely tolerates Markdown as a low-priority fallback.
Where This Fits in AR-* and the AX Score
Content Negotiation falls under AR-CONT, the category covering how content is delivered once an agent has found a page. In the live AX Audit, it’s its own named check worth up to 8 of the 100 points — one of the higher-value single checks, reflecting how directly it affects an agent’s actual reading cost.
ainative.ax scores the full 8 of 8 on this check: a genuine text/markdown response with structured YAML frontmatter, served from the real homepage route.
Frequently Asked Questions
Do I need to implement this for every page, or just the homepage?▼
Can I just serve my existing HTML with a text/markdown Content-Type header?▼
Does YAML frontmatter actually matter, or is plain Markdown enough?▼
Check Your Content Negotiation Score
The AX Audit sends a real Accept: text/markdown request to your homepage and checks whether you honor it with a genuine Markdown response.
Check your content negotiation score→Free audit. No signup required.