Site agent-ready : servir du Markdown aux crawlers IA depuis Apache, gratuitement
De 50 à 100/100 sur l'audit Cloudflare AI Compatibility, niveau Level 5 Agent-Native, en 30 lignes de configuration et zéro abonnement CDN.
- Cloudflare a publié un audit gratuit qui mesure si un site est « agent-ready », autrement dit prêt à être consommé par les agents IA
- Sur les critères principaux, le plan Free de Cloudflare obtient zéro point : les fonctionnalités Markdown for Agents et Content Signals sont facturées 240 $/an minimum sur le plan Pro
- Sur rankit.fr, hébergement Apache/LiteSpeed mutualisé, le score est passé de 50 à 100/100 en quatre paliers : 50 → 67 (.htaccess Markdown for Agents), 67 → 83 (robots.txt enrichi avec Content-Signal), 83 → 100 (Link headers RFC 8288)
- Niveau atteint : Level 5 Agent-Native, la classification la plus élevée du système Cloudflare
- 30 lignes de configuration sur trois fichiers (
.htaccess+robots.txt+ Link headers), zéro nouveau service externe, zéro abonnement CDN, zéro dépendance technique - Code complet copiable, configuration Nginx fournie, pièges techniques documentés (parsing Lighthouse, échappement des Link headers sous LiteSpeed)
- Ressources : convertisseur HTML→Markdown Rankit · documentation officielle Cloudflare
Pourquoi servir du Markdown aux crawlers IA
3 minAccept: text/markdown, elle, reste libre pour tout le monde.
Pendant vingt ans, les pages web ont été optimisées pour deux audiences : les humains et les robots Google. La première lit avec ses yeux, la seconde rampe avec un parser HTML qui comprend très bien la mise en page. Tout le monde y trouvait son compte.
Les LLM rebattent les cartes. Quand ClaudeBot ou GPTBot aspire une page pour répondre à un utilisateur, il ne fait pas un rendu visuel. Il convertit en interne le HTML brut en représentation textuelle exploitable, puis transmet cette représentation au modèle qui consomme des tokens à chaque caractère. Le HTML est, pour cet usage, un format bavard et bruité, alors que le Markdown a été pensé dès l'origine pour être lisible aussi bien par un humain que par une machine, sans aucune mise en page parasite.
Le coût caché du HTML pour un agent IA
Prenons un cas concret. Une page d'article rankit.fr fait environ 180 Ko de HTML avec son CSS inline, ses balises ARIA, ses scripts, ses meta og:, ses JSON-LD. La même page convertie en Markdown propre fait environ 18 Ko. Soit dix fois moins de matière à traiter.
Pour le modèle, cette différence se traduit en tokens consommés. Sur la page citée :
| Format servi | Taille | Tokens estimés | Bruit non-sémantique |
|---|---|---|---|
| HTML brut | 180 Ko | ≈ 45 000 | Élevé (CSS, scripts, ARIA) |
| Markdown converti | 18 Ko | ≈ 4 500 | Quasi nul |
| Réduction | −90 % | −90 % | − |
Une réduction de quatre-vingt-dix pour cent du contexte consommé n'est pas un détail. Pour un agent qui doit synthétiser dix sources avant de répondre, cela peut être la différence entre tenir dans la fenêtre de contexte et tronquer arbitrairement les sources. Et un agent qui tronque, c'est un agent qui cite mal, ou ne cite pas du tout.
Un signal de qualité pour l'écosystème
Au-delà de l'économie de tokens, servir une version Markdown négociée envoie trois signaux convergents aux développeurs d'agents et aux moteurs IA.
Premier signal : maturité technique. Le site comprend les contraintes des consommateurs IA, sait configurer la content negotiation HTTP, et accepte de produire deux représentations cohérentes du même contenu. C'est un marqueur d'attention rare en 2026.
Deuxième signal : intention d'être lu. Servir du Markdown explicite, c'est dire aux LLM oui, vous pouvez consommer ce contenu, voici la version qui vous convient. À l'inverse, un site qui répond uniquement en HTML et qui place un robots.txt restrictif communique l'inverse. Les agents qui doivent choisir entre dix sources favoriseront mécaniquement les sites du premier groupe.
Troisième signal : durabilité. Cloudflare a publié sa spec en février 2026, OpenAI et Anthropic l'ont adoptée dans la foulée. Le mouvement est lancé. Servir du Markdown aujourd'hui, c'est se positionner avant que cela devienne un standard implicite, comme l'a été la balise <meta name="description"> il y a vingt ans.
La mécanique HTTP : Accept et Content-Type
Cette mécanique de négociation de contenu existe depuis longtemps : elle est standardisée par l'IETF dans la RFC 7231, ratifiée en 1999. Le principe : le client indique ses préférences via l'en-tête Accept, le serveur répond avec le format le plus approprié et signale son choix via Content-Type.
Concrètement, quand un navigateur visite votre site, il envoie typiquement :
GET /mon-article HTTP/1.1 Host: www.rankit.fr Accept: text/html,application/xhtml+xml,...
Le serveur répond en HTML, business as usual. Mais quand un crawler IA moderne visite la même URL, il peut désormais envoyer :
GET /mon-article HTTP/1.1 Host: www.rankit.fr Accept: text/markdown User-Agent: ClaudeBot/1.0 (+claude.ai/bot)
Si le serveur sait répondre, il sert un fichier Markdown avec Content-Type: text/markdown; charset=utf-8. Sinon, il sert du HTML par défaut, ce qui marche aussi mais consomme dix fois plus de tokens chez le crawler. La différence entre les deux comportements, c'est exactement ce que mesure l'audit Cloudflare AI Compatibility, et c'est exactement ce qu'on va activer en .htaccess dans la suite de cet article.
L'audit Cloudflare AI Compatibility : l'état initial
2 minCloudflare a mis en ligne au printemps 2026 un audit gratuit baptisé AI Compatibility Audit. L'outil bombarde l'URL fournie d'une série de tests calibrés pour mesurer si un site est fait pour les agents IA. Pas pour Google, pas pour les humains. Pour les agents.
Les tests couvrent dix-sept points répartis en cinq catégories : Discoverability, Content Accessibility, Bot Access Control, API, Auth, MCP, et Commerce. Tous les tests ne sont pas activés sur tous les sites, c'est ce que Cloudflare appelle un partial scan. Pour rankit.fr, qui est un site éditorial sans API publique ni paiement intégré, je n'ai sélectionné que 7 checks pertinents sur les 17 disponibles.
Les 17 checks Cloudflare et les 7 retenus pour rankit.fr
Voici la cartographie complète des checks de l'audit, qui sera utile pour comprendre la suite. Sur rankit.fr, j'ai activé les sept checks de la moitié haute du tableau (Discoverability, Content, Bot Access Control), et désactivé les dix de la moitié basse (API/Auth/MCP, Commerce) qui ne s'appliquent pas à un site éditorial.
| Catégorie | Check | Activé | Cible |
|---|---|---|---|
| Discoverability | robotsTxt | ✓ | Présence et validité du fichier robots.txt |
sitemap | ✓ | Présence d'un sitemap XML déclaré | |
linkHeaders | ✓ | En-têtes HTTP Link RFC 8288 sur la home | |
| Content Accessibility | markdownNegotiation | ✓ | Réponse à Accept: text/markdown |
| Bot Access Control | robotsTxtAiRules | ✓ | Règles d'accès pour les crawlers IA |
contentSignals | ✓ | Directive Content-Signal dans robots.txt | |
webBotAuth | ✓ | Mécanisme d'authentification des bots | |
| API / Auth / MCP | apiCatalog | − | Fichier /.well-known/api-catalog (RFC 9727) |
oauthDiscovery | − | Endpoints OAuth 2.0 discoverable | |
oauthProtectedResource | − | Métadonnées OAuth Protected Resource | |
mcpServerCard | − | Carte serveur MCP (Model Context Protocol) | |
a2aAgentCard | − | Carte agent A2A (Agent-to-Agent) | |
agentSkills | − | Skills agents documentés | |
webMcp | − | Endpoint WebMCP standardisé | |
| Commerce | x402 | − | Paiement HTTP 402 (Payment Required) |
mpp | − | Machine Payment Protocol | |
ucp | − | Universal Commerce Protocol | |
acp | − | Agentic Commerce Protocol |
Le périmètre de 7 checks que j'ai retenu correspond à ce qu'on peut appeler le « noyau dur agent-ready » : les éléments de configuration que tout site web devrait avoir, qu'il soit éditorial, marchand, ou applicatif. Pour les éditeurs SaaS qui exposent une API publique, l'extension naturelle consisterait à activer aussi apiCatalog (RFC 9727) et oauthDiscovery. Pour un site e-commerce qui implémente Stripe ou similaire, les checks Commerce deviennent pertinents le jour où ces protocoles HTTP 402-based seront supportés par les processeurs de paiement, ce qui n'est pas encore le cas en 2026.
L'URL exacte qui reproduit la mesure faite sur rankit.fr est :
https://isitagentready.com/www.rankit.fr?checks=robotsTxt, sitemap,linkHeaders,markdownNegotiation,robotsTxtAiRules, contentSignals,webBotAuth
robots.txt.
Résultat initial sur rankit.fr
Avant toute intervention, l'audit donne un verdict mitigé. Le score global est de 50/100, ce qui place rankit.fr au niveau Level 1 : Basic Web Presence. Le détail qui nous intéresse est dans la section Content, qui mesure spécifiquement la négociation Markdown :
| Indicateur | Valeur avant | Verdict Cloudflare |
|---|---|---|
| Score global | 50/100 | Level 1 : Basic Web Presence |
| Section Content | 0/1 | Markdown negotiation : échec |
| Test exécuté | GET / | Avec en-tête Accept: text/markdown |
| Réponse serveur | text/html | Au lieu de text/markdown attendu |
| Durée du scan | 478 ms | Partial scan, profil Content |
Le seul indicateur que je tiens pour parfaitement certain dans ces résultats, c'est le score global de 50 et l'échec Content 0/1. Cloudflare expose aussi des sous-scores par catégorie (Discoverability, Bot Access Control), mais leur calcul exact dépend de pondérations internes que la documentation publique ne détaille pas. Je préfère donc me concentrer sur ce qui est vérifiable et sur ce qui change après l'intervention, plutôt que d'inventer une décomposition par catégorie qui pourrait induire en erreur.
Le test précis : ce que fait Cloudflare
L'audit déroule un test extrêmement simple sur la racine du site :
# Requête envoyée par Cloudflare GET / HTTP/2 Host: www.rankit.fr Accept: text/markdown # Réponse attendue : text/markdown # Réponse obtenue avant intervention : HTTP/2 200 content-type: text/html; charset=UTF-8 # Verdict Cloudflare : # « Site does not support Markdown for Agents »
Tout est dans la troisième ligne de la réponse. Le serveur ignore complètement la préférence du client et sert du HTML, alors qu'on lui a explicitement demandé du Markdown. Pour Cloudflare, c'est un échec sec, et le score Content tombe à zéro.
Content-Type commençant par text/markdown. C'est une bonne chose car la mécanique HTTP est claire : si le serveur ne sait pas répondre dans le format demandé, il devrait renvoyer un code 406 Not Acceptable ou se conformer. Servir du HTML en faisant semblant d'avoir compris est, techniquement, une non-conformité.
Bonne nouvelle : ce verdict, ce score 0/1, sont entièrement réversibles avec une configuration Apache élémentaire. C'est ce qu'on va voir maintenant, après un détour par la solution officielle Cloudflare et son tarif.
La solution Cloudflare officielle, et son tarif
3 minLa documentation officielle Cloudflare décrit Markdown for Agents en termes très clairs. Quand un crawler IA envoie Accept: text/markdown sur une zone éligible, le réseau Cloudflare intercepte la requête, fetch le HTML d'origine, le convertit en Markdown via un convertisseur interne, et sert directement la version Markdown au client. L'origine ne change pas, le travail est fait au niveau du CDN.
L'élégance du dispositif est réelle. Pas de conversion à programmer, pas de fichier .md à créer, pas de cohérence à maintenir entre HTML et Markdown : tout est calculé à la volée par Cloudflare. La feature ajoute même un en-tête bonus, x-markdown-tokens, qui indique au client le nombre estimé de tokens contenus dans la version Markdown servie.
Autre raffinement à connaître : Cloudflare ajoute systématiquement un en-tête de réponse content-signal: ai-train=yes, search=yes, ai-input=yes dans les conversions Markdown for Agents. Cet en-tête est cohérent avec la directive du même nom qui existe désormais dans robots.txt via le framework contentsignals.org. À retenir : la directive Content-Signal dans robots.txt est le mécanisme principal et standardisé, l'en-tête HTTP n'en est que la confirmation par requête servie. On reviendra sur ce point dans la section bonus consacrée aux signaux.
Comment activer Markdown for Agents chez Cloudflare
Trois voies sont possibles : interface dashboard, API, ou règles de configuration sur des sous-domaines spécifiques. La voie dashboard est la plus simple :
- Se connecter au dashboard Cloudflare avec un compte qui héberge une zone plan Pro ou supérieur
- Sélectionner la zone, naviguer dans AI Crawl Control
- Activer le toggle Markdown for Agents
- Attendre quelques minutes la propagation
Pour les SaaS multi-tenant qui utilisent Cloudflare for SaaS avec des hostnames personnalisés, une activation par règle de configuration est possible, mais elle requiert un advanced subscription avec accès aux custom metadata, qui est lui-même un palier Enterprise.
Le tarif réel de la fonctionnalité
C'est ici que le bât blesse. La documentation Cloudflare est limpide :
Trois mots font toute la différence : Pro, Business and Enterprise. Le plan Free, qui héberge la grande majorité des sites web protégés par Cloudflare dans le monde, est explicitement exclu. La précision at no cost en fin de phrase signifie sans surcoût par rapport au plan, pas gratuit. Pour bénéficier de Markdown for Agents, il faut basculer son site sur un plan payant.
Les tarifs publics de Cloudflare en avril 2026 (sources : documentation Cloudflare, comparatifs Vendr et CheckThat) :
Le plan Pro mensuel coûte 25 $ au lieu de 20 $ en annuel, soit 300 $/an. Pour un site éditorial moyen, qui n'a pas besoin du WAF avancé, ni des Image Resize, ni des features Pro, payer 240 à 300 $ par an pour activer une seule case à cocher est économiquement absurde. Surtout quand cette case se réplique en .htaccess.
Dans quels cas la solution Cloudflare reste pertinente
Soyons honnêtes : Cloudflare Pro a des avantages réels qui peuvent justifier le tarif si on en a besoin. Pour un site qui combine plusieurs des facteurs suivants, l'abonnement se rentabilise :
- Trafic mondial massif avec besoin de cache CDN avancé sur 330+ POP
- Surface d'attaque importante nécessitant WAF managé OWASP, bot management, exposed credentials check
- Optimisation images automatique (Polish, Mirage) sur sites e-commerce ou médias
- Volume de pages très élevé où la conversion HTML→Markdown manuelle deviendrait industriellement coûteuse
- Architecture totalement statique où on n'a pas la main sur la couche serveur (hébergement Pages, Vercel, Netlify)
Pour un site éditorial standard hébergé sur Apache ou LiteSpeed mutualisé, qui contrôle son .htaccess et qui ajoute ses fichiers .md au fur et à mesure, ces avantages ne s'appliquent pas. Et 240 $/an, c'est le prix d'un excellent dîner ou d'un mois d'outils SEO chez un confrère. Ce n'est pas le prix d'un toggle de configuration HTTP.
Voyons donc comment activer la même fonctionnalité, à zéro euro, sur tout serveur Apache ou LiteSpeed.
La solution Apache en .htaccess, ligne par ligne
6 minAccept: text/markdown et réécrit l'URL vers le fichier .md jumeau s'il existe. Le second pose les bons en-têtes HTTP (Content-Type, Vary). Le troisième déclare le type MIME des fichiers .md. Le tout fonctionne sur Apache 2.4+, LiteSpeed (mutualisé O2switch, Hostinger, OVH), et tout serveur compatible .htaccess.
L'objectif est simple. Quand un crawler IA visite https://www.rankit.fr/mon-article avec l'en-tête Accept: text/markdown :
- Le serveur détecte la préférence Markdown du client
- Il vérifie qu'un fichier
mon-article.mdexiste à la racine - Si oui, il le sert avec
Content-Type: text/markdown; charset=utf-8 - Sinon, il sert le HTML normal sans erreur
- Dans tous les cas, il ajoute
Vary: Acceptpour informer les caches
Cette logique s'écrit en trois blocs .htaccess distincts, qu'on va construire et expliquer un par un avant de les assembler.
Bloc 1 : la règle de réécriture mod_rewrite
C'est le cœur du dispositif. Trois cas doivent être couverts pour gérer toutes les formes d'URL d'un site moderne : la racine /, les URL propres sans extension de type /mon-slug, et les URL avec extension HTML explicite de type /mon-slug.html.
# ================================================ # CONTENT NEGOTIATION MARKDOWN (crawlers IA) # ================================================ <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # Cas 1 : racine "/" avec Accept: text/markdown RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/?$ RewriteCond %{DOCUMENT_ROOT}/index.md -f RewriteRule ^$ /index.md [L,E=IS_MARKDOWN:1] # Cas 2 : URL /slug (sans extension) RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/([^.]+)$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^([^.]+)$ /$1.md [L,E=IS_MARKDOWN:1] # Cas 3 : URL /slug.html avec extension RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/(.+)\.html$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^(.+)\.html$ /$1.md [L,E=IS_MARKDOWN:1] </IfModule>
Décortiquons les directives utilisées, parce que chacune compte.
RewriteCond %{HTTP_ACCEPT} text/markdown [NC] : c'est la condition sentinelle. Le flag [NC] rend la comparaison insensible à la casse, ce qui est conforme à la RFC 7231 sur les types de média. La condition se déclenche dès que la chaîne text/markdown apparaît dans l'en-tête Accept du client, même au milieu d'une liste comme text/html, text/markdown, */*.
RewriteCond %{REQUEST_URI} ^/?$ : on cible la racine. Le pattern accepte aussi bien / que /index.html selon la configuration du serveur. Pour les Cas 2 et 3, la regex capture le slug dans une backreference numérotée %1 exploitée à la condition suivante.
RewriteCond %{DOCUMENT_ROOT}/%1.md -f : c'est la condition critique. On vérifie l'existence physique du fichier .md jumeau sur le disque, via le test -f (regular file). Si le fichier n'existe pas, la règle ne s'applique pas, et le serveur tombe en fallback sur le HTML standard. Aucune erreur 404, aucune cassure : la dégradation est gracieuse.
RewriteRule ... [L,E=IS_MARKDOWN:1] : l'action. Le flag [L] stoppe le traitement après cette règle (Last). Le flag [E=IS_MARKDOWN:1] définit une variable d'environnement qui sera lue par le bloc 2 pour appliquer le bon Content-Type. Cette variable est le pont entre mod_rewrite et mod_headers.
Bloc 2 : les en-têtes HTTP de réponse
Une fois la réécriture faite, il faut s'assurer que la réponse part avec les bons en-têtes. Trois en-têtes sont indispensables, plus un en-tête optionnel mais recommandé.
# Headers pour les .md servis via négociation <IfModule mod_headers.c> Header set Content-Type "text/markdown; charset=utf-8" env=IS_MARKDOWN Header set X-Content-Negotiation "markdown-served" env=IS_MARKDOWN # Vary: Accept critique pour caches CDN (LiteSpeed, Cloudflare) <FilesMatch "\.(html|md)$"> Header append Vary "Accept" </FilesMatch> </IfModule>
Header set Content-Type "text/markdown; charset=utf-8" env=IS_MARKDOWN : on force le bon type MIME quand la variable IS_MARKDOWN a été définie par le bloc 1. La précision charset=utf-8 est importante pour les contenus français qui contiennent des caractères accentués.
Header set X-Content-Negotiation "markdown-served" env=IS_MARKDOWN : un en-tête de debug très pratique. Il permet de vérifier en un coup d'œil, via les outils de développement du navigateur ou via curl -I, que le serveur a bien servi du Markdown via la négociation. Ce n'est pas un en-tête standard, mais le préfixe X- reste autorisé pour les en-têtes spécifiques.
Vary: Accept indique aux caches que la réponse dépend de l'en-tête Accept, donc qu'il faut deux entrées de cache distinctes par URL. C'est non négociable.
Bloc 3 : le type MIME des fichiers .md
Par défaut, Apache ne sait pas qu'un fichier .md est du Markdown. Il le traite comme un fichier inconnu, voire le sert en application/octet-stream ce qui force un téléchargement. Il faut donc lui apprendre.
# Configuration MIME pour les .md (text/markdown, pas text/plain) <IfModule mod_mime.c> AddType text/markdown .md AddCharset UTF-8 .md </IfModule> # Lecture inline (pas de download forcé) <FilesMatch "\.md$"> Header set Content-Disposition "inline" </FilesMatch> # Empêcher l'indexation Google (les crawlers IA ignorent ce header) <FilesMatch "\.md$"> Header set X-Robots-Tag "noindex, nofollow" </FilesMatch>
AddType text/markdown .md : la directive clé. C'est elle qui aligne le type MIME sur ce qu'attend Cloudflare et tous les crawlers IA. Beaucoup de tutoriels en ligne préconisent text/plain à tort. Le test Cloudflare ne valide que text/markdown. Ne vous trompez pas.
Content-Disposition: inline : empêche le navigateur de proposer le téléchargement quand un humain accède à une URL .md directement. La page s'affiche alors comme du texte brut, ce qui est cohérent avec un Markdown source.
X-Robots-Tag: noindex, nofollow : c'est le détail astucieux. Google indexe les .md s'il les trouve, et cela créerait du contenu dupliqué. On lui demande donc de ne pas indexer. Mais les crawlers IA ignorent X-Robots-Tag : ils n'indexent pas au sens Google, ils consomment du contenu. La directive noindex ne les empêche pas d'utiliser les pages Markdown servies. Résultat : Google reste sur le HTML, les agents IA gagnent leur version Markdown, tout le monde est content.
La règle des fichiers jumeaux : comment ça s'articule
Avant d'assembler le tout, un point pédagogique important. Le .htaccess ne convertit rien à la volée : il joue le rôle d'aiguilleur entre deux fichiers qui doivent coexister à la racine du site. Pour chaque page publiée, il faut donc maintenir deux versions du même contenu, partageant le même slug.
Prenons l'exemple de l'URL https://www.rankit.fr/livre-blanc-geo-greenred-2026. Pour que la négociation de contenu fonctionne, deux fichiers doivent être physiquement présents sur le serveur :
| Fichier sur le serveur | Sert qui | Sert quoi |
|---|---|---|
livre-blanc-geo-greenred-2026.html | Humains et Googlebot | Page complète avec mise en page, CSS, scripts |
livre-blanc-geo-greenred-2026.md | Crawlers IA (ClaudeBot, GPTBot, etc.) | Markdown propre, sans bruit, économe en tokens |
Le mécanisme du .htaccess peut alors se décrire en une phrase : si la requête arrive avec Accept: text/markdown et que le fichier .md existe, le serveur sert le .md ; dans tous les autres cas, le serveur sert le .html. La dégradation est gracieuse : un .md manquant n'empêche jamais le HTML d'être servi.
Cas particulier de la racine du site : pour que https://www.rankit.fr/ renvoie du Markdown aux IA, il faut un fichier index.md à côté du index.html. Le .htaccess traite cette racine comme un cas dédié dans sa première règle de réécriture.
Concrètement, sur rankit.fr, l'arborescence ressemble à cela :
www.rankit.fr/ ├── .htaccess ├── index.html # humains + Googlebot ├── index.md # crawlers IA ├── livre-blanc-geo-greenred-2026.html ├── livre-blanc-geo-greenred-2026.md ├── geo-markdown-content-negotiation-apache-gratuit.html ├── geo-markdown-content-negotiation-apache-gratuit.md ├── brave-search-grail-22-signaux-moteur-ia.html ├── brave-search-grail-22-signaux-moteur-ia.md └── ...
Cette correspondance un-à-un peut sembler lourde au premier abord, mais elle a une vertu : la version Markdown reste sous votre contrôle. Vous pouvez l'enrichir, l'épurer, l'adapter au contexte des LLM, là où Cloudflare convertit automatiquement le HTML sans que vous puissiez intervenir. Pour les sites à fort volume éditorial, la conversion peut être automatisée par script (voir la section dédiée plus bas).
Assemblage final : les 30 lignes ultimes
Voici les trois blocs assemblés, au format prêt à coller dans votre .htaccess existant. À placer après vos règles HTTPS/www mais avant vos règles applicatives.
# ================================================================ # CONTENT NEGOTIATION MARKDOWN : Markdown for Agents en pur Apache # Compatible Apache 2.4+, LiteSpeed, O2switch, Hostinger, OVH # ================================================================ # --- Bloc 1 : réécriture si Accept: text/markdown --- <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # Cas 1 : racine "/" RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/?$ RewriteCond %{DOCUMENT_ROOT}/index.md -f RewriteRule ^$ /index.md [L,E=IS_MARKDOWN:1] # Cas 2 : URL /slug RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/([^.]+)$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^([^.]+)$ /$1.md [L,E=IS_MARKDOWN:1] # Cas 3 : URL /slug.html RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/(.+)\.html$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^(.+)\.html$ /$1.md [L,E=IS_MARKDOWN:1] </IfModule> # --- Bloc 2 : en-têtes HTTP --- <IfModule mod_headers.c> Header set Content-Type "text/markdown; charset=utf-8" env=IS_MARKDOWN Header set X-Content-Negotiation "markdown-served" env=IS_MARKDOWN <FilesMatch "\.(html|md)$"> Header append Vary "Accept" </FilesMatch> </IfModule> # --- Bloc 3 : MIME et configuration .md --- <IfModule mod_mime.c> AddType text/markdown .md AddCharset UTF-8 .md </IfModule> <FilesMatch "\.md$"> Header set Content-Disposition "inline" Header set X-Robots-Tag "noindex, nofollow" </FilesMatch>
Trente lignes utiles, hors commentaires. Trente lignes qui font exactement le travail que Cloudflare facture 240 $/an. Trente lignes qui passent l'audit AI Compatibility avec un score parfait sur le critère Content. Et trente lignes que vous gardez sous votre contrôle, modifiables à volonté, sans dépendance externe.
Vérification immédiate avec quatre commandes curl
2 mincurl permettent de vérifier en moins d'une minute que la content negotiation fonctionne. Les tests à passer : humain reçoit du HTML, crawler IA reçoit du Markdown, en-tête Vary: Accept présent partout, article spécifique converti correctement. Si les quatre passent, l'audit Cloudflare passera.
Le test ne prend pas plus d'une minute. Ouvrez un terminal sur votre machine, et lancez les quatre commandes suivantes l'une après l'autre.
Test 1 : un humain doit toujours recevoir du HTML
Première vérification cruciale : la content negotiation ne doit rien casser pour les visiteurs normaux. Un navigateur classique envoie Accept: text/html, ... et doit recevoir du HTML.
# Commande à lancer curl -I https://www.rankit.fr/ # Réponse attendue (extraits importants) HTTP/2 200 content-type: text/html; charset=UTF-8 vary: Accept
Le content-type doit rester text/html, et l'en-tête vary: Accept doit être présent. Si ce n'est pas le cas, le bloc 2 du .htaccess n'est pas appliqué correctement.
Test 2 : un crawler IA doit recevoir du Markdown
C'est le test critique, celui que Cloudflare exécute dans son audit. On simule un crawler IA en forçant l'en-tête Accept.
# Commande à lancer curl -I -H "Accept: text/markdown" https://www.rankit.fr/ # Réponse attendue HTTP/2 200 content-type: text/markdown; charset=utf-8 vary: Accept x-content-negotiation: markdown-served
Trois éléments à valider : content-type: text/markdown; charset=utf-8 (le critère Cloudflare), vary: Accept (la sécurité cache), et l'en-tête de debug x-content-negotiation: markdown-served qui confirme que le bloc 2 a bien été déclenché par la variable d'environnement.
Test 3 : un article spécifique en mode IA
Si la racine fonctionne, on vérifie qu'un article spécifique fonctionne aussi. C'est le cas le plus fréquent en production.
# URL propre sans extension curl -I -H "Accept: text/markdown" \ https://www.rankit.fr/livre-blanc-geo-greenred-2026 # URL avec extension .html (doit aussi fonctionner) curl -I -H "Accept: text/markdown" \ https://www.rankit.fr/livre-blanc-geo-greenred-2026.html
Les deux variantes d'URL doivent renvoyer text/markdown. Si l'une des deux échoue, vérifiez que les Cas 2 et 3 du bloc 1 sont bien tous deux présents dans votre .htaccess.
Test 4 : inspection du contenu Markdown servi
Dernière vérification : on récupère le contenu réel pour confirmer qu'il s'agit bien de Markdown lisible et bien formé.
# Récupère le corps de la réponse en mode Markdown curl -H "Accept: text/markdown" https://www.rankit.fr/ | head -30 # Sortie attendue : du Markdown propre # Rankit.fr : Consultant SEO et GEO Frédéric Jézégou, freelance SEO senior basé à Pornichet... ## Services proposés - **Audit SEO technique** - **Stratégie GEO** - **Présence dans les IA** ...
Vous devez voir du Markdown lisible : titres avec dièses, listes avec tirets, gras avec doubles astérisques. Si vous voyez du HTML brut avec balises, le bloc 1 n'a pas réécrit l'URL et la requête est partie sur le fichier HTML par défaut. Si vous voyez du texte sans aucune mise en forme, votre fichier .md est probablement vide ou mal formé.
Vary peut être nécessaire via le dashboard. Sinon, vérifiez l'ordre des règles dans votre .htaccess : la content negotiation doit être placée avant les redirections HTTP applicatives.
L'audit Cloudflare après déploiement : la preuve par l'image, en 4 paliers
4 min.htaccess Markdown for Agents (Content 1/1). Palier 3 : 83 après le robots.txt avec Content-Signal (Bot Access Control 2/2, Level 5 Agent-Native atteint). Palier 4 : 100/100 après les Link headers RFC 8288 (Discoverability 3/3). Score parfait, niveau maximal, en moins d'une heure de configuration cumulée.
Quelques minutes après avoir poussé la nouvelle version du .htaccess sur la production O2switch, j'ai relancé l'audit Cloudflare AI Compatibility sur la même URL. Et puis encore deux fois après chaque amélioration. Le résultat se raconte en quatre paliers chiffrés.
Palier 2 : passage de 50 à 67 avec le .htaccess
text/html au lieu de text/markdown. Verdict : Site does not support Markdown for Agents.text/markdown; charset=utf-8. Verdict Cloudflare : Site supports markdown negotiation.Le détail technique du test, capturé après modification, montre que la requête GET / Accept: text/markdown reçoit désormais en réponse content-type: text/markdown; charset=utf-8, avec le verdict positif de Cloudflare : « Response content-type is text/markdown; charset=utf-8, site supports markdown negotiation ». Section Content passée de 0/1 à 1/1, soit un gain de +17 points sur le score global.
Palier 3 : 83 et Level 5 Agent-Native après ajout du robots.txt
L'histoire ne s'arrête pas à 67. Quelques minutes après ce premier audit, j'ai poussé en production le robots.txt enrichi avec la directive Content-Signal: search=yes, ai-train=yes, ai-input=yes décrite dans la section 8 de cet article. Nouveau scan de l'audit Cloudflare, et le résultat fait un saut spectaculaire : 67 → 83, et le niveau passe directement de Basic Web Presence à Agent-Native, la classification la plus élevée du système Cloudflare.
Le saut s'explique simplement. La directive Content-Signal dans robots.txt, combinée à la mention Allow: / et à l'absence de blocage explicite des crawlers IA légitimes, fait passer la section Bot Access Control de partiel à 2/2. Le calcul global remonte à 83.
L'enseignement méthodologique est intéressant. Le .htaccess seul, malgré toute son ingéniosité technique, plafonnait à 67 parce qu'il ne traite qu'un seul critère : la négociation de contenu Markdown. C'est l'ajout du robots.txt déclaratif, qui parle au cerveau des crawlers et pas seulement à leur client HTTP, qui débloque le palier supérieur. Les deux leviers sont complémentaires, pas redondants.
Palier 4 : 100/100 après ajout des Link headers RFC 8288
Reste un dernier critère à satisfaire pour viser le maximum. La section Discoverability plafonne à 2/3 parce qu'il manque un en-tête HTTP Link: conforme à la RFC 8288 (Web Linking) sur la page d'accueil. C'est un mécanisme standardisé qui permet aux agents IA de découvrir, dès le premier appel HTTP, les ressources machine-lisibles qui décrivent le site : sitemap, robots.txt, documentation API, llms.txt, etc.
Sur rankit.fr, j'ai ajouté trois lignes dans le bloc mod_headers du .htaccess qui pointent vers les deux ressources machine-lisibles que mon site expose déjà : /sitemap.xml et /robots.txt. La sous-section consacrée aux Link headers en section 9 détaille la syntaxe correcte et le piège technique à éviter sous LiteSpeed. Une fois déployé, nouveau scan : 83 → 100, sections Discoverability, Content et Bot Access Control toutes à leur maximum.
| Indicateur | État initial | + .htaccess Markdown | + robots.txt Content-Signal | + Link headers | Gain total |
|---|---|---|---|---|---|
| Score global | 50 | 67 | 83 | 100 | +50 |
| Section Content | 0/1 | 1/1 | 1/1 | 1/1 | − |
| Section Bot Access Control | − | partiel | 2/2 | 2/2 | − |
| Section Discoverability | − | 2/3 | 2/3 | 3/3 | +1 |
| Niveau Cloudflare | Level 1 | Level 1+ | Level 5 | Level 5 | − |
| Label associé | Basic Web Presence | Basic Web Presence | Agent-Native | Agent-Native | − |
.htaccess avec les règles de négociation Markdown et les Link headers, un robots.txt avec la directive Content-Signal, et les fichiers Markdown jumeaux des pages HTML. Aucun service externe, aucune dépendance technique, aucun abonnement CDN. C'est exactement la configuration qu'un consultant SEO peut déployer sur le site de n'importe quelle PME hébergée chez O2switch, OVH mutualisé ou Infomaniak en moins d'une heure de travail effectif.
Et après le 100/100 ?
Une fois le score à 100 sur le profil Content, il reste deux pistes pour aller plus loin sur d'autres profils d'audit. Cloudflare propose en effet des profils plus exigeants comme full, qui activent les 17 checks au lieu de 7, et qui testent des critères additionnels comme API, Auth, MCP & Skill Discovery et Commerce. Pour un site éditorial comme rankit.fr, ces critères sont hors périmètre. Mais pour un éditeur SaaS, un site e-commerce ou une plateforme proposant une API publique, ce sont des leviers concrets.
- API catalog (rel="api-catalog") : ajouter un fichier
/.well-known/api-catalogconforme RFC 9727 et un Link header pointant vers lui. C'est le mécanisme officiel pour annoncer aux agents l'existence d'une API publique. - llms.txt : ajouter un fichier
llms.txtà la racine du site, conforme à la norme émergente, qui agrège la documentation principale du site sous forme Markdown agent-friendly.
Mais ce qui vient de se passer sur rankit.fr est déjà l'aboutissement complet de la promesse « reproduire gratuitement ce que Cloudflare facture 240 $/an ». Score parfait, niveau maximal, sans aucune dépendance externe, en moins d'une heure de configuration. Soyons clairs sur l'enjeu économique de ce résultat.
L'économie réelle, chiffrée sur 5 ans
2 minFaisons les comptes calmement. La question n'est pas de cracher sur Cloudflare, qui propose un produit techniquement excellent et utile à de nombreux usages. La question est de mesurer ce qu'on dépense pour activer cette case spécifique, et ce qu'on en retire en retour.
Cas mono-site : un site éditorial standard
Hypothèse : un site éditorial classique (blog professionnel, vitrine consultant, site média), hébergé sur Apache ou LiteSpeed mutualisé, qui veut activer Markdown for Agents pour rester compétitif sur le GEO.
| Solution | Coût annuel | Coût 5 ans | Effort initial |
|---|---|---|---|
| Cloudflare Free + .htaccess Apache | 0 $ | 0 $ | 30 min de config |
| Cloudflare Pro annuel | 240 $ | 1 200 $ | Toggle + migration DNS |
| Cloudflare Pro mensuel | 300 $ | 1 500 $ | Toggle + migration DNS |
| Cloudflare Business annuel | 2 400 $ | 12 000 $ | Toggle + migration DNS |
| Économie .htaccess vs Pro annuel | 240 $ | 1 200 $ | − |
Sur 5 ans, l'écart minimum est de 1 200 $. Au cours de change actuel, c'est environ 1 100 € qui restent dans la trésorerie de l'entreprise au lieu de partir vers un abonnement CDN. Pour un freelance ou une PME, c'est trois bons écrans, ou un séjour en formation Formaseo, ou le budget d'une refonte graphique.
Cas multi-sites : un consultant ou une agence
Pour un freelance comme moi qui gère plusieurs domaines, ou pour une agence qui héberge les sites de ses clients, l'écart se multiplie linéairement. Mes propres propriétés web : rankit.fr, dicocitations.com, vultifrine.com, greenred.fr, soit quatre domaines actifs.
.htaccess dupliquée. Maintenance : 0. Score Cloudflare AI Audit : 67, identique au Pro.Pour un consultant SEO/GEO indépendant ou une petite agence avec quatre clients en mutualisé, on parle de 4 800 $ environ 4 400 € qui peuvent être réinvestis ailleurs : outil de suivi GEO, abonnement IA premium pour la production, ou simplement une trésorerie plus saine.
Le coût caché de la dépendance Cloudflare
Au-delà du chèque mensuel, il y a un coût qui ne se voit pas dans les tableaux de tarifs : la dépendance à un fournisseur tiers pour des fonctionnalités HTTP basiques.
Si demain Cloudflare change ses conditions tarifaires, ajoute un quota d'usage, ou décide de monter Markdown for Agents en feature Premium uniquement, vous subissez la décision sans recours. Si Cloudflare a une panne mondiale (ce qui est arrivé en 2020, 2022 et 2024), votre content negotiation tombe avec eux. Si vous voulez ajouter une logique métier sur la conversion (cache personnalisé, transformation de contenu, contrôle d'accès), vous êtes limité par leur API.
En .htaccess, le code vous appartient. Il s'exécute dans votre stack, sous votre contrôle, modifiable à la milliseconde. Vous pouvez y ajouter ce que vous voulez, comme nous allons le voir maintenant avec deux en-têtes bonus que Cloudflare ne propose pas par défaut.
Aller plus loin que Cloudflare : x-markdown-tokens et Content-Signal dans robots.txt
3 minx-markdown-tokens est un en-tête HTTP qui indique aux agents le nombre estimé de tokens du Markdown servi (utile pour leur gestion de contexte). Content-Signal est une directive du fichier robots.txt, pas un en-tête HTTP, qui exprime selon le framework contentsignals.org les permissions d'usage du contenu (entraînement, recherche, contexte agentique). En contrôlant son .htaccess et son robots.txt, on configure les deux indépendamment de Cloudflare.
Markdown for Agents, c'est la base. Mais une fois la mécanique en place, on peut enrichir le dispositif avec deux signaux complémentaires qui parlent un langage encore plus précis aux agents IA modernes. Le premier, x-markdown-tokens, est un en-tête HTTP que vous pouvez calculer en PHP au moment de servir le .md. Le second, Content-Signal, est une directive de votre robots.txt qui n'a rien à voir avec le .htaccess mais qui complète parfaitement le tableau. Voyons les deux.
L'en-tête x-markdown-tokens
Cet en-tête, popularisé par Cloudflare, indique au client le nombre estimé de tokens contenus dans la réponse Markdown. Pour un agent IA qui doit gérer une fenêtre de contexte limitée (par exemple 200 000 tokens chez Claude), savoir qu'une page consommera 4 500 tokens permet de décider à l'avance combien de sources fetcher avant de faire l'inférence.
Le calcul du nombre de tokens est une approximation. La règle empirique communément admise pour le français est environ 1 token pour 3,5 caractères. On peut donc l'estimer côté serveur avec un script PHP léger.
<?php // Routeur PHP qui sert un .md avec calcul de tokens // À utiliser à la place du Bloc 1 si vous voulez x-markdown-tokens $accept = $_SERVER['HTTP_ACCEPT'] ?? ''; $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $slug = trim(preg_replace('#\.html$#', '', $uri), '/'); if (stripos($accept, 'text/markdown') !== false) { $md_path = __DIR__ . '/' . $slug . '.md'; if (is_file($md_path)) { $content = file_get_contents($md_path); // Estimation : ~1 token pour 3.5 caractères en français $tokens = (int) round(mb_strlen($content, 'UTF-8') / 3.5); header('Content-Type: text/markdown; charset=utf-8'); header('Vary: Accept'); header('X-Markdown-Tokens: ' . $tokens); header('X-Content-Negotiation: markdown-served'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($md_path)) . ' GMT'); echo $content; exit; } } // Fallback HTML normal $html_path = __DIR__ . '/' . $slug . '.html'; if (is_file($html_path)) { header('Vary: Accept'); readfile($html_path); exit; } http_response_code(404);
Ce script remplace le Bloc 1 quand on veut un calcul précis. La règle .htaccess qui route vers ce fichier devient :
# Si Accept: text/markdown, router vers md-router.php RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([^.]+)$ /md-router.php [L]
La directive Content-Signal dans robots.txt
Le framework Content Signals a été initié par Cloudflare en septembre 2025 pour permettre aux éditeurs d'exprimer machine-readable leurs préférences sur l'usage de leur contenu par les IA. Premier point essentiel à comprendre : Content-Signal n'est pas un en-tête HTTP, c'est une directive qui s'ajoute à votre fichier robots.txt. C'est une extension du Robots Exclusion Protocol, pas un en-tête de réponse HTTP. Les crawlers IA conformes vont chercher cette information dans robots.txt, là où ils ont l'habitude de lire User-agent, Allow et Disallow.
Le framework définit trois signaux principaux :
search: autoriser l'indexation et l'affichage dans les résultats de recherche IA (valeursyes,no)ai-input: autoriser l'utilisation comme contexte agentique en temps réel, RAG ou grounding (valeursyes,no)ai-train: autoriser l'utilisation pour entraîner ou affiner des modèles (valeursyes,no)
Sur les domaines Free chez Cloudflare qui n'ont pas de robots.txt existant, Cloudflare insère automatiquement la directive Content-Signal: search=yes, ai-train=no par défaut. Les domaines qui ont déjà un robots.txt, comme rankit.fr, ne sont pas modifiés. Il faut donc ajouter la directive soi-même, et c'est précisément ce qui me convient mieux : je décide de ma politique, pas Cloudflare à ma place.
La politique permissive de rankit.fr
Sur rankit.fr, j'ai opté pour la politique permissive maximale. Mon contenu existe pour être lu, indexé, cité, et accessoirement contribuer à l'amélioration des modèles qui me citent. C'est une décision éditoriale qui m'appartient, et qui peut différer pour un site média payant ou une publication scientifique soumise à embargo. Voici l'extrait à coller dans robots.txt.
# Politique Content Signals (contentsignals.org) # En tant que condition d'accès à ce site, vous acceptez les signaux suivants : # (a) si content-signal = yes, vous pouvez collecter le contenu pour l'usage correspondant # (b) si content-signal = no, vous ne pouvez pas collecter le contenu pour l'usage correspondant # (c) si le signal n'est pas fourni, l'opérateur du site n'accorde ni ne restreint l'usage # # Signification des trois signaux : # search : indexation et affichage dans des résultats de recherche # ai-input : utilisation comme contexte temps réel pour modèles IA (RAG, grounding) # ai-train : utilisation pour entraîner ou affiner des modèles IA User-agent: * Content-Signal: search=yes, ai-train=yes, ai-input=yes Allow: / Sitemap: https://www.rankit.fr/sitemap.xml
Les commentaires ne sont pas obligatoires mais recommandés par contentsignals.org : ils rendent la politique lisible par un humain qui auditerait votre fichier, et explicitent la sémantique des trois signaux pour quiconque ne connaît pas encore le framework. Vous pouvez aussi générer une version personnalisée plus complète sur contentsignals.org avec leur outil officiel.
Pour les politiques plus restrictives, voici trois exemples qui correspondent à des cas d'usage courants :
# Cas A : permissive maximale (choix rankit.fr) # Pour les sites qui veulent maximiser leur visibilité dans les IA Content-Signal: search=yes, ai-train=yes, ai-input=yes # Cas B : refuser uniquement l'entraînement (choix par défaut Cloudflare managé) # Pour les sites qui acceptent la citation mais refusent que leur contenu # alimente l'entraînement de modèles fondationnels Content-Signal: search=yes, ai-train=no, ai-input=yes # Cas C : recherche classique uniquement # Pour les sites média sur abonnement, publications scientifiques sous embargo, # contenus juridiques sensibles Content-Signal: search=yes, ai-train=no, ai-input=no
Note importante : l'en-tête HTTP content-signal n'est pas le mécanisme principal
Précision technique pour ne pas se tromper. Quand Cloudflare convertit du HTML en Markdown via Markdown for Agents, sa réponse HTTP inclut effectivement un en-tête content-signal: ai-train=yes, search=yes, ai-input=yes. Cet en-tête HTTP est cohérent avec ce qui est déclaré dans le robots.txt, mais ce n'est pas ce que les crawlers consultent en premier. Les crawlers conformes vont d'abord lire robots.txt, et l'en-tête HTTP n'est que la confirmation par requête de la politique globale.
Concrètement : si vous ajoutez Header set Content-Signal dans votre .htaccess mais pas la directive dans robots.txt, les crawlers ne verront pas votre politique au moment où ils décident de collecter votre contenu. La règle est donc : la déclaration vit dans robots.txt, l'en-tête HTTP est secondaire et plutôt destiné aux clients qui ont déjà fetché le contenu.
robots.txt. Ensuite, c'est indépendant de Cloudflare : votre politique vous appartient et reste valable même si vous changez de CDN demain. Enfin, c'est conforme au framework standardisé contentsignals.org, ratifié par l'IETF dans le groupe de travail AI Preferences (AIPREF).
Le piège Lighthouse : pourquoi votre score SEO peut tomber à 92
Soyons honnêtes sur un effet secondaire que vous allez rencontrer en déployant cette directive. Au moment où vous ajoutez Content-Signal: à votre robots.txt, votre score Lighthouse SEO va probablement chuter de 100 à 92. C'est exactement ce qui s'est passé sur rankit.fr. Search Console peut aussi afficher un avertissement « Syntax not understood » sur cette ligne.
La raison est mécanique. Lighthouse fait huit audits SEO automatisés, chacun pèse environ 12,5 points sur le score final. L'un de ces audits est « robots.txt is valid » qui vérifie que toutes les directives appartiennent à une liste blanche connue (User-agent, Allow, Disallow, Sitemap, Crawl-delay, etc.). Comme Content-Signal n'est pas encore dans cette liste blanche au moment où j'écris ces lignes, Lighthouse signale la directive comme « Unknown directive », l'audit échoue, et le score tombe d'environ huit points.
Cloudflare reconnaît explicitement le problème dans sa propre documentation :
Et la communauté Chrome a effectivement ouvert le Pull Request #16767 sur le repository Lighthouse pour ajouter Content-Signal à la safelist des directives reconnues. Le PR a été ouvert en octobre 2025 et reste en review au moment de cette publication. Une fois mergé, le warning disparaîtra automatiquement et votre score remontera à 100 sans que vous ayez à toucher à votre robots.txt.
Mais le score Lighthouse SEO n'est pas un signal de ranking Google
Avant de paniquer et de retirer la directive pour récupérer votre 100, lisez ce que John Mueller de l'équipe Search Relations de Google dit régulièrement à ce sujet : le score Lighthouse SEO n'est pas un facteur de classement. Google n'utilise pas ce score pour décider du positionnement de vos pages. C'est un outil de diagnostic destiné aux développeurs, pas un signal de ranking.
L'unité de mesure qui compte vraiment, c'est le comportement réel de Googlebot et l'indexation effective dans Search Console, pas un score agrégé calculé par un outil tiers. La preuve : sur rankit.fr, malgré le score Lighthouse à 92, l'indexation Google fonctionne parfaitement, le crawl est stable, et aucune URL n'a été déréférencée à cause de cette directive.
L'arbitrage devient alors lisible. D'un côté, un score Lighthouse cosmétique qui passe de 100 à 92, sans aucun impact sur le ranking Google réel. De l'autre, un signal GEO standardisé qui exprime à 3,8 millions de domaines Cloudflare et à tous les agents IA conformes votre politique d'usage de contenu. Le choix me semble clair : le vrai gain GEO l'emporte sur le score cosmétique, surtout que ce dernier est une régression temporaire dont la résolution est déjà engagée côté Lighthouse.
Vos trois stratégies face à ce dilemme
Pour les sites où le score Lighthouse a une importance contractuelle ou commerciale (présentations clients, audits d'agence, monitoring automatisé), voici les options possibles, classées de la plus pédagogique à la plus défensive :
- Garder la directive et expliquer. C'est le choix de rankit.fr. Si quelqu'un vous interpelle sur le score 92, vous lui montrez le PR Lighthouse en attente, vous citez John Mueller, et vous expliquez que vous êtes en avance d'environ six mois sur la safelist. C'est un argument de maturité technique, pas une faute.
- Garder la directive et auto-documenter le robots.txt. Vous ajoutez en commentaires de votre
robots.txtune note explicative qui contextualise la directive et anticipe la critique. Quiconque lit le fichier comprend tout de suite pourquoi elle est là, et où on en est dans le cycle de standardisation. - Retirer temporairement la directive. Si vous gérez un site institutionnel à fort enjeu commercial sur les scores agrégés, vous pouvez décider d'attendre que Lighthouse merge le PR avant de déployer Content-Signal. Vous perdez le signal GEO marginal, mais vous préservez votre 100. C'est un choix défensif, pas une erreur.
Sur rankit.fr, j'ai opté pour la stratégie hybride entre les deux premières options : la directive est en place, et le robots.txt contient une note explicative en commentaires. Le score Lighthouse SEO est à 92, mais le score Cloudflare AI Compatibility est à 100/100, et le ranking Google est intact. Trois mesures qui pointent dans des directions différentes, et qui ensemble racontent l'histoire d'un site qui assume d'être en avance sur la transition GEO.
Le palier final : Link headers RFC 8288 pour décrocher le 100/100
3 min.htaccess. La RFC 8288 standardise un en-tête HTTP Link: qui annonce aux agents IA, dès le premier appel, où trouver les ressources machine-lisibles décrivant le site (sitemap, robots.txt, documentation API). L'audit Cloudflare valide cette pratique sous le check linkHeaders de la section Discoverability. Piège technique sous LiteSpeed à connaître : l'échappement des doubles quotes par \" casse le parsing.
Le principe : annoncer ses ressources machine-lisibles
Les Link headers existent depuis la RFC 5988 de 2010, mise à jour par la RFC 8288 en 2017. Le concept est simple : ajouter un ou plusieurs en-têtes HTTP Link: à la réponse de la page d'accueil, qui pointent vers des ressources liées avec une relation typée. Le client lit ces en-têtes avant même de parser le HTML, et sait immédiatement quelles autres ressources consulter.
Pour les agents IA, c'est un mécanisme de découverte central. Au lieu de scraper toute votre arborescence pour trouver le sitemap ou le robots.txt, ils lisent les Link headers de votre racine et savent où aller. C'est la version industrialisée du « voici la carte du site, servez-vous ».
L'audit Cloudflare AI Compatibility teste précisément ce critère sous le nom linkHeaders, dans la section Discoverability. Pour le valider, il faut que la réponse à GET / contienne au moins un en-tête Link: avec une relation reconnue par l'IANA Link Relations Registry et identifiée comme agent-useful. Les quatre relations principales sont :
| Relation | Cible typique | Cas d'usage |
|---|---|---|
describedby | sitemap.xml, robots.txt, llms.txt | Description machine-lisible du site (la plus polyvalente) |
api-catalog | /.well-known/api-catalog | Catalogue d'API publique conforme RFC 9727 |
service-desc | openapi.yaml, swagger.json | Spécification OpenAPI ou similaire |
service-doc | /docs/api, /api/help | Documentation humaine de l'API |
Pour un site éditorial comme rankit.fr qui n'expose pas d'API publique, la relation à utiliser est describedby. Elle pointe vers les ressources qui décrivent le site, à savoir le sitemap XML et le robots.txt. Pour un site SaaS ou un éditeur d'API, vous combineriez describedby avec api-catalog ou service-desc.
Le code .htaccess à ajouter
Trois lignes à insérer dans le bloc mod_headers du .htaccess, après les blocs Markdown for Agents existants :
# Bloc 4 : Link headers RFC 8288 pour la découverte agent # (critère linkHeaders de l'audit Cloudflare AI Compatibility) <IfModule mod_headers.c> Header set Link '</sitemap.xml>; rel="describedby"; type="application/xml"' Header append Link '</robots.txt>; rel="describedby"; type="text/plain"' </IfModule>
La directive Header set Link définit le premier en-tête, la directive Header append Link en ajoute un second séparé par une virgule (équivalent à deux en-têtes Link: distincts dans la réponse HTTP, c'est conforme à la RFC). Le résultat servi sur la racine donne :
HTTP/2 200 content-type: text/html; charset=UTF-8 link: </sitemap.xml>; rel="describedby"; type="application/xml" link: </robots.txt>; rel="describedby"; type="text/plain"
Le piège LiteSpeed : doubles quotes échappées par backslash
Voici un piège qui m'a coûté un audit raté lors du premier essai. La syntaxe Apache classique pour les valeurs avec espaces utilise des doubles quotes externes et des doubles quotes internes échappées par backslash :
# Cette syntaxe est valide Apache mais cassée sur LiteSpeed Header set Link "</sitemap.xml>; rel=\"describedby\"; type=\"application/xml\""
Sous Apache 2.4 standard, cette ligne fonctionne et l'en-tête HTTP servi est correctement décodé. Mais sous LiteSpeed (le serveur utilisé par défaut sur la plupart des hébergements mutualisés français comme O2switch, Infomaniak ou OVH Performance), le parser interprète littéralement les \" et les inclut dans la valeur servie. Résultat dans la réponse HTTP :
link: </sitemap.xml>; rel=\"describedby\"; type=\"application/xml\"
Les backslashes sont préservés littéralement, et les parsers RFC 8288 (dont celui de l'audit Cloudflare) échouent à reconnaître la relation describedby parce qu'elle est entourée de \" au lieu de ". L'audit a renvoyé le verdict « Link headers present but no agent-useful relation types found », ce qui était techniquement exact : aucune relation n'était parsable.
La solution est élégante. Apache mod_headers accepte les simples quotes comme délimiteurs de valeur, exactement comme un shell Unix. À l'intérieur de simples quotes, les doubles quotes sont préservées telles quelles sans aucun échappement nécessaire. C'est la syntaxe officielle utilisée dans la documentation Apache de référence du framework IIIF.
Validation : passer Discoverability de 2/3 à 3/3
Une fois le snippet déployé, le test se fait en deux étapes. D'abord, vérification curl pour s'assurer que les en-têtes HTTP servis sont propres :
# La sortie ne doit contenir aucun backslash
curl -I https://www.rankit.fr/ | grep -i "link:"
Puis relance de l'audit Cloudflare avec le profil complet pour que la section Discoverability soit testée intégralement :
Lancer l'audit Rankit (7 checks) sur isitagentready.com
Sur rankit.fr, le résultat de cet audit final est sans appel : score global 100/100, Discoverability 3/3, Content 1/1, Bot Access Control 2/2, niveau Level 5 Agent-Native confirmé. C'est l'aboutissement complet de la promesse de cet article. Trois fichiers de configuration, moins de quarante lignes au total, zéro service externe, et le site décroche le score maximal de l'audit Cloudflare AI Compatibility sur les sept critères testés.
Et pour les sites sous Nginx ?
2 minmap détecte Accept: text/markdown, suivi d'une directive try_files dans le bloc location qui sert le .md si présent. Configuration prête à coller fournie. Compatible Nginx 1.18+, OpenResty, Plesk Onyx.
Tout le monde n'est pas sous Apache. Pour les sites Nginx (souvent utilisés sur VPS Hetzner, OVH Cloud, AWS Lightsail, ou en stack moderne avec PHP-FPM), la même logique se transpose élégamment. Nginx n'a pas l'équivalent direct de .htaccess, la configuration se fait dans le fichier de site (typiquement /etc/nginx/sites-available/votre-site.conf).
# ============================================================= # Au niveau http {} : map qui détecte Accept: text/markdown # ============================================================= map $http_accept $wants_markdown { default 0; "~*text/markdown" 1; } # ============================================================= # Au niveau server {} : déclaration MIME et logique de service # ============================================================= server { listen 443 ssl http2; server_name www.example.com; root /var/www/html; # Type MIME pour les .md types { text/markdown md; } charset utf-8; location / { # Si Accept: text/markdown ET .md existe : on le sert if ($wants_markdown) { rewrite ^/$ /index.md break; rewrite ^/(.+?)(\.html)?$ /$1.md break; } # Fallback HTML normal try_files $uri $uri.html $uri/ =404; } # En-têtes pour les .md servis location ~ \.md$ { add_header Content-Type "text/markdown; charset=utf-8" always; add_header Vary "Accept" always; add_header X-Content-Negotiation "markdown-served" always; add_header X-Robots-Tag "noindex, nofollow" always; add_header Content-Disposition "inline" always; } # Vary: Accept aussi sur les .html (cohérence cache) location ~ \.html$ { add_header Vary "Accept" always; } }
Trois points d'attention spécifiques à Nginx.
Le bloc map doit être placé au niveau http {} dans nginx.conf, pas dans le bloc server. C'est une particularité Nginx : les directives map ne sont pas autorisées dans le contexte server.
La directive if dans location est connue pour ses pièges (if is evil), mais ici l'usage avec rewrite ... break est sûr et idiomatique. Pas de risque de boucle.
Recharger la configuration après modification : sudo nginx -t pour valider la syntaxe, puis sudo systemctl reload nginx. Sur un VPS bien configuré, l'opération est sans coupure.
Comment produire les fichiers Markdown jumeaux
2 min.md qui doit exister. Trois voies pour les produire : conversion manuelle au moment de la rédaction, script PHP automatique au déploiement, ou convertisseur en ligne comme rankit.fr/md/. Sur rankit.fr, j'utilise une combinaison des trois selon les pages.
Tout le mécanisme .htaccess repose sur l'existence de fichiers .md jumeaux à côté des fichiers .html. Si un article s'appelle livre-blanc-geo-greenred-2026.html, il faut un fichier livre-blanc-geo-greenred-2026.md à la racine pour que la content negotiation fonctionne sur cette URL.
La question logique devient donc : comment produire ces fichiers Markdown ? Trois approches existent, chacune avec ses avantages.
Approche manuelle au moment de la rédaction
C'est la voie que j'ai privilégiée pour mes articles importants. Au moment où je rédige le HTML d'un article, je rédige aussi sa version Markdown source. Le Markdown devient en réalité le format maître, et le HTML est généré à partir de lui (par moi, manuellement, ou via un convertisseur).
Avantages : qualité maximale du Markdown servi (pas de bruit, structure fidèle aux intentions de l'auteur). Inconvénients : effort double à la rédaction, et risque de désynchronisation HTML/MD si on modifie l'un sans l'autre.
Approche script PHP automatique
Pour les sites avec un grand nombre de pages générées dynamiquement (CMS, e-commerce, sites éditoriaux à fort volume), une conversion automatique au moment du build ou en cron quotidien est plus réaliste. Plusieurs bibliothèques PHP font le travail :
- league/html-to-markdown (Composer) : robuste, bien maintenu, supporte les principales extensions Markdown
- turndown (Node.js, si vous avez un build pipeline) : très configurable, populaire dans l'écosystème JS
- pandoc en CLI : la référence absolue, à invoquer en post-build via
pandoc -f html -t markdown_strict
L'idée : à chaque déploiement, un script parcourt le dossier, lit chaque .html, en extrait le contenu principal (sans nav, sans sidebar, sans footer), le convertit en Markdown et écrit le .md jumeau. Le résultat est mécaniquement à jour.
Approche convertisseur en ligne : rankit.fr/md/
Pour les sites éditoriaux qui n'ont pas envie d'installer Composer ou Pandoc, la voie la plus simple est de passer par un convertisseur qui prend une URL HTML en entrée et retourne du Markdown propre en sortie. C'est exactement ce que j'ai développé sur rankit.fr/md/, après avoir constaté que les outils existants étaient soit verbeux (gardaient trop de balises), soit trop décharnés (perdaient les liens internes).
Le convertisseur Rankit fait trois choses qu'on peut difficilement obtenir ailleurs :
- Il nettoie agressivement les éléments non-sémantiques (CSS inline, scripts, ARIA, blocs de navigation)
- Il préserve la structure sémantique : titres, listes, citations, code, liens et tableaux dans leur forme Markdown standard
- Il respecte l'encodage UTF-8 français (un point souvent défaillant chez les convertisseurs anglophones avec les apostrophes typographiques et les caractères accentués)
L'outil est gratuit, sans inscription, conçu pour être l'outil que j'aurais aimé trouver quand j'ai commencé ce projet sur rankit.fr. Vous collez l'URL de votre page HTML, vous récupérez le Markdown formaté, vous l'enregistrez à côté du .html. Trois clics, et votre page est prête pour la content negotiation.
Convertissez vos pages HTML en .md propres en 3 clics
Vous avez activé la content negotiation Markdown sur votre .htaccess ? Il vous manque les fichiers .md jumeaux pour que ça fonctionne. Le convertisseur Rankit transforme n'importe quelle URL HTML en Markdown propre, sans bruit, encodage UTF-8 préservé, structure sémantique respectée. Sans inscription, sans limite raisonnable.
Le .htaccess final : bloc complet à copier-coller
2 min.htaccess complet qui consolide les quatre blocs construits au fil de l'article : (1) mod_rewrite pour la content negotiation, (2) mod_headers pour Content-Type et Vary, (3) AddType pour le MIME .md, (4) Link headers RFC 8288. Une quarantaine de lignes effectives, prêtes à coller dans un .htaccess vierge, validées en production sur rankit.fr (LiteSpeed / O2switch). Score : 100/100 Cloudflare AI Compatibility · Level 5 Agent-Native.
Voici la version consolidée et prête à déployer. Chacun des quatre blocs a été construit et expliqué un par un dans les sections précédentes. Les voici assemblés dans le bon ordre, avec commentaires détaillés, prêts à être collés tels quels dans un .htaccess vierge à la racine du site.
À placer après vos règles HTTPS/www mais avant toute règle applicative (WordPress, Laravel, routing custom). Compatible Apache 2.4+, LiteSpeed (O2switch, Hostinger, Infomaniak, OVH Performance), et tout serveur supportant les .htaccess.
# ================================================================ # .HTACCESS COMPLET · MARKDOWN FOR AGENTS · CLOUDFLARE 100/100 # ================================================================ # Testé en production sur rankit.fr (O2switch / LiteSpeed) # Audit Cloudflare AI Compatibility : 100/100 · Level 5 Agent-Native # Compatible Apache 2.4+, LiteSpeed, Nginx via traduction séparée # ================================================================ # # BLOC 1 · mod_rewrite : Accept: text/markdown -> fichier .md jumeau # BLOC 2 · mod_headers : Content-Type, Vary, X-Content-Negotiation # BLOC 3 · mod_mime : type MIME, charset, inline, noindex # BLOC 4 · mod_headers : Link headers RFC 8288 (Discoverability) # ================================================================ # --- BLOC 1 : réécriture si Accept: text/markdown --- <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # Cas 1 : racine "/" avec Accept: text/markdown RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/?$ RewriteCond %{DOCUMENT_ROOT}/index.md -f RewriteRule ^$ /index.md [L,E=IS_MARKDOWN:1] # Cas 2 : URL propre /slug (sans extension) RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/([^.]+)$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^([^.]+)$ /$1.md [L,E=IS_MARKDOWN:1] # Cas 3 : URL legacy /slug.html avec extension explicite RewriteCond %{HTTP_ACCEPT} text/markdown [NC] RewriteCond %{REQUEST_URI} ^/(.+)\.html$ RewriteCond %{DOCUMENT_ROOT}/%1.md -f RewriteRule ^(.+)\.html$ /$1.md [L,E=IS_MARKDOWN:1] </IfModule> # --- BLOC 2 : en-têtes HTTP de réponse --- <IfModule mod_headers.c> Header set Content-Type "text/markdown; charset=utf-8" env=IS_MARKDOWN Header set X-Content-Negotiation "markdown-served" env=IS_MARKDOWN # Vary: Accept (obligatoire) pour les caches CDN (LiteSpeed, Cloudflare) <FilesMatch "\.(html|md)$"> Header append Vary "Accept" </FilesMatch> </IfModule> # --- BLOC 3 : MIME et configuration des .md --- <IfModule mod_mime.c> AddType text/markdown .md AddCharset UTF-8 .md </IfModule> <FilesMatch "\.md$"> Header set Content-Disposition "inline" Header set X-Robots-Tag "noindex, nofollow" </FilesMatch> # --- BLOC 4 : Link headers RFC 8288 (Discoverability 3/3) --- # IMPORTANT : simples quotes obligatoires sous LiteSpeed # (l'échappement avec \" casse le parsing) <IfModule mod_headers.c> Header set Link '</sitemap.xml>; rel="describedby"; type="application/xml"' Header append Link '</robots.txt>; rel="describedby"; type="text/plain"' </IfModule>
Une fois ce .htaccess déployé à la racine du site et le robots.txt contenant la directive Content-Signal, l'audit Cloudflare AI Compatibility renvoie :
- Score global : 100/100 · Level 5 Agent-Native
- Discoverability : 3/3 · sitemap, robots.txt et Link headers détectés
- Content : 1/1 · négociation Markdown supportée
- Bot Access Control : 2/2 · politique Content-Signal déclarée
Trois fichiers, une quarantaine de lignes de code, zéro abonnement CDN. Le même résultat que Cloudflare facture 240 $/an minimum sur le plan Pro, ici en Apache pur, sous votre contrôle total, avec la liberté d'étendre la politique à votre rythme.
.htaccess à la racine du site.
2. S'assurer que chaque page HTML dispose d'un fichier .md jumeau (manuellement, par script PHP, ou via le convertisseur rankit.fr/md/).
3. Ajouter la directive Content-Signal dans votre robots.txt (voir section 8).
4. Purger le cache LSCache via cPanel le cas échéant.
5. Lancer les quatre tests curl de la section 5 pour valider.
6. Relancer l'audit Cloudflare pour confirmer le 100/100.
Palier bonus : /.well-known/api-catalog (RFC 9727)
2 min/api/post/{slug}.json construit plus tôt), une dernière brique complète l'agent-readiness : la norme IETF RFC 9727 publiée en juin 2025, qui standardise /.well-known/api-catalog. Trois lignes de .htaccess, un fichier Linkset JSON, et n'importe quel agent IA peut désormais découvrir le catalogue d'API dès la première requête HTTP. Le check apiCatalog de l'audit Cloudflare, dans la catégorie API/Auth/MCP & Skill Discovery, reconnaît cette voie.
Nos sections précédentes ont couvert trois formats servis via content negotiation : HTML pour les humains, Markdown pour les crawlers IA, et JSON via l'endpoint /api/post/{slug}.json. La question naturelle qui se pose ensuite : comment un agent découvre-t-il que l'endpoint JSON existe ?
Trois voies de découverte coexistent aujourd'hui, avec des niveaux d'agent-readiness différents :
- Le
<link rel="alternate" type="application/json">dans le<head>HTML : l'agent doit télécharger et parser le HTML d'abord. - Le champ
alternateFormatà l'intérieur du JSON lui-même : l'agent doit déjà avoir fetché le JSON pour le trouver. - La voie well-known RFC 9727 : l'agent fetche une URL prédictible unique et obtient le catalogue complet, sans parsing HTML.
La troisième voie est la plus agent-native. C'est aussi la plus jeune : la norme est la RFC 9727, ratifiée par l'IETF en juin 2025 par Kevin Smith (Vodafone) après treize révisions et deux ans de travail.
Le principe : un well-known URI prédictible
La RFC définit un well-known URI unique : /.well-known/api-catalog. Tout client conforme peut faire un GET sur cette URL sur n'importe quel domaine et savoir immédiatement quelles APIs sont exposées et où les trouver. Le mécanisme s'appuie sur la RFC 8615 (Well-Known URIs) et le format Linkset JSON de la RFC 9264.
Trois points techniques obligatoires pour satisfaire la RFC :
- L'endpoint DOIT être servi en HTTPS (recommandation de sécurité §8 de la RFC).
- La réponse DOIT être disponible au format
application/linkset+jsondéfini par la RFC 9264. - Le Content-Type DEVRAIT inclure le paramètre profile
profile="https://www.rfc-editor.org/info/rfc9727"pour que les consommateurs puissent identifier le document comme un api-catalog valide.
Le fichier linkset.json
Le format Linkset (RFC 9264) est simple : un document JSON avec un tableau linkset à la racine, chaque entrée contenant une URL anchor et un ensemble de relations de lien typées. Pour rankit.fr, le fichier est placé à la racine du site sous /linkset.json.
{
"linkset": [
{
"anchor": "https://www.rankit.fr/api/post/",
"service-doc": [
{
"href": "https://www.rankit.fr/geo-markdown-content-negotiation-apache-gratuit",
"type": "text/html",
"hreflang": ["fr"],
"title": "Documentation API (français)"
}
],
"service-meta": [
{
"href": "https://www.rankit.fr/api/post/geo-markdown-content-negotiation-apache-gratuit.json",
"type": "application/json",
"title": "Représentation JSON d'article (Schema.org TechArticle)"
}
],
"license": [
{ "href": "https://creativecommons.org/licenses/by-sa/4.0/" }
]
}
]
}
Les relations de lien utilisées (service-doc, service-meta, license) viennent du registre IANA des Link Relations. Leur sémantique est standardisée : service-doc pointe vers la documentation API lisible par un humain, service-meta vers les métadonnées additionnelles sur les endpoints API (ici, la voie de content negotiation JSON).
Le code .htaccess (Bloc 6)
Trois choses à faire côté serveur : router /.well-known/api-catalog vers le fichier physique, servir le bon Content-Type, et annoncer le catalogue via un Link header sur chaque page HTML.
# --- Bloc 6 : api-catalog (RFC 9727) --- <IfModule mod_rewrite.c> RewriteCond %{REQUEST_URI} ^/\.well-known/api-catalog/?$ [NC] RewriteRule ^\.well-known/api-catalog/?$ /linkset.json [L,E=IS_LINKSET:1] </IfModule> <IfModule mod_headers.c> Header set Content-Type "application/linkset+json; profile=\"https://www.rfc-editor.org/info/rfc9727\"" env=IS_LINKSET Header set Cache-Control "public, max-age=3600" env=IS_LINKSET # Annonce du catalogue via Link header sur chaque page HTML <FilesMatch "\.html$|/$"> Header append Link '</.well-known/api-catalog>; rel="api-catalog"; type="application/linkset+json"' </FilesMatch> </IfModule>
Validation curl
Trois vérifications pour confirmer le bon déploiement :
# Test 1 : l'endpoint well-known sert le bon Content-Type curl -I https://www.rankit.fr/.well-known/api-catalog # Attendu : content-type: application/linkset+json; profile="..." # Test 2 : le contenu JSON est valide et parsable curl https://www.rankit.fr/.well-known/api-catalog | jq . # Test 3 : la page d'accueil annonce le catalogue via Link header curl -I https://www.rankit.fr/ | grep -i "link:" # Attendu, parmi d'autres : link: </.well-known/api-catalog>; rel="api-catalog"; ...
Avis honnête sur le gain à l'audit
En toute transparence : déployer l'api-catalog ne fait pas monter le score global au-dessus de 100/100. Vous êtes déjà au maximum. Ce que cela change, c'est le périmètre de l'audit, qui s'étend de trois catégories (Discoverability, Content, Bot Access Control) à quatre, avec la nouvelle catégorie API/Auth/MCP/Skill Discovery également à 100/100.
Quand vous activez la catégorie API/Auth/MCP & Skill Discovery dans l'audit, Cloudflare exécute le check apiCatalog (cette section, Bloc 6) et le check agentSkills (Bloc 7, voir section suivante). Les deux passent pour rankit.fr, ce qui donne un 2/2 sur cette catégorie et confirme le déploiement. Les autres checks potentiels documentés dans les premières specs (oauthDiscovery, oauthProtectedResource, mcpServerCard, a2aAgentCard, webMcp) ne font pas partie du scope d'audit actuel à avril 2026.
La question stratégique devient donc : en ai-je besoin pour un site éditorial ? Pour rankit.fr, la réponse est nuancée. Ce n'est pas un SaaS avec une API publique OAuth, pas de serveur MCP, pas d'agent skills exposées au sens strict du terme. Mais la sortie JSON de chaque article via /api/post/{slug}.json est une API publique au sens architectural. La déclarer via la voie standardisée RFC 9727 est techniquement rigoureux, ne coûte rien, et signale une maturité technique aux agents discriminants.
apiCatalog validé. L'api-catalog est exposé conformément au standard IETF RFC 9727, et rankit.fr reste en avance sur la courbe des normes au fur et à mesure que de nouveaux checks sont ajoutés. Anticiper les normes fait partie du métier.
Palier bonus 2 : /.well-known/skills (Agent Skills Discovery)
3 minagentSkills de l'audit Cloudflare cherche un /.well-known/skills/index.json qui liste des Agent Skills (un draft RFC Cloudflare, version 0.1, janvier 2026, qui s'appuie sur le format Skills d'Anthropic). Pour rankit.fr, trois vrais skills sont exposés : la content negotiation Markdown sur Apache, la directive Content-Signal dans robots.txt, et les Link headers RFC 8288 sous LiteSpeed. Avec le Bloc 6 (api-catalog) et ce Bloc 7 déployés, l'audit retourne 2/2 sur la catégorie API/Auth/MCP/Skill Discovery et confirme le 100/100 sur quatre catégories.
Le format Agent Skills vient d'Anthropic et a été adopté par OpenAI Codex, OpenCode et désormais Cloudflare. Un skill est un dossier qui contient un fichier SKILL.md avec un frontmatter YAML (champs name et description) et des instructions Markdown. Les agents IA peuvent récupérer l'index, découvrir les skills disponibles, et charger progressivement ceux qui sont pertinents pour la tâche en cours.
Pour un site éditorial comme rankit.fr, exposer des skills revient à publier de l'expertise structurée et lisible par machine que n'importe quel agent conforme peut consommer directement. C'est un pas au-delà des articles destinés à la lecture humaine : les skills sont du savoir opérationnel qu'un agent peut appliquer immédiatement.
Structure de dossiers
Le draft Cloudflare spécifie une hiérarchie prédictible sous /.well-known/skills/ :
/.well-known/skills/ ├── index.json # Obligatoire : index des skills ├── htaccess-markdown-negotiation/ │ └── SKILL.md # Skill 1 : content negotiation Markdown ├── content-signal-robots-txt/ │ └── SKILL.md # Skill 2 : Content-Signal robots.txt └── rfc8288-link-headers-litespeed/ └── SKILL.md # Skill 3 : Link headers sous LiteSpeed
Le fichier index.json
L'index liste chaque skill disponible avec son nom, sa description et les fichiers présents dans son dossier. Chaque nom de skill doit respecter la spec de nommage Agent Skills (1 à 64 caractères alphanumériques minuscules et tirets, sans tiret de début ou de fin).
{
"skills": [
{
"name": "htaccess-markdown-negotiation",
"description": "Configurer un .htaccess Apache (ou LiteSpeed) pour servir du Markdown aux crawlers IA via la content negotiation HTTP quand ils envoient l'en-tête Accept text/markdown...",
"files": ["SKILL.md"]
},
{
"name": "content-signal-robots-txt",
"description": "Ajouter la directive Content-Signal dans un robots.txt pour déclarer les préférences d'usage IA...",
"files": ["SKILL.md"]
},
{
"name": "rfc8288-link-headers-litespeed",
"description": "Configurer des Link headers RFC 8288 dans un .htaccess Apache (ou LiteSpeed)...",
"files": ["SKILL.md"]
}
]
}
Un fichier SKILL.md
Chaque SKILL.md commence par un frontmatter YAML (entre deux lignes ---) suivi d'instructions Markdown. Le frontmatter doit déclarer name et description ; tout ce qui suit est du Markdown libre lu par l'agent quand le skill s'active.
--- name: htaccess-markdown-negotiation description: Configure an Apache .htaccess (or LiteSpeed) to serve Markdown to AI crawlers via HTTP content negotiation when they send the Accept text/markdown header. Use when setting up a website to be agent-ready, when implementing Markdown for Agents on shared hosting, or when targeting the Cloudflare AI Compatibility audit Content score (markdownNegotiation check). --- # Apache Markdown Content Negotiation for AI Crawlers ## What this skill does Configures an Apache HTTP server (or LiteSpeed, the default on most French shared hosting like O2switch, Infomaniak, OVH Performance) to serve Markdown content to AI crawlers when they send the HTTP header `Accept: text/markdown`... ## When to use - Setting up a website to be readable by AI crawlers - Implementing GEO on Apache or LiteSpeed - Reducing token consumption for AI agents fetching the site - Passing the Content score on Cloudflare's `isitagentready.com` audit ## Implementation [Bloc Apache .htaccess complet, exactement celui de la Section 4 de cet article]
Note : les SKILL.md sont publiés en anglais pour maximiser la lisibilité par les agents IA, qui consomment du contexte multilingue mais favorisent l'anglais pour les instructions techniques. La description et le contenu pédagogique restent traduits dans cet article en français.
Le code .htaccess (Bloc 7)
Même approche que pour le Bloc 6 : servir le bon Content-Type pour l'index et pour les fichiers SKILL.md, et fournir un alias depuis l'ancienne URL /.well-known/agent-skills/ vers le chemin officiel /.well-known/skills/, pour que l'audit et les futurs scanners trouvent les ressources au même emplacement.
# --- Bloc 7 : Agent Skills Discovery --- <IfModule mod_rewrite.c> # Alias : /.well-known/agent-skills/ -> /.well-known/skills/ RewriteCond %{REQUEST_URI} ^/\.well-known/agent-skills/(.+)$ [NC] RewriteRule ^\.well-known/agent-skills/(.+)$ /.well-known/skills/$1 [L] </IfModule> <IfModule mod_headers.c> # Content-Type pour l'index <Files "index.json"> Header set Content-Type "application/json; charset=utf-8" Header set Cache-Control "public, max-age=3600" Header set Access-Control-Allow-Origin "*" </Files> # Content-Type pour les fichiers SKILL.md <FilesMatch "^SKILL\.md$"> Header set Content-Type "text/markdown; charset=utf-8" Header set Cache-Control "public, max-age=3600" Header set Access-Control-Allow-Origin "*" </FilesMatch> </IfModule>
Validation curl
# Test 1 : index.json est servi en application/json curl -I https://www.rankit.fr/.well-known/skills/index.json # Attendu : content-type: application/json; charset=utf-8 # Test 2 : l'alias /.well-known/agent-skills/ renvoie le même contenu curl -I https://www.rankit.fr/.well-known/agent-skills/index.json # Attendu : même réponse que le test 1 # Test 3 : SKILL.md est servi en text/markdown curl -I https://www.rankit.fr/.well-known/skills/htaccess-markdown-negotiation/SKILL.md # Attendu : content-type: text/markdown; charset=utf-8
Résultat de l'audit avec les quatre catégories
Avec le Bloc 6 (api-catalog) et le Bloc 7 (Agent Skills) déployés, l'audit Cloudflare peut exécuter neuf checks répartis sur quatre catégories. Lien direct pour reproduire le scan rankit.fr :
Lancer l'audit Rankit (9 checks) sur isitagentready.com
Résultat attendu :
- Score global : 100/100 · Level 5 Agent-Native
- Discoverability : 3/3 · sitemap, robots.txt, Link headers
- Content : 1/1 · négociation Markdown
- Bot Access Control : 2/2 · politique Content-Signal
- API/Auth/MCP/Skill Discovery : 2/2 · API Catalog + Agent Skills index
htaccess-markdown-negotiation, content-signal-robots-txt, rfc8288-link-headers-litespeed) sont extraits du contenu réel de cet article. C'est de la véritable expertise que tout agent conforme peut appliquer directement. L'audit passe et les skills aident réellement les agents downstream qui les consomment.
Questions fréquentes
3 min.md jumeaux, l'en-tête Vary: Accept, l'impact SEO, les crawlers concernés en 2026, la vérification, l'équivalent Nginx, et la justification du choix .htaccess sur rankit.fr.
Le Markdown est aujourd'hui le format que les LLM préfèrent traiter. Sa structure explicite (titres, listes, liens) est lisible directement par les modèles, sans rendu visuel ni parsing complexe, et elle réduit drastiquement la consommation de tokens par rapport au HTML, qui contient beaucoup de bruit (CSS inline, balises de mise en page, scripts, attributs ARIA). Servir une version Markdown améliore la qualité des extractions par les LLM tout en réduisant le coût d'inférence pour les agents qui consomment vos pages.
La fonctionnalité Markdown for Agents est disponible sur les plans Cloudflare Pro (240 $/an en facturation annuelle, soit 300 $/an en mensuel), Business (2 400 $/an annuel ou 3 000 $/an mensuel) et Enterprise (à partir de 24 000 $/an). Elle est explicitement exclue du plan Free dans la documentation officielle Cloudflare.
Oui. LiteSpeed est compatible avec la syntaxe Apache mod_rewrite et mod_headers. Le .htaccess décrit dans cet article a été testé en production sur rankit.fr hébergé chez O2switch (LiteSpeed mutualisé) et passe l'audit Cloudflare AI Compatibility avec succès. Aucune adaptation spécifique à LiteSpeed n'est nécessaire pour la content negotiation Markdown. Si vous utilisez LSCache, pensez à purger le cache après modification du .htaccess.
Oui. La logique du .htaccess est de servir un fichier .md jumeau quand le client envoie Accept: text/markdown. Si le .md n'existe pas, le serveur sert le HTML par défaut, sans erreur. La conversion HTML vers Markdown peut se faire manuellement, par script PHP au déploiement, ou avec des outils en ligne comme le convertisseur Rankit (rankit.fr/md/) qui transforme une URL HTML en .md propre.
Oui, sans aucune exception. Vary: Accept indique aux caches CDN, navigateurs et proxies que la réponse dépend de l'en-tête Accept envoyé par le client. Sans ce Vary, un cache peut servir la version Markdown à un visiteur humain qui arriverait sur la même URL après un crawler IA, ou inversement. C'est une faute de configuration majeure qui casse le site pour la moitié des utilisateurs. Sur LiteSpeed et Cloudflare en façade, l'oubli est immédiatement visible.
Aucun impact négatif si la configuration est correcte. Googlebot envoie Accept: text/html par défaut, donc il continue de recevoir le HTML normal. Les fichiers .md sont marqués X-Robots-Tag: noindex, nofollow pour éviter une indexation parasite. Les crawlers IA (GPTBot, ClaudeBot, PerplexityBot) ignorent ces directives et continuent de recevoir le Markdown qu'ils préfèrent. Le SEO Google reste intact, le GEO progresse.
À avril 2026 : ClaudeBot d'Anthropic envoie Accept: text/markdown depuis fin 2025, GPTBot d'OpenAI le supporte sur certains contextes agentiques, PerplexityBot et BraveBot le testent. Au-delà de la mécanique strictement automatique, l'avantage est qu'un développeur d'agent qui pointe son code sur votre site préférera explicitement votre version Markdown : c'est un signal de qualité technique pour l'écosystème entier.
La méthode la plus simple est curl. Lancez curl -I -H "Accept: text/markdown" https://votre-site.fr/ et vérifiez que l'en-tête de réponse contient content-type: text/markdown; charset=utf-8 ainsi que vary: Accept. Vous pouvez aussi utiliser l'audit gratuit Cloudflare AI Compatibility qui teste cette fonctionnalité dans la section Content. Un score 1/1 confirme que tout fonctionne. La section Vérification immédiate avec quatre commandes curl de cet article détaille la procédure complète.
La logique reste identique mais la syntaxe change. Sur Nginx, on utilise un bloc map dans http {} pour détecter Accept: text/markdown, suivi d'une directive try_files dans le bloc location. Le principe : si l'en-tête contient text/markdown et que le fichier .md existe, on le sert avec Content-Type text/markdown. La section Nginx de cet article fournit la configuration complète prête à coller.
Trois raisons. D'abord, le coût : 240 $/an pour activer une case à cocher quand 30 lignes de .htaccess font le même travail, ça n'a pas de sens budgétaire. Ensuite, la pédagogie : démontrer que le GEO n'est pas réservé aux infrastructures CDN haut de gamme, c'est aussi un message porté à mes clients PME. Enfin, le contrôle : maîtriser sa stack permet d'aller plus loin que ce que propose Cloudflare en activant x-markdown-tokens calculé sur mesure et la directive Content-Signal dans le robots.txt avec la politique éditoriale de mon choix.
Conclusion : démocratiser le GEO technique
3 minCet article démontre une chose simple. La négociation de contenu en HTTP, mécanisme que l'IETF a standardisé en 1999 dans la RFC 7231, suffit à faire tout ce que Cloudflare baptise Markdown for Agents. Trente lignes de configuration Apache. Aucune dépendance externe. Aucun abonnement.
Pourtant, autour de cette mécanique élémentaire, s'est construit en quelques mois un récit où le GEO technique deviendrait l'apanage de ceux qui paient un CDN premium. C'est la première chose à corriger.
Le GEO ne doit pas se transformer en marché captif. La promesse des moteurs IA, c'est précisément qu'un site éditorial bien construit, bien structuré, bien documenté, peut être cité par Claude, ChatGPT ou Perplexity à égalité avec les grands sites institutionnels. Cette promesse tombe si on conditionne la visibilité IA à un abonnement à 240 $ par an que beaucoup de TPE et freelances ne peuvent pas justifier.
La deuxième chose à corriger, c'est l'idée que le GEO serait une discipline radicalement nouvelle. Le GEO repose à 80 % sur des fondamentaux techniques anciens : un HTML sémantique propre, une structure de titres cohérente, des liens internes pensés, une vitesse de chargement raisonnable, et donc, désormais, une content negotiation correctement configurée. Tout cela se fait avec les outils standards du web, dans le serveur que vous avez déjà, en quelques heures de travail bien dirigé.
Sur rankit.fr, l'audit Cloudflare AI Compatibility est passé de 50 à 100/100 en moins d'une heure de travail effectif, en quatre paliers progressifs : .htaccess Markdown for Agents (50 → 67), robots.txt avec Content-Signal (67 → 83), Link headers RFC 8288 (83 → 100). Niveau atteint : Level 5 Agent-Native, la classification la plus élevée du système Cloudflare. C'est l'équivalent d'un signal lumineux qui s'allume sur le tableau de bord d'un site et qui dit aux agents IA : oui, vous pouvez me consommer, et dans le format que vous préférez. Pour un consultant SEO/GEO indépendant, c'est exactement le genre d'amélioration que je veux pouvoir reproduire chez chacun de mes clients PME, en facturant le temps et l'expertise, pas l'abonnement à un fournisseur tiers.
Trente lignes de .htaccess. Zéro euro de surcoût annuel. Plus 17 points d'audit Cloudflare en moins d'une heure. Cette équation me satisfait, et je pense qu'elle satisfera la grande majorité des sites Apache et LiteSpeed du monde. Le code est dans cet article. Le convertisseur Markdown est en ligne. Tout le reste, c'est juste du temps de configuration que vous économisez en suivant ce mode d'emploi.
Et le jour où vous voudrez aller plus loin avec une politique Content-Signal sur mesure dans votre robots.txt, un calcul de tokens personnalisé en PHP, ou une politique d'accès différenciée par chemin, vous serez heureux de maîtriser votre stack au lieu de dépendre des conditions générales d'un CDN. Le contrôle technique, dans ce métier, c'est aussi une forme d'indépendance professionnelle.