What GPTBot sees before your React app hydrates | BotScore
Skip to content
Add extension
Navigate
Add extension
Extension
Install BotScore
Pick your browser.<br>Audits run locally | free to start, no account, no tracking.
Blog
What GPTBot sees before your React app hydrates
17 June 2026
Lighthouse scores the hydrated DOM. Many AI crawlers stop at the first HTML response.
You ship a React app. The page loads, the headings show up, Lighthouse gives you a green SEO<br>score. Looks fine.
Now fetch the same URL the way a lot of bots do — no JavaScript, just the first HTTP response.<br>Often you get a shell: , a couple of script tags,<br>maybe a title. The copy your users actually read never appeared in that response.
That split — raw HTML vs Live DOM — is what we call DOM drift.<br>Your app can look perfect in Chrome and still ship an empty document to anything that stops at<br>step one.
Same URL, two documents: hydrated Live DOM vs raw initial HTML.
The empty #root problem
Most SPAs follow the same sequence: minimal HTML, download JS, mount into<br>#root, user sees content. Steps three and four happen after the wire transfer.<br>GPTBot, ClaudeBot, and plenty of other agents fetch the URL, respect<br>robots.txt, and parse what came back — which is often much closer to that first<br>HTML than to the tree you inspect in DevTools.
Crawler behavior is not uniform. Googlebot renders JavaScript for indexing (with limits and<br>delays). Many AI fetchers do not run your bundle at all, or run far less of it. The practical<br>takeaway for a dev shipping a CSR app:<br>if your only exists after hydration, do not assume every agent<br>saw it.
Typical CSR response:
Acme — AI-native analytics
After hydration:
AI-native analytics for product teams<br>Track agent-readability alongside human UX…
Users never notice. Lighthouse might not either — it scores the page once your framework has<br>run. An audit that compares both surfaces will.
You see this on Vite + React SPAs, Vue CLI apps, client-only Next routes. SSR helps, but a<br>client-only wrapper on one route brings the gap back. Analytics look fine, the SEO category<br>passes, and the marketing site still curls to an empty shell.
When to care: pricing tables, docs headings, anything you'd be embarrassed to<br>paste from curl into a ticket. If the proposition lives in JS, it probably isn't<br>in the initial HTML.
Wrong tool for the job
When “SEO” comes up, teams reach for tools they already have. Each one is useful. None of them<br>diff raw HTML against the hydrated DOM.
Tool<br>What it actually tells you
Lighthouse<br>Performance, human a11y, basic meta — on the hydrated page
Cloud GEO dashboards<br>Whether ChatGPT cited your brand this week
Site crawlers<br>Rankings, links, campaigns across the domain
Lighthouse is great at what it does. Ahrefs and Semrush are great at theirs. BotScore checks<br>something else: llms.txt, AI bot robots rules, landmarks, JSON-LD, and whether the HTML that<br>shipped over the wire matches what Chrome shows after your bundle runs.
If you want to know whether ChatGPT mentioned you yesterday, get a monitoring tool. If you<br>want to fix what GPTBot can read on this tab before you merge, you need a local<br>audit that mirrors crawler constraints.
FAQ — How is BotScore different from Lighthouse?
Side-by-side: raw HTML vs Live DOM
BotScore runs in the browser on the active tab. For DOM drift it fetches initial HTML for the<br>same URL and diffs visible text and landmarks against the Live DOM after hydration.
Try it:
Open a CSR-heavy page in Chrome or Firefox.
Open the side panel.
Toggle Raw HTML and Live DOM .
Look for a missing , an empty , body copy that<br>only shows up hydrated.
Check Machine Readability in the breakdown — DOM drift failures land there.
In the split view, ask four questions:
Is there an in raw HTML, or only after JS?
Does exist in the first response, or is everything inside<br>#root with no semantic shell?
Pick a paragraph users can read — same text in the raw panel?
Primary nav links — real in HTML, or injected client-side?
A page can pass three Lighthouse SEO checks and fail all four. That's the point: not another<br>score, a literal diff between what shipped and what Chrome shows.
Toggle Raw HTML and Live DOM in the side panel.
SEM-DOM-DELTA
We encode this as rule SEM-DOM-DELTA:
Fetch initial HTML for the active URL.
Compare visible text and landmarks (h1, main, key regions) to the<br>hydrated DOM.
Fail at ~40%+ client-only text, or when structural landmarks are missing from<br>initial HTML.
Warn at ~15%+.
Fixes depend on your stack: SSR or SSG for headings and body copy, pre-render critical routes at<br>build time, or move / into the shell even if<br>styling still hydrates client-side. SPAs are fine for humans. Agent-readable HTML is a separate<br>deliverable from “works in Chrome after JS runs.”
Discoverability checks that pair with DOM drift
DOM drift is the loud failure on CSR sites. Agent-readability is wider — BotScore runs 27 rules<br>across five categories. A few that show up...