AI bots do not execute JavaScript during content indexing. If your website relies on client-side rendering to display content, that content is invisible to every AI engine. This is one of the most common — and most damaging — GEO mistakes. For more on this, see our guide to Page Speed & AI Crawlers: Does It Matter?.
The Problem
Modern web frameworks like React, Vue, and Angular render content in the browser using JavaScript. When a human visits, they see your full page. When an AI crawler visits, it sees an empty shell. Our Core Web Vitals Explained: LCP, INP, and CLS for SEO in 2026 guide covers this in detail.
<!-- What AI crawlers see on a client-rendered page -->
<div id="root"></div>
<script src="/bundle.js"></script>
<!-- No content. Nothing to cite. -->
Which AI Crawlers Are Affected?
Every AI crawler has this limitation:
| Crawler | Executes JS? | Impact |
|---|---|---|
| GPTBot | No | Can’t read client-rendered content |
| ChatGPT-User | No | Browsing mode still can’t execute JS reliably |
| PerplexityBot | No | Completely skips JS-dependent content |
| Google-Extended | No | Despite Google’s JS rendering for SEO, AI uses a separate pipeline |
| ClaudeBot | No | Zero visibility for JS-only pages |
The Fix: Server-Side Rendering
Serve complete HTML from your server. AI crawlers receive fully rendered content without needing JavaScript. As we discuss in The 80-Word Rule: Why Shorter Paragraphs Win AI Citations, this is a critical factor.
Next.js (Recommended)
// Static Generation — best for blog content
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({ slug: post.slug }));
}
// Server-Side Rendering — for dynamic content
export default async function Page() {
const data = await fetchData();
return <Article data={data} />;
}
Astro
Astro renders everything to static HTML by default — zero JavaScript shipped unless you opt in. Ideal for content sites. If you want to go deeper, Content Hub Strategy for Search & AI breaks this down step by step.
Other Frameworks
| Framework | Solution |
|---|---|
| React SPA | Migrate to Next.js or Remix with SSR |
| Vue SPA | Use Nuxt.js with SSR/SSG |
| Angular SPA | Use Angular Universal |
| Svelte SPA | Use SvelteKit with prerendering |
How to Test Your Site
Check if AI crawlers can see your content: (We explore this further in How AI Search is Changing Consumer Behavior in 2026.)
- Disable JavaScript in your browser (DevTools → Settings → Disable JavaScript)
- Reload the page — if content disappears, AI can’t see it either
- Use curl —
curl https://yoursite.com/pageand check if content is in the HTML - View source — Right-click → View Page Source. If content isn’t there, it’s client-rendered
The Data
Analysis of 10 million AI search results confirms: JavaScript-heavy pages receive significantly fewer AI citations regardless of content quality or domain authority. A well-structured static page outperforms a high-authority JS-rendered page every time. This relates closely to what we cover in Free GEO Audit Tools for AI Visibility.
Partial Solutions
If full SSR migration isn’t possible immediately: For more on this, see our guide to Why Every Page Needs an FAQ Section for GEO.
- Pre-render critical pages — Blog posts, product pages, landing pages
- Use hybrid rendering — SSR for content pages, CSR for dashboards
- Implement dynamic rendering — Serve pre-rendered HTML to bot user-agents
FAQ
Does Google’s JavaScript rendering help with AI citations?
No. Google’s rendering pipeline for traditional search is separate from Google AI Overview’s content extraction. Don’t assume Google’s JS rendering covers AI. Our robots.txt for AI Crawlers — Complete Setup Guide guide covers this in detail.
Is static site generation better than SSR for GEO?
Both work well. SSG is faster and more reliable since pages are pre-built. SSR works for dynamic content that changes frequently.
What about hydration — does that cause issues?
No. Hydration adds interactivity after the initial HTML render. AI crawlers receive the pre-rendered HTML and never execute the hydration JavaScript.