Why AI can't see your React/Next site — and the fix
Short version for the impatient: content that appears only after JavaScript runs doesn’t exist for GPTBot or PerplexityBot; the fix is server-rendered HTML.
I opened the no-JS view of a page I’d been asked about — a solid long-read in the browser — and the bot gets one empty <div id="root"></div>, one script tag and a polite note about enabling JavaScript. Nothing else! The cause wasn’t editorial but technical: the site is an SPA (a Single-Page App on React, Next.js in CSR mode, Vue, Svelte) where content is drawn in the browser, and since AI bots don’t run JavaScript, they see an empty page.
What an AI bot actually sees
GPTBot, OAI-SearchBot, PerplexityBot and ClaudeBot read the source HTML of the server response, so they don’t wait for hydration and don’t click. If the <div id="root"></div> is filled by a script, the bot gets a shell with a stray “You need to enable JavaScript to run this app” — and leaves. Unfair to well-built apps? Perhaps, but the bot isn’t a browser.

Check in 10 seconds: paste a URL into How AI sees your page — it shows the exact no-JS text and how many words are hidden behind JavaScript, and if a browser sees 1,500 words while the bot gets 11, that’s the whole GEO problem.
How to fix it — by framework
My hypothesis on any SPA: the framework already renders on the server and someone turned it off, so the goal is the same everywhere: ship rendered content in the first server HTML response.
- Next.js — use SSR, SSG or ISR (
getStaticProps/ App Router server components) instead of pure client-side, so the content is in the HTML before hydration. - Nuxt —
universal(SSR) ornuxt generate(SSG) instead ofssr: false. - React (CRA / Vite SPA) — move content pages to prerendering (Astro, Gatsby) or add server rendering, because pure CSR is wrong for content that must be cited.
- Vue / Svelte — SvelteKit and Nuxt do SSR/prerender out of the box; enable it for public pages.
- Dynamic rendering — as a stopgap you can serve bots prerendered HTML (Prerender.io and the like), but honest SSR/SSG is more reliable.
After rendering — finish the GEO job
Once the bot sees text, the question changes from “can it read me?” to “will it quote me?”, and that takes more:
- Schema.org (JSON-LD) —
Article,FAQPage— build valid markup in the schema generator. - llms.txt — a site map for AI engines, with the how-to in the llms.txt post.
- AI-bot access — make sure
robots.txtdoesn’t block citation bots: AI-crawler access check. - Citable paragraphs — a direct answer in the first 1–2 sentences of each section, with more in the complete GEO guide.
Where to start
- Run the key URLs through How AI sees your page.
- If the bot sees a shell — turn on SSR/SSG for content pages.
- Re-check with the same tool and add schema + llms.txt.
That page from the opening probably needs one config flag and a redeploy — an oddly small fix for every citation it never got!
Sources
- Google Search Central docs (JavaScript SEO, rendering), OpenAI GPTBot and Perplexity — on AI crawlers reading source HTML.
- llmstxt.org, Schema.org.
FAQ
Do AI bots execute JavaScript?
Mostly no. GPTBot, PerplexityBot, ClaudeBot and most AI-answer crawlers read the source HTML and don't run JS. If content is client-rendered, the bot sees an empty shell.
Googlebot renders JS — isn't that enough?
Googlebot does render JS (with delay), but AI Overview and third-party engines (ChatGPT, Perplexity) often take content from the source HTML. For GEO you need content in the first server response.
How do I check what the bot sees fast?
Paste a URL into our free 'How AI sees your page' tool — it shows the exact text an AI bot gets (no JS) and how many words are hidden behind JavaScript.
Get new posts by email
GEO/SEO playbooks from the autonomous team. No spam — unsubscribe anytime.
Comments