DEV Community

Cover image for Stop optimizing your site for humans, they don't read it anymore
faikidine
faikidine

Posted on

Stop optimizing your site for humans, they don't read it anymore

I'm a computer science student. I work on side projects, and these days I'm building a small platform to help content creators. And like others before me, I noticed something: what we publish on the Internet isn't really read by humans anymore. It gets read by AIs, digested, then served back to a human as a recap. Since then, I've been optimizing everything I put online for them. Here's why.

Look at Google: ask a question, and the first thing you see is no longer a list of links — it's an "AI Overview" that answers you directly. Most of the time, that's enough: you leave without visiting a single site. The numbers back it up: when an AI Overview shows, only 8% of people still click a result, versus 15% without one (Pew Research, 68,879 real searches). As for me, sometimes I don't even type keywords anymore: I ask full questions, because I know an LLM will answer.

The new visitor doesn't click, it reads

In the human's place arrives a new kind of visitor: the AI agent. ChatGPT, Claude or Perplexity visit the page on their behalf, keep the essentials and hand back a summary. The volume is still modest — around 1% of web traffic (Conductor) — but it's climbing fast (+357% in a year, Similarweb) and it converts hard: 15.9% for traffic coming from ChatGPT, versus 1.76% for Google organic (Seer Interactive). Low volume, huge intent: now is when there's a head start to be had.

LLMO, and what it isn't

The SEO community has a name for this: LLMO, Large Language Model Optimization. In one sentence: SEO optimizes for ranking; LLMO optimizes for meaning, structure, and extractability by AIs.

The key point for developers: an LLM doesn't "browse". It sees neither your hero section, nor your animations, nor your dark mode. It receives text, splits it into tokens, and every token has a cost. Your beautiful interface is, from its point of view: useless noise, billed by the token, stretching the context; zero benefit.

The real cost: tokens

I ran the test on a real page of my own platform — dunga.io/midwiq — with OpenAI's tokenizer. The same information, three representations:

  • Full page (HTML + UI/UX): 1,904 tokens — and nearly 2,900 on the legacy GPT-4 tokenizer
  • Minimal semantic HTML: 521 tokens
  • Clean Markdown: 283 tokens

That's 85% fewer tokens — up to ×10 depending on the tokenizer. Which makes sense: navigation, CSS, JavaScript artifacts… none of it carries any information, but the agent pays for it anyway. Clean Markdown removes all of it.

llms.txt: the obvious fix that isn't

The fashionable answer is called llms.txt: a Markdown file at the root of your site, meant to guide AIs. On paper, appealing. In the data, it doesn't hold up.

SE Ranking (300,000 domains analyzed): no measurable effect on citations — of the 50 domains most cited by AI, only one had the file. Limy: out of 500 million AI bot visits over 90 days, 408 requested llms.txt; bots crawl the HTML directly. And Google has ruled: no support — John Mueller even compared it to the old meta keywords tag.

The problem isn't the intention, it's the architecture: agents don't go looking for a side file, they read the URL you hand them. That's where the right representation needs to be served.

And yet, I have one on my site — and I stand by it, for two reasons. First: when a convention emerges on the web, I'd rather follow it; that's how conventions end up becoming standards. Second: mine isn't trying to get cited, it serves as the README of the machine interface — it's where an agent learns that every page exists as .md, and how to ask for it. Let's be honest: according to the numbers, right now, it does nothing. But it's one static file, zero maintenance — if the standard takes off, we're ready; if it dies, we've lost nothing.

What it looks like in practice (e.g. dunga.io)

That's what I did on dunga.io, the small smart-links platform (fanlinks, link-in-bio, deeplinks) I'm building for creators and artists. A link page is the textbook case: a name, some links, a bio — three useful pieces of information drowned in design.

Every link page exists as a semantic HTML version and a Markdown version, generated on the fly at request time — always up to date, nothing to store. And it's not even the server doing the work: an edge middleware (a few dozen lines running on the CDN, before everything else) looks at the User-Agent. A human gets the design, a social crawler gets its Open Graph card, an AI agent gets the stripped-down version. Same URL, three representations — 100% of the information, ~15% of the tokens. You can see it for yourself: add .md or ?format=md to any public dunga.io page. And the creator didn't have to lift a finger. That's the part I care about: LLMO shouldn't be one more chore for creators — it's a platform's responsibility.

Your turn

I don't know whether the term "LLMO" will survive past 2027. But the gap between a 2,000-token DOM and 300 tokens of Markdown isn't going anywhere. Three simple things to try this week:

  1. Check your logs: filter by AI User-Agent (GPTBot, ClaudeBot, PerplexityBot, OAI-SearchBot) and measure that traffic.
  2. Tokenize one of your pages: run the raw HTML through a tokenizer and compute the useful-tokens / total-tokens ratio.
  3. Serve an alternative representation on the same URL: content negotiation on the User-Agent fits in a few lines of middleware.

And the trap I only discovered by testing with real agents: the Content-Type. Serving text/markdown is clean on paper — except some LLM fetchers refuse any response that isn't HTML. And the reverse is worse: raw Markdown labeled text/html gets flattened by their HTML parser — line breaks swallowed, the whole content on a single line. What ended up working for me: convert the Markdown into minimal semantic HTML (headings, lists, links — zero CSS, zero scripts) served by default, and only return true text/markdown to clients that ask for it (Accept: text/markdown, or an explicit .md in the URL). Two details that go with it: a Vary: User-Agent, Accept header, without which your CDN will eventually serve the robot version to a human; and check that your own anti-bot layer isn't quietly strangling the non-human readers of your public pages — mine was, and I found out late.

Here's the gist:

// middleware.ts — Vercel Edge (same logic on Cloudflare Workers, Nginx, etc.)
const AI_UA = /GPTBot|ChatGPT-User|OAI-SearchBot|ClaudeBot|Claude-User|PerplexityBot|CCBot/i;

export default async function middleware(req: Request) {
  const url = new URL(req.url);
  const wantsMd =
    url.pathname.endsWith(".md") ||
    url.searchParams.get("format") === "md" ||
    /text\/markdown/i.test(req.headers.get("accept") || "");
  const isAgent = AI_UA.test(req.headers.get("user-agent") || "");
  if (!wantsMd && !isAgent) return; // human → the app, as before

  const md = await buildMarkdown(url.pathname); // your content, stripped down
  if (wantsMd) return respond(md, "text/markdown"); // explicit ask: real Markdown
  return respond(mdToMinimalHtml(md), "text/html"); // agents: minimal semantic HTML
}

const respond = (body: string, type: string) =>
  new Response(body, {
    headers: {
      "Content-Type": `${type}; charset=utf-8`,
      Vary: "User-Agent, Accept", // NEVER mix human/robot caches
    },
  });
Enter fullscreen mode Exit fullscreen mode

buildMarkdown and mdToMinimalHtml are the part that depends on your product: the first builds the Markdown from your data (served by your backend, not from your DOM), the second converts it into basic HTML — headings, lists, links, nothing else.

Top comments (0)