What AI tools actually read on a web page: a server-log test
I planted six made-up prices on a web page and asked five AI tools about it. Only the two in the page text came back, and the server logs show why.

Key findings
Bottom line: four of five AI tools reported the prices in the page text and nothing else. None of them looked at llms.txt or the Markdown copy, even though three of them read llms.txt when I asked them to open it directly. Perplexity never fetched the page at all.
In this AI crawler test, I planted six made-up prices in six different places on one web page and asked five AI tools what the page charged, three times each, on November 2, 2026. On November 5, I ran a positive control: I asked each tool to open llms.txt and the Markdown copy directly.
- Only prices in the page text came back. In 15 runs across five AI tools, no tool reported a price that appeared only in JSON-LD schema, llms.txt, a Markdown copy of the page, or text added by JavaScript (0 of 15 for each).
- A closed accordion didn't hide anything. ChatGPT, Google AI Mode, Claude and Gemini each reported both page-text prices in all three runs, including the one in a closed accordion (12 of 12 runs).
- The tools could read llms.txt. They just didn't look. No AI agent requested llms.txt or the Markdown copy during the test, even though llms.txt sat at the standard /llms.txt location and the Markdown copy was linked from the page. When I asked directly, ChatGPT, Google AI Mode and Claude each fetched llms.txt and reported its price.
- Perplexity never fetched the page. Perplexity couldn't load the page in any of its three runs, and the server logs show it never sent a request for it, even while its crawler fetched other, linked pages on the same site. In the control, it couldn't open either file.
- Repeat runs didn't fetch again. ChatGPT and Claude each fetched the page once, on the first run, and made no new fetch on the two repeat runs. In the control, a fresh Claude chat with memory off answered correctly without sending a new request.
Results from the November 2 test, plus a positive control on November 5. A dated update will be added here after a week of daily log checks.
The moment that surprised me most: Perplexity told me it had opened a URL directly, and my server logs show it never sent a request for it.
What each AI tool read

| Plan (where it lived) | ChatGPT | Google AI Mode | Claude | Gemini | Perplexity |
|---|---|---|---|---|---|
| Pelican (HTML) | 3/3 | 3/3 | 3/3 | 3/3 | 0/3 |
| Osprey (closed accordion) | 3/3 | 3/3 | 3/3 | 3/3 | 0/3 |
| Heron (JavaScript) | 0/3 | 0/3 | 0/3 | 0/3 | 0/3 |
| Egret (JSON-LD schema) | 0/3 | 0/3 | 0/3 | 0/3 | 0/3 |
| Cormorant (llms.txt) | 0/3 | 0/3 | 0/3 | 0/3 | 0/3 |
| Kittiwake (Markdown copy) | 0/3 | 0/3 | 0/3 | 0/3 | 0/3 |
| Said the page couldn't be loaded | 0/3 | 0/3 | 0/3 | 0/3 | 3/3 |
The two prices in the page text came back every time. ChatGPT, Google AI Mode, Claude and Gemini reported Pelican and Osprey in all 12 of their runs, so hiding a price in a closed accordion made no difference here, as long as the text was in the HTML.
Nothing outside the page text came back, including the schema price, which sat in the HTML but only inside a script tag. Heron, Egret, Cormorant and Kittiwake were each reported in 0 of 15 runs. Claude said outright that it had fetched the "server-rendered HTML."
Every tool that reached the page repeated its note that the prices weren't real, and none of them made up a price for the missing plans.



What the server logs showed
The answers only tell you what a tool said. The access log shows what it actually asked the server for. These are the requests for the test page and its files during the test, not counting my own browser.
| Time (PT, Nov 2) | User agent | Requested | IP check |
|---|---|---|---|
| 10:06:12 pm | ChatGPT-User | Test page, once (run 1 only) | Not verified |
| 10:07:58, 10:13:31, 10:17:48 pm | Google-Lens | Test page | In Google's published user-triggered fetchers range |
| 10:08:40 pm | Claude-User | Test page, once (run 1 only) | Not verified |
| 10:10:44 pm | "Google" | Test page | Google-owned block, but not in Google's published lists, so unverified |
| During the test | Any AI agent | The JavaScript-loaded file, llms.txt or the Markdown copy | No requests |
ChatGPT and Claude each fetched the page once, on the first run. On runs two and three they answered without a new request. The logs can't show where those answers came from. The likeliest explanation is a copy cached from the first fetch, but I can't confirm that. The November 5 control points the same way for Claude: a fresh incognito chat, with no memory, answered correctly with no new request, about 16 minutes after an earlier fetch of the same file.
Google fetched the page live while it wasn't in Google's index. The three Google-Lens requests came from IPs inside Google's published list of user-triggered fetchers, and Google AI Mode's sources panel pointed to the page even though a site: search returned nothing. None of those fetches picked up the JavaScript price.
Nobody but me ever requested the file the JavaScript loaded the Heron price from. No AI agent requested llms.txt or the Markdown copy either. From October 31 until the control on November 5, llms.txt was requested only by SEO tools (Semrush's site audit bot, SEOJuice, Piperic and Keywords Everywhere), a web survey bot, a fetch-cache bot and once by an ordinary Firefox browser on Android.
A user-agent name on its own doesn't prove anything. The morning after the test, a scanner at 35.203.82.17 sent 250 requests in a few minutes, rotating through the ChatGPT-User, Perplexity-User, PerplexityBot and Claude-User names while looking for configuration files and keys. Its IP isn't in Perplexity's published lists. If you count AI bot visits from user agents alone, scanners like this end up in your numbers.
Could they have read llms.txt?
A zero only means something if the tool could have found the price. So on November 5, I asked each tool to open llms.txt and the Markdown copy directly, and checked the access log for each request.
| Tool | llms.txt (Cormorant) | Markdown copy (Kittiwake) | Requests logged |
|---|---|---|---|
| ChatGPT | Reported $53.94 | Said the file had an unsupported content type | Both files |
| Google AI Mode | Reported $53.94 | Said the URL was inaccessible, then reported $29.67 | Both files |
| Claude | Reported $53.94 | Reported $29.67 | Both files |
| Perplexity | Fetch failed | Fetch failed | None |
| Gemini | Error | Error | None |
Three of the four tools that read the test page also read llms.txt when I asked. They just didn't check it when I asked about the page. The file was at the standard location and linked to the test page, and no tool went looking.
The Markdown copy was messier. ChatGPT downloaded the whole file, then said it couldn't use it because of its content type. I served it as text/markdown, which is the official file type for Markdown, and ChatGPT's tool turned it down. A site that serves .md files as plain text might get a different answer. Google AI Mode fetched the file three times and reported the right price while saying the URL was inaccessible, so its own account of what it did was wrong.
Gemini failed on both files, and on the HTML test page it had read correctly on November 2, with no request reaching the server. That looked like a problem on Gemini's side that morning, so I count its control as inconclusive, not as a no.
Why Perplexity couldn't see the page
Perplexity only answered from pages its own crawler had already visited. When I gave it a URL it hadn't crawled, it said the page wouldn't load, and it never sent a request to fetch it.
The site wasn't blocking it. Genuine PerplexityBot, from IPs in Perplexity's published range, visited other pages on the site during the test: at 10:07 pm (the services page and robots.txt), around 10:17 pm, and from 10:38 to 10:39 pm. It never asked for the test page, because nothing linked to it.
Perplexity documents a separate agent, Perplexity-User, that visits pages when a user asks about them. That's the one that should have shown up, and there were no requests from its published IPs all day. To rule out my own site, I also set up a request-logging URL on a separate host (webhook.site), which records every request it gets. Then I asked Perplexity five more ways, each in a fresh thread.
| How I asked | URL | What Perplexity said | Request logged |
|---|---|---|---|
| The bare URL, with no question | Test page | The direct fetch failed | None |
| "What plans are listed at [URL]?" | Test page with a unique query string | Both versions of the URL failed to load | None |
| "What does [URL] say about pricing?" | The site's SEO services page, with a unique query string | Answered with that page's prices | None |
| "Fetch this page live right now and quote its exact text" | Test page with a unique query string | Quoted its tool's error: "Failed to fetch content" | None |
| "What does this page say?" | A unique webhook.site URL | Couldn't retrieve the contents | None, on either host |
None of them produced a request. As a control, I gave ChatGPT the same webhook.site URL, and its request arrived within seconds.
The services page is the telling one. Perplexity's crawler had already visited it, and when I asked Perplexity to open it directly, it said it had opened the URL and answered with the page's content. It did that twice, once with a unique query string added, and no request for that page reached the server either time. It was reading its stored copy.
In these runs, pasting a link didn't make Perplexity read a new page. A page has to be crawled first, which means linked from somewhere PerplexityBot visits. And asking an AI tool whether it read your page isn't a test. Only the logs can tell you that.

Limitations
This is one page on one small site, tested on one evening with a short control three days later, with one account per tool, from Vancouver. ChatGPT was logged out and Perplexity used its default Search mode. The control added AI requests for llms.txt and the Markdown copy to the logs, so the finding that no AI agent asked for them covers October 31 to the morning of November 5. It tests what a tool could read on this page, not how often AI tools cite pages or how common any of this is across the web. The larger studies cover that side, and the results here line up with them: Vercel and MERJ found no JavaScript rendering by the major AI crawlers across their network, Ahrefs found that 97% of the llms.txt files on the 137,000 sites it tracked got no requests in a month, Ahrefs also found no AI citation lift from adding schema, and HasData's AI Crawler Block Index measured how firewalls and robots.txt affect AI crawlers. What this test adds is the request-by-request view from the server.
How to run this test yourself
- Make an unlinked test page with a visible note that it's a test, and plant one made-up fact in each place you want to check (plain HTML, JavaScript, schema, llms.txt, anything else).
- Check the page source and the rendered page, and confirm that robots.txt and your firewall allow the AI user agents.
- Ask each tool the same question in a fresh chat, three times, and save the exact answers and screenshots with timestamps.
- Ask each tool to open each file directly, so you know a zero means it didn't look rather than couldn't read it.
- Pull your raw access logs for the test window and match each request to a run by time.
- Check bot IPs against each company's published range files before you trust a user-agent name.
Methodology
Conrad Studio original research. The main test answers were collected on November 2, 2026, between 10:06 and 10:35 pm Pacific. The positive control ran on November 5, 2026, between 10:33 and 10:56 am Pacific.
Test page
I built a test page on an agency site. The page described a made-up product with six pricing plans, each named after a seabird, and each price lived in a different place.
| Plan | Price | Where the price lived |
|---|---|---|
| Pelican | $47.13 | A plain paragraph in the HTML (the control) |
| Heron | $62.81 | Added to the page by JavaScript from a separate text file, so it wasn't in the page source |
| Osprey | $38.57 | Inside a closed accordion ("More plans"), in the HTML but hidden until clicked |
| Egret | 71.29 USD | JSON-LD Product schema only |
| Cormorant | $53.94 | The site's llms.txt file only |
| Kittiwake | $29.67 | A Markdown copy of the page only, linked from the page as an alternate version |
The llms.txt and Markdown prices were where a tool following those conventions would look. llms.txt was the site's existing file at the standard /llms.txt location, with a new section that linked to the test page and gave the Cormorant price. The Markdown copy sat at the page's address with .md on the end, was linked from the page's head with a link rel="alternate" type="text/markdown" tag, and was served as text/markdown. The Egret price was in the HTML too, but only inside a JSON-LD script tag, not in the page text.
The page carried a visible note saying the prices weren't real and the page was part of an AI crawler experiment. Before running anything, I checked the page source and the rendered page, confirmed that the main AI user agents got a 200 response, and confirmed that robots.txt allowed them. The page wasn't in the sitemap or linked from anywhere else on the site, and it wasn't in Google's index at the time of the test. Not being linked matters for the Perplexity result. Not being indexed matters for Google AI Mode, which fetched the page live anyway.
Question and tools
Each tool got the same prompt in a fresh chat: "What plans does [URL] offer, and how much does each one cost?" I ran it three times per tool, from Vancouver.
- ChatGPT, logged out
- Google AI Mode, signed in
- Claude (claude.ai, Opus 5.5, with web fetch)
- Gemini Pro
- Perplexity Pro, default Search mode
Positive control
On November 5, I gave each tool two prompts, each in a fresh chat: "Open [site]/llms.txt and tell me what plans and prices it lists," and the same for the Markdown copy. I used the same accounts and settings as the main test and matched each answer to the access log by time.
I then re-ran both Claude prompts in incognito chats, which don't use memory or past chats, to rule out answers coming from my account. Gemini returned errors on both files, so I asked it to open the HTML test page it had read on November 2. That failed too.
Answers and logs
I saved each answer's exact text with a checksum, took screenshots at the time, and pulled the raw access logs for each session. Bot IP addresses were checked against each company's published IP range files, where the company publishes one and I could load it.
For the nerds: logs are the raw SSL access log from cPanel. Google-Lens requests came from 66.249.84.138 to .140, inside 66.249.84.128/27 in user-triggered-fetchers-google.json. PerplexityBot requests came from 18.97.9.96 to .103, each listed in perplexitybot.json. ChatGPT-User (9.129.50.35 on November 2; 9.129.50.36 and .46 in the control) and Claude-User (160.79.106.x) weren't checked against published lists, so they're reported as unverified. All checks are against published range files, not reverse DNS.










