For years, sites built on purely client-side JavaScript (Angular or React SPAs with no server rendering) leaned on dynamic rendering — detecting search crawlers at the edge and serving them a pre-rendered static snapshot, while regular users still got the full client-side app.
Two things have made that approach increasingly fragile. First, based on their currently published documentation, the major AI search crawlers don't execute JavaScript — OpenAI's GPTBot, Anthropic's ClaudeBot, and PerplexityBot are documented as not running headless browsers, so a page that depends on client-side execution to populate its content is invisible to them regardless of what Googlebot eventually renders. That's their stated behaviour today, not a permanent guarantee, so it's worth rechecking as these crawlers evolve. Second, Google's own crawling infrastructure applies practical limits to how much it will process per fetch, which matters more as client-side state payloads get larger.
The AI crawler visibility gap
Ranking well now means being visible to both traditional search crawlers and AI answer engines, and they don't behave the same way:
| Crawler | Executes JavaScript? | Indexes CSR-only content? |
|---|---|---|
| Googlebot | Yes, on a delayed second pass | Yes, with a lag |
| Bingbot | Limited / partial | Inconsistent |
| GPTBot (OpenAI) | No | No — frequently missed |
| ClaudeBot (Anthropic) | No | No |
| PerplexityBot | No | No |
Because these agents need to respond quickly, they bypass JavaScript rendering entirely rather than queue a page for a slower rendering pass the way Googlebot does. A page that serves an empty root element on first HTTP response reads as a blank page to them.
Why dynamic rendering is a migration workaround, not an architecture
Dynamic rendering kept legacy SPA sites alive in Google's index, but it carries permanent overhead: a real risk of serving meaningfully different content to bots versus users if the two paths drift out of sync, added latency at the edge from running a headless render on every bot request, and — critically — zero coverage for AI crawlers unless you're maintaining an ever-growing list of bot user-agents and serving them the same prerendered path, which most dynamic-rendering setups were never built to do.
The actual fix
The scalable answer is native server-side rendering — Next.js, Remix, Nuxt, or Astro — where the origin server delivers full body copy, semantic headings, canonical tags, and structured data in the initial HTML response with no client-side execution required to see them. That's the only architecture that's visible to both categories of crawler without maintaining two parallel rendering paths.
Related articles
JavaScript Hydration & SEO: Why 'Rendered HTML' Still Fails Search Engines
"Google renders JS, so it's fine" misses two things: two-wave indexing, and AI crawlers that don't render JS at all. Here's where hydration actually breaks.
React Server Components vs. Traditional SSR: The Technical SEO Comparison
Traditional SSR solves the blank-page problem but still ships a full JS bundle to hydrate. RSC changes that calculation — here's what actually improves.
Optimising INP for Heavy JavaScript Frameworks
INP measures total interaction time, not just when the browser started responding. On heavy JS frameworks, hydration is usually the hidden cost.

Written by
Paul Lovell
International SEO Consultant & Founder of Always Evolving SEO. 15+ years running technical audits, log-file analysis, and root-cause fixes for multimillion-dollar businesses — speaker at SMX London, Search & Content Summit, and SEMrush events.