Skip to main content
When ChatGPT, Claude or Perplexity fetches one of your pages, it does not see the page the way a visitor does. It receives the raw HTML: your navigation, cookie banner, scripts, tracking pixels, footer, and somewhere inside all of that, the words you actually wrote. A Markdown twin is a second copy of the same page, published at its own address, containing only the content. Same words, no layout.
On a typical article the twin is 15 to 25% the size of the HTML page. That difference is the assistant’s reading budget, and it is spent on your content rather than on your markup.

Why this matters

An assistant answering a question has a fixed amount it can read before it stops. Every kilobyte of navigation markup is a kilobyte it does not spend on your argument, your data, or your product. Serving a twin does three things:
  • Your content is read in full, rather than truncated halfway through the page
  • Quotes come out clean, because there is no markup to strip and misread
  • Nothing is guessed, since headings, lists and tables arrive already structured
Your normal pages are unchanged. Visitors, Google and everything else keep seeing exactly what they saw before.

Setting it up on WordPress

The SnowSEO plugin publishes twins for every public post and page. There is nothing to write.
1

Install and connect the plugin

Install SnowSEO from the WordPress plugin directory and connect it to your brand under SnowSEO → Settings.Already publishing to this site from SnowSEO? Then this is done.
2

Switch twins on

Go to Settings → Reading in the WordPress admin and tick “Publish a markdown copy of every public post and page”, then save.
This is off until you turn it on. Enabling it publishes new addresses on your site, so the plugin does not do it for you.
3

Check it worked

Open any published post and add .md to the end of its address:
You should see plain text, starting with a short block of title and date information, then the article. If you get your normal page or a 404, see Troubleshooting below.

What gets a twin

Every post and page that is:
  • Published, and not password protected
  • Publicly viewable
  • Not marked noindex by Yoast, Rank Math, SEOPress, The SEO Framework or All in One SEO
That last rule matters. If you have told search engines to ignore a page, SnowSEO does not publish a Markdown copy of it either. Drafts, private posts, and anything behind a password are never published as a twin.

Setting it up on other platforms

For Next.js, Astro, Nuxt, SvelteKit, Express, Cloudflare Workers or a custom stack, the SnowSEO SDK does the same job.
1

Install

2

Point it at your content

If your pages come from Markdown files already, point at the folder:
beacon.ts
If they don’t - a React or Vue app, a CMS, anything rendered rather than stored as Markdown - convert the rendered page instead:
beacon.ts
strictNegotiation: false matters on Next.js and other React frameworks.Left on, the SDK answers 406 Not Acceptable when a request’s Accept header names neither HTML nor Markdown. Next sends Accept: text/x-component for every client-side navigation, so strict mode breaks routing across your whole site.
No account or key is needed for Markdown twins. siteUrl is used to build the links between a page and its twin, so it must match the address your site is actually served on.
3

Wire it into your routing

proxy.ts
beaconMiddleware serves the twin when one is asked for. beaconAdvertise adds the header that tells an assistant the twin exists.
The isTwinFetch guard is required when using createFetchResolver.That resolver builds the twin by fetching your own page, so the request re-enters your middleware. Without the guard it calls itself until the request dies. It is not needed with dir, which reads from disk.
4

Decide which paths get twins

Twins make sense for public pages and not for your app. Skip anything behind auth - a twin of a signed-out dashboard shell tells an assistant nothing and advertises a URL that never has content.
If your site has a staging password or similar gate, run that gate first: a twin serves the same content as the page, so handling it earlier would let anyone read protected content by adding .md.

How assistants find your twins

Three routes, so an assistant does not have to know your URL convention in advance. You also get /llms.txt, a single index of every twin on the site, on both WordPress and the SDK. That is the emerging convention for telling AI tools which pages matter, and it is pointed to from your robots.txt so it can be found without guessing.

Twins and Google

Markdown twins are deliberately kept out of search results. Each twin is served with X-Robots-Tag: noindex, follow. Without it, a search engine could index the raw Markdown file and show it in results, and a visitor clicking through would land on a page of unstyled text instead of your real page.
This does not hide twins from AI assistants. An assistant that follows the pointer on your page, or asks for Markdown directly, reads the twin normally. noindex governs search results only.
For the same reason, twins are not listed in the sitemap your site submits to search engines. Submitting pages you have marked noindex produces “Submitted URL marked noindex” errors in Google Search Console, once per page.
The SDK behaves the same way, so twins are held out of search whichever platform you are on.If you would rather have them indexed, set X-Robots-Tag yourself and pair it with a Link: rel="canonical" back to the HTML page, so the two do not compete. Send one or the other, never both: a canonical asks for the twin to be consolidated onto your page, while noindex asks for it to be dropped, and the two directives contradict.

Checking your setup

Run a GEO Audit on your site and open the Machine Readable section. SnowSEO checks the twin end to end: You can also check by hand from a terminal:
A working twin returns 200 with Content-Type: text/markdown; charset=utf-8.

Troubleshooting

Twins are off, or that particular page is not eligible.Check Settings → Reading first. If twins are on, confirm the post is published rather than a draft, is not password protected, and has not been marked noindex by your SEO plugin. A page marked noindex never gets a twin.
Something in front of WordPress is serving a cached HTML copy.Most page caches store one response per address and do not know that Accept: text/markdown should produce a different one. SnowSEO marks Markdown responses as uncacheable, but a CDN configured to ignore those instructions can still override it. Clear the cache and try again; if it persists, exclude .md addresses from your cache rules.
Twins are generated from the current content of the post, so a stale twin is almost always a cache.Clear your page cache, then request the .md address again. If your CDN caches aggressively, purge that address specifically.
Mark it noindex in your SEO plugin. SnowSEO skips it, and the page stays out of both search results and Markdown twins.