In this article
There is a gap between the page you look at and the page your server sends, and answer engines live on the wrong side of it. Everything below was found on this site, by running curl against our own URLs and reading what came back. None of it showed up in a browser, an audit tool or a Lighthouse run, because in every case the page looked perfect.
What an answer engine actually reads#
Google renders JavaScript before indexing. It has for years, which is why a client-rendered page can still rank. That habit is what makes this whole category of bug invisible: the search engine you have been optimising for is the one that papers over it.
Answer engines are a mixed population and many of them do not render. Some fetch the URL and read the response. Some read a cached copy taken by a crawler that did not execute scripts. Some are reading an index built by a third party. You do not control which, and you cannot detect it from analytics.
The safe assumption is the pessimistic one: if it is not in the response body, assume nothing quoted you. That single assumption turns an unknowable problem into a one-line check.
1. The answer that unmounts when closed#
The most common one, and the most expensive. An FAQ accordion that mounts its answer only while the item is open. Closed, the DOM holds the question and nothing else.
So the served HTML of a ten-question FAQ is ten questions and zero answers. A model looking for a passage finds the question it was searching for, attached to nothing, and moves on to a site that answered it.
Ten pages carried an FAQ where the served HTML had every question and not one answer. The schema had them all along, which is why it never showed up as a search problem.
The fix is to collapse rather than unmount. Keep the answer mounted and hide it with max-height and opacity, so it is present for anything reading the page and tidy for the person looking at it. A native details element also keeps its text in the document.
2. Schema describing a page that does not exist#
FAQPage markup is easy to add and easy to forget about, and it drifts the moment the visible copy is edited by anyone who does not know the markup is there.
On our pricing page, the FAQPage described four questions. The number of those four that appeared anywhere on the page was zero. They had been written, marked up, and then replaced in the visible copy by different questions, and nothing connected the two.
That is a mismatch against Google's own requirement that structured data reflect content visible to the user. It is also a wasted move on its own terms, because the engines reading the DOM rather than the markup got nothing from it.
Generate both from one array. If the visible accordion and the schema are built from the same source, they cannot disagree, and a copy edit updates both at once. While you are there, count the FAQPage nodes on the URL: two is a duplicate-entity problem rather than two chances to be read.
3. The number that ships as zero#
An animated counter that rolls up to its value on scroll renders its starting value in the server HTML. Almost always that is zero.
Our homepage ran three of them. A visitor saw the figures count up. A crawler read the page as claiming "0+ leads handed off" and "$0k+ revenue credited back". The only audience that never saw the animation was the one quoting the page.
If a number matters enough to put on the page, render it as text and animate from it rather than to it. If it does not matter that much, the honest move is usually to delete it, which is what we did.
4. Links that only exist after a click#
A dropdown navigation that mounts its panel on open puts none of those links in the server HTML. Most component libraries do this by default, and it is the right call for performance.
It is the wrong call for discovery if the nav is the only place a page is linked from. We had ten pages in that position: in the sitemap, reachable by a human through the menu, and carrying zero crawlable internal links from anywhere on the site.
A page with no internal link is discoverable and unranked. The fix is not to change the nav, it is to make the footer the real link graph and put everything that matters in it, or in a hub page that is itself linked.
5. Answers with no edges#
The first four are technical. This one is editorial and it is the one most sites lose on, because nothing is broken.
A passage gets quoted when it can be lifted out of the page and still make sense. That means it starts with the answer, it is self-contained, and it stops. An answer that depends on the two paragraphs above it cannot be lifted, because the engine will not lift those as well.
The rule we write to: the question goes in an h2, the definition goes in the first sentence under it, and the qualification comes second. Never a build-up. If the passage cannot be pasted into a chat window and still read as an answer, it is not one.
6. The hidden list nobody asked for#
The opposite failure, and rarer, but worth knowing because it is usually introduced by someone doing the right thing.
Our hero had a row of three proof points that rotated through twenty-one phrases. Rotating content is invisible to anything reading the page once, so the full set was added as a screen-reader list to make it accessible. That was the correct instinct and it produced a twenty-one item bulleted inventory in the HTML, sitting where a human reader sees one quiet line.
Anything parsing the page as text got a wall of bullets as the most structurally prominent thing near the top. We kept every word and made it a paragraph instead. Same content for a screen reader, no wall.
The ten-minute audit#
Run these against your own site before you buy anything that promises to measure AI visibility.
Curl your best page
curl -s URL > page.html, then open it in a text editor. Not view-source in a browser, which can show you the rendered DOM. The file is what your server actually sent.
Search for the answer
Pick the one sentence you would most want quoted and search the file for it. If it is absent, nothing else in this list matters until it is present.
Count questions against answers
Count occurrences of your FAQ questions, then of the first six words of each answer. The two numbers should match. When answers come back lower, your accordion is unmounting them.
Diff schema against visible copy
Pull every question out of your FAQPage JSON-LD and check each one appears in the body text. Any that do not are a mismatch with Google's guidelines and invisible to DOM readers.
Grep for your own links
For the ten pages you most want found, grep the homepage HTML for their href. A zero means no crawler reaches that page from your front door.
Look for zeroes that should not be there
Search the HTML for 0+ and $0. Animated counters are the usual source, and they are quoting a number you never intended to publish.
What about llms.txt?#
Worth adding and worth being honest about. It is a community proposal rather than an adopted standard, and no major answer engine has publicly committed to reading it. Anybody selling you an llms.txt strategy is ahead of the evidence.
The case for doing it anyway is modest and real. It costs an afternoon, it does nothing harmful, and writing one forces you to produce a clean index of what your site actually contains, which is a useful exercise whether or not a model ever reads the file. We generate ours from the same source as the site, so it cannot drift.
What it is not is a substitute for the HTML being right. A perfect llms.txt on a site whose answers unmount when closed is a tidy index pointing at pages that have nothing to quote. Fix the six above first. There is more on the measurement side in tracking AI visibility and on the file itself in how to write llms.txt.
Frequently asked
Why is my page not cited by AI when it ranks in search?
Usually because the answer is not in the HTML your server sends. Google renders JavaScript before indexing; many answer engines fetch and read without it, or read a snapshot taken without it. An answer that only exists after hydration, or only after a click, is an answer the model never saw. Run curl against your own URL and search the output for the sentence you expect to be quoted.
How do I check what an answer engine sees on my page?
curl -s https://yoursite.com/page | grep -c "your sentence here". If the count is zero, the sentence is not in the served HTML, whatever the browser shows you. That single command catches most of it: collapsed answers that unmount, client-rendered sections, numbers that animate up from zero, and navigation that only mounts on click.
Does FAQ schema have to match the visible page?
Yes. Google's structured data guidelines require the marked-up content to be visible to the user on the page. FAQPage markup describing questions that appear nowhere is a mismatch, and it is also a wasted opportunity: the engines that read the DOM rather than the markup get nothing. Generate the schema and the visible copy from one source so they cannot drift.
Should FAQ answers be collapsed or expanded?
Either, as long as the text stays in the DOM. Collapse with max-height and opacity rather than unmounting, and the answer is present for anything reading the page while staying tidy for the reader. A native details element also keeps the text in the document. What loses you the citation is rendering only the question until somebody clicks.
How long should a quotable answer be?
Roughly 40 to 80 words, in one paragraph, leading with the definition. Long enough to stand alone when lifted out of the page, short enough to be quoted whole rather than truncated. The failure mode is an answer that only makes sense after the two paragraphs above it, because the engine will not lift those as well.
Do question-shaped headings help AI citation?
They help retrieval, which is the step before citation. A model looking for a passage that answers a question matches a heading carrying that question followed by a direct answer far more readily than a marketing headline followed by a build-up. Put the question in an h2 and the answer in the first sentence under it.
Is llms.txt worth adding?
It is cheap and unproven. The file is a community proposal rather than an adopted standard, and no major answer engine has publicly committed to reading it. The honest case for adding one is that it costs an afternoon, it forces you to write a clean index of what your site actually contains, and it does nothing harmful. Do not expect traffic from it and do not let it substitute for the HTML being right.
Does server-side rendering fix this on its own?
No. Server rendering gets your markup into the response, which is necessary and not sufficient. A server-rendered accordion can still unmount its answers, a server-rendered counter can still print its starting value, and a server-rendered nav can still mount its dropdown on click. Every failure in this article shipped from a server-rendered site.
What is the single highest-value fix?
Make sure every answer you want quoted appears in the served HTML as a complete sentence under a heading that asks the question. That one change covers most of the six failures below, and it is checkable in a minute with curl rather than requiring a tool or a subscription.
Try it on autopilot
Every answer on this site is in the HTML.
We found all six of these on our own pages and fixed them. The comparison pages, the pricing FAQ and the answer layer are all server-rendered, generated from one source, and checkable with the commands above.
Wondering how this differs from SEO? AIO versus SEO.