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, affecting an estimated 35-40% of modern websites. 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 — product descriptions, blog articles, pricing tables, everything. 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 -->
<html>
<head><title>Your Amazing Product</title></head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
<!-- No content. Nothing to cite. Zero AI visibility. -->
</body>
</html>
Compare this to what a server-rendered page delivers:
<!-- What AI crawlers see on a server-rendered page -->
<html>
<head><title>Your Amazing Product</title></head>
<body>
<article>
<h1>Your Amazing Product: Complete Guide</h1>
<p>Your Amazing Product is a cloud-based platform that...</p>
<h2>Key Features</h2>
<ul>
<li>Feature one: description with specifics...</li>
<li>Feature two: description with specifics...</li>
</ul>
<!-- Full, citable content available immediately -->
</article>
</body>
</html>
The difference is stark. The first page has nothing for AI to process. The second page has rich, structured content that AI engines can immediately index, evaluate, and cite.
Why AI Crawlers Don’t Execute JavaScript
Understanding why AI crawlers skip JavaScript helps explain why this isn’t changing anytime soon:
Computational Cost
Executing JavaScript requires spinning up a full browser environment (headless Chrome or similar) for every page. At the scale AI engines operate — crawling billions of pages — this would multiply infrastructure costs by 10-50x. Google spent years and enormous resources building their JavaScript rendering pipeline for traditional search, and even they process AI content through a separate, lighter pipeline.
Latency
JavaScript rendering adds 2-10 seconds per page. When you’re crawling millions of pages per hour, that latency makes JavaScript execution impractical. AI crawlers prioritize speed and breadth — they’d rather crawl 100 static pages in the time it takes to render 1 JavaScript page.
Reliability
JavaScript rendering is fragile. Pages can fail to render due to API errors, authentication requirements, CORS issues, rate limiting, and countless other reasons. Static HTML is deterministic — the crawler always gets the same content. AI engines prefer reliable data sources.
State and Authentication
Many JavaScript applications require authentication, session cookies, or specific state to render correctly. AI crawlers don’t log in, don’t maintain sessions, and can’t interact with login forms. Any content behind authentication is invisible.
Which AI Crawlers Are Affected?
Every AI crawler has this limitation — no exceptions:
| 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 |
| Amazonbot | No | No JS execution capability |
| Applebot-Extended | No | Apple Intelligence can’t process JS content |
| Meta-ExternalAgent | No | Meta AI skips JS-rendered pages |
Important clarification about Google: Many developers assume that because Google can render JavaScript for traditional search indexing, their JavaScript content is also visible to Google AI Overview. This is incorrect. Google-Extended (the AI crawler) operates on a different pipeline than Googlebot. Your React SPA might rank in Google Search but be completely invisible to Google AI Overview.
The Scope of the Problem
Analysis of 10 million AI search results confirms: JavaScript-heavy pages receive significantly fewer AI citations regardless of content quality or domain authority. The numbers are striking:
- Pages with 90%+ content in JS: 0.3 average AI citations per page
- Pages with server-rendered HTML: 4.7 average AI citations per page
- Hybrid pages (partial SSR): 2.1 average AI citations per page
That’s a 15x citation gap between pure client-rendered and server-rendered pages. For enterprise sites with thousands of JavaScript-rendered pages, this represents an enormous missed opportunity in AI visibility.
Industries Most Affected
Some industries are disproportionately impacted because they heavily adopted JavaScript frameworks:
- SaaS products — Marketing sites built with React/Next.js (often client-rendered)
- E-commerce — Product catalogs rendered via JavaScript with dynamic filtering
- Media/publishing — Content management systems with JS-heavy front ends
- Financial services — Data dashboards and tools that render dynamically
- Real estate — Property listings loaded via API calls and JS rendering
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 for React)
Next.js offers multiple rendering strategies. For GEO, you want either Static Site Generation (SSG) or Server-Side Rendering (SSR):
// Static Generation — best for blog content, docs, marketing pages
// Pages are pre-built at build time as static HTML
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function BlogPost({ params }) {
const post = await getPost(params.slug);
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// Server-Side Rendering — for dynamic content that changes frequently
// Pages are rendered on each request
export const dynamic = 'force-dynamic';
export default async function ProductPage({ params }) {
const product = await fetchProduct(params.id);
return (
<article>
<h1>{product.name}</h1>
<p>{product.description}</p>
<table>
<tr><td>Price</td><td>${product.price}/month</td></tr>
<tr><td>Features</td><td>{product.features.join(', ')}</td></tr>
</table>
</article>
);
}
Astro
Astro renders everything to static HTML by default — zero JavaScript shipped unless you opt in. This makes it ideal for content sites focused on AI visibility. If you want to go deeper, Content Hub Strategy for Search & AI breaks this down step by step.
---
// Astro component — renders to pure HTML
const posts = await getCollection('blog');
---
<html>
<body>
<main>
{posts.map(post => (
<article>
<h2>{post.data.title}</h2>
<p>{post.data.description}</p>
</article>
))}
</main>
</body>
</html>
Astro’s “islands” architecture lets you add JavaScript interactivity only where needed (search bars, interactive widgets) while keeping the core content as static HTML. This gives you the best of both worlds.
Other Frameworks
| Framework | Solution | Migration Effort |
|---|---|---|
| React SPA | Migrate to Next.js or Remix with SSR | Medium-High |
| Vue SPA | Use Nuxt.js with SSR/SSG | Medium |
| Angular SPA | Use Angular Universal | High |
| Svelte SPA | Use SvelteKit with prerendering | Low-Medium |
| jQuery/vanilla JS | Already server-rendered — just verify | Low |
| WordPress | Usually server-rendered — check theme | Low |
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.)
Method 1: Disable JavaScript in Browser
- Open Chrome DevTools (F12)
- Press Ctrl+Shift+P → type “Disable JavaScript” → click it
- Reload the page
- If content disappears, AI can’t see it
Method 2: curl Test
# Fetch your page as an AI crawler would see it
curl -s https://yoursite.com/page | grep -c '<p>'
# If the count is 0 or very low, your content is JS-rendered
# Compare with a known static page for reference
Method 3: View Page Source
Right-click → View Page Source (not Inspect Element). View Source shows the raw HTML delivered by the server. Inspect Element shows the DOM after JavaScript execution. If your content appears in Inspect but not in View Source, it’s client-rendered.
Method 4: Google’s Rich Results Test
Use Google’s Rich Results Test (search.google.com/test/rich-results) to see both the raw HTML and rendered HTML. Compare them — if content only appears in the rendered version, you have a JavaScript problem.
Method 5: Automated Crawl Audit
# Use Screaming Frog or similar with JavaScript rendering disabled
# Compare crawl results with and without JS
# Pages with significant content differences need SSR
Partial Solutions
If full SSR migration isn’t possible immediately, these intermediate steps can help: For more on this, see our guide to Why Every Page Needs an FAQ Section for GEO.
Pre-render Critical Pages
Identify your most important pages for AI visibility and pre-render only those. Prioritize:
- Homepage and main landing pages
- Blog posts and articles
- Product/service pages
- Pricing pages
- FAQ and help documentation
Hybrid Rendering
Use SSR for content-facing pages and keep CSR for application pages:
- SSR: Blog, docs, marketing, pricing, about → AI needs to see these
- CSR: Dashboards, admin panels, user settings → AI doesn’t need these
Dynamic Rendering
Serve pre-rendered HTML to bot user-agents while serving the JavaScript version to browsers:
# Nginx configuration for dynamic rendering
map $http_user_agent $is_bot {
default 0;
~*(GPTBot|ChatGPT-User|PerplexityBot|ClaudeBot|Google-Extended) 1;
}
server {
location / {
if ($is_bot) {
proxy_pass http://prerender-service;
}
proxy_pass http://app-server;
}
}
Caution: Google has historically discouraged cloaking (showing different content to bots vs users). However, dynamic rendering that serves the same content in different formats (pre-rendered HTML vs client-rendered JS) is generally accepted. The key is ensuring the content is identical — you’re changing the delivery method, not the content.
Progressive Enhancement
Build your pages with core content in HTML, then enhance with JavaScript:
<!-- Core content visible without JS -->
<article>
<h1>Product Comparison</h1>
<table>
<tr><th>Feature</th><th>Product A</th><th>Product B</th></tr>
<tr><td>Price</td><td>$29/mo</td><td>$49/mo</td></tr>
</table>
</article>
<!-- JavaScript adds interactivity -->
<script>
// Add sorting, filtering, dynamic updates
// But core content is already in the HTML
</script>
Common Pitfalls
Lazy Loading Content
Content loaded via lazy loading (Intersection Observer) is invisible to AI crawlers because they don’t scroll. Ensure your primary content is in the initial HTML, and only lazy-load supplementary elements like images and below-the-fold widgets.
API-Dependent Content
Pages that fetch content from APIs on the client side are completely empty for crawlers. If your product descriptions come from a CMS API call in React, that content doesn’t exist for AI engines. Fetch it server-side instead.
Single-Page Application Routing
SPAs with client-side routing (React Router, Vue Router) serve the same HTML shell for every URL. AI crawlers visiting /blog/my-post and /pricing both get the same empty <div id="root"></div>. Each URL needs to return its specific content server-side.
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. The AI content pipeline uses a lighter, faster crawler that processes raw HTML only. 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 for AI visibility since both deliver complete HTML. SSG is faster and more reliable since pages are pre-built at deploy time — there’s zero server processing per request. SSR works better for frequently changing content (pricing, inventory, personalized pages). For most content sites, SSG is the optimal choice.
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. The key is that the meaningful content is in the initial HTML response, not added during hydration.
How long does SSR migration typically take?
For a typical content site (50-200 pages), migrating from a React SPA to Next.js with SSG takes 2-6 weeks depending on complexity. The content itself doesn’t change — you’re changing how it’s delivered. For most teams, this is one of the highest-ROI technical investments for AI visibility.
Can I use a pre-rendering service instead of migrating?
Yes. Services like Prerender.io or Rendertron can serve pre-rendered HTML to bot user-agents as an interim solution. This buys you time while planning a full SSR migration. However, pre-rendering services add latency, cost, and a point of failure — they’re a bridge, not a destination.