---
title: "Markdown Copies of Your Posts: Who Reads Them and How to Serve Them Safely"
url: https://hostmy.blog/markdown-version-of-blog-posts/
date: 2026-09-14
modified: 2026-09-03
lang: en
author: "Aditya Sharma"
description: "Content negotiation reaches coding agents only. Distinct.md URLs carry the rest. Here is how to serve both without poisoning your cache."
categories:
  - "RankReady"
image: https://hostmy.blog/wp-content/uploads/2026/09/hmb-card-1864-1024x538.jpg
word_count: 1475
---

# Markdown Copies of Your Posts: Who Reads Them and How to Serve Them Safely

A page tested here weighed 4.7 MB as HTML. The same words as Markdown came to 18 KB. Roughly 260 times smaller, with nothing removed that a reader would miss.

The difference is navigation, inline scripts, base64 images, tracking, cookie markup and the several thousand attributes a modern theme wraps around a paragraph. A machine reading that page spends almost all of its budget on scaffolding.

Serving a Markdown copy fixes that. Unlike llms.txt, where [the evidence points at no citation effect](/llms-txt-does-not-work/), the saving here is measurable at the byte level. The part that gets misreported is who actually receives it, and there are two separate delivery mechanisms with two very different audiences.

## Why 260 times smaller changes the outcome

Size is not a vanity metric here. Every client reading your page works inside a budget, and the budget is spent on whatever arrives.

Measure your own gap:

`curl -s https://yoursite.com/your-post/ | wc -c
curl -s https://yoursite.com/your-post/ \
| tr '\n' ' ' \
| sed -e 's/<script[^>]*>.*<\/script>//g' -e 's/<[^>]*>//g' \
| tr -s ' \n' ' \n' | wc -c`

The first number is what you ship. The second is roughly what a reader came for. On most WordPress themes the ratio is somewhere between 20 and 100 to one before you count images. Running that same ratio across a sitemap is how you go about [finding the pages an AI cannot parse cheaply](/find-pages-ai-cannot-parse/).

The second effect is fidelity. Converting HTML to text loses structure, so a table becomes a run-on line and a code block becomes prose. Markdown keeps the table a table. That is worth more than the byte count on any page carrying commands or comparisons.

## Content negotiation reaches coding agents, and only coding agents

The elegant version of this feature is an `Accept` header. The client asks for `text/markdown`, your server returns Markdown at the same URL, everyone is happy.

That works. It just does not reach who most people assume it reaches.

| Client | Sends `Accept: text/markdown` |
| ------ | ----------------------------- |
| Claude Code | Yes |
| Copilot Chat and Copilot CLI | Yes |
| Cursor | Yes |
| Microsoft Copilot | Yes |
| OpenClaw | Yes |
| OpenCode | Yes |
| ChatGPT browse | No |
| Claude.ai | No |
| Perplexity | No |
| Gemini | No |
| Grok | No |

Coding agents negotiate. Consumer AI clients do not, and [what an assistant's fetch actually looks like](/ai-crawlers-request-by-request/) explains why the two behave so differently. If your reason for adding Markdown is ChatGPT or Perplexity, the header on its own does nothing for you.

That is not a reason to skip it. Coding agents are a real and growing audience, particularly for documentation, tutorials and anything technical. It is a reason to do the second half as well.

## Distinct.md URLs carry the reach the header cannot

The second mechanism is a plain URL that ends in `.md`, discoverable from the HTML page.

`<link rel="alternate" type="text/markdown" href="https://yoursite.com/your-post/index.md">`

Any client that parses your HTML can find that link and follow it. No header, no negotiation, no assumptions about what the client sends. That is why the distinct URL plus the alternate link tag carry the reach, and the header alone does not.

Both mechanisms should point at the same content. Pick one URL shape and keep it. `/your-post/index.md` and `/your-post.md` are both fine, and switching between them later breaks every link anyone has saved.

## Verify both paths with four commands

Check the header route first:

`curl -sI -H "Accept: text/markdown" https://yoursite.com/your-post/ \
| grep -i -E 'http/|content-type|vary'`

You want `content-type: text/markdown; charset=utf-8` back. Getting `text/html` means negotiation is not wired up, and the request fell through to the normal page.

Then confirm the body is really Markdown:

`curl -s -H "Accept: text/markdown" https://yoursite.com/your-post/ | head -20`

Headings should start with `#`. A doctype declaration means you are looking at HTML with a hopeful content type.

Now the URL route:

`curl -sI https://yoursite.com/your-post/index.md | grep -i -E 'http/|content-type'`

And the discovery tag:

`curl -s https://yoursite.com/your-post/ | grep -i 'rel="alternate"'`

All four have to pass. Three out of four is a feature that works in your testing and fails for half the clients that would have used it.

## Cloudflare will happily serve the wrong variant

This is the failure that turns a nice feature into an outage, and it catches people who did everything else correctly.

Correct negotiation requires the response to carry `Vary: Accept`, telling caches that the response body depends on the request header. Setting that header is straightforward.

Cloudflare does not honour `Vary` by default, and it has been changing other defaults too, covered in [Cloudflare's default change for crawler traffic](/cloudflare-crawler-default-wordpress/). Setting `Vary: Accept` on your origin is not the same as the edge respecting it. The edge can cache whichever variant it saw first and serve that to everyone.

The consequence runs both ways. A human visitor gets a wall of raw Markdown. Or a coding agent gets 4.7 MB of HTML and gives up.

Test for it directly:

`# 1. normal request
curl -s -o /dev/null -w 'html req -> %{content_type} %{size_download}\n' \
https://yoursite.com/your-post/

# 2. markdown request
curl -s -o /dev/null -w 'md req -> %{content_type} %{size_download}\n' \
-H "Accept: text/markdown" https://yoursite.com/your-post/

# 3. normal request again, immediately
curl -s -o /dev/null -w 'html again-> %{content_type} %{size_download}\n' \
https://yoursite.com/your-post/`

Line three must match line one. If line three comes back as Markdown, your edge cached the negotiated variant and every visitor is now getting it.

Add cache status to the picture when you are debugging:

`curl -sI -H "Accept: text/markdown" https://yoursite.com/your-post/ \
| grep -i -E 'cf-cache-status|age|vary|cache-control'`

The safe configurations are two: serve Markdown only at distinct `.md` URLs so no negotiation happens at a cached URL, or bypass the cache entirely for requests carrying a Markdown `Accept` header. Both work. Doing negotiation on a cached URL with no cache rule is the one that breaks.

Content negotiation through an edge that ignores Vary

Content negotiation through an edge that ignores Vary

Client
Accept: text/markdown

Edge cache
key: URL only

Origin
Vary: Accept

asks for Markdown

cache miss

Next visitor gets
Markdown
a browser renders raw text
Cloudflare does not honour Vary by default. Test through the CDN, not against the
origin.

Setting Vary: Accept on the origin is correct and not sufficient. An edge keyed on URL alone caches whichever variant it saw first and serves that to everyone.

## Three details that decide whether the copy is useful

Serving Markdown is not the same as serving good Markdown.

**Strip the chrome.** Navigation, related posts, comment threads and the newsletter box do not belong in the Markdown copy. If your generator converts the full page, you have made the file smaller without making it cleaner.

**Keep the front matter minimal and honest.** Title, canonical URL, published date and modified date. That last one matters, because stale pages are roughly three times more likely to lose citations they held, and the Markdown copy is a second place that claim gets made.

**Point canonical at the HTML page.** The Markdown copy is an alternate representation, not a competing document. State that in the front matter and in a `Link: rel="canonical"` header on the `.md` response.

`curl -sI https://yoursite.com/your-post/index.md | grep -i 'link:'`

## The five minute version on WordPress

Doing this by hand means a rewrite rule for the `.md` URLs, a converter that strips theme output rather than the whole page, correct content types on two routes, an alternate link tag injected into `wp_head`, and a cache rule that stops your CDN mixing the variants. Any one of those going wrong produces a feature that looks fine in your browser and fails in the field, which makes it the most fiddly item on [the WordPress checklist behind AI search](/ai-search-optimization-wordpress/).

That whole path is what [RankReady](https://wordpress.org/plugins/rankready-ai-llm-seo/) handles. It is a WordPress AI SEO plugin that runs alongside Rank Math, Yoast, AIOSEO or SEOPress rather than replacing them, and setup runs about five minutes. The cache safety part is the reason it exists as a plugin rather than a snippet, because most WordPress sites sit behind an edge that does not respect `Vary`.

What this buys is crawlability and a far cheaper page for a machine to read. Whether that turns into a citation is not something a plugin decides, and nobody selling you the opposite has the data.

## Run the three line cache test today

If you already serve Markdown, the cache test above is the check worth running first, because it is the one with a visible failure for human visitors.

If you do not serve Markdown yet, start with the distinct `.md` URL and the alternate link tag. That combination has no cache risk and reaches more clients than the header does.

Then work back down the stack. Whether crawlers can fetch anything at all is layer one of [the five checks in the order that makes them mean something](/five-layer-ai-seo-audit/), and the index that points at all of this is covered in [producing the file on a WordPress site](/llms-txt-generator-wordpress/).

Have you ever requested your own page with a Markdown `Accept` header, and do you know what came back?