Why Client-Side Rendering Is Killing Your AI Visibility
AI crawlers like GPTBot and ClaudeBot don't run JavaScript. If your site is client-side rendered, here's why they see a blank page — and how to fix it.

Here's a true story (names changed). A polished EdTech site — clean Next.js build, fast, beautiful — scored 48/100 on a GEO audit. The killer finding wasn't design or content quality. It was this: when you fetched the raw HTML, every page was nearly empty.
| Page | Raw HTML size | Server <h1> | Server body words |
|---|---|---|---|
| Homepage | 16.2 KB | 0 | ~8 (title only) |
| Topic page | 20.4 KB | 0 | ~12 |
| Blog post | 17.0 KB | 0 | ~9 |
Hundreds of lessons and articles — invisible. Why? Client-side rendering (CSR). If you're new to GEO, start with what GEO is and why it matters, then come back here.
What CSR actually does
With a CSR app (classic create-react-app, or a misconfigured SPA), the server sends a near-empty HTML shell plus a JavaScript bundle. The browser then runs the JS, which builds the page. Humans don't notice — their browser executes the script.
But here's the catch: many AI crawlers don't run JavaScript.
Who can and can't see your JS content
| Crawler | Runs JavaScript? | Sees CSR content? |
|---|---|---|
| Googlebot / Gemini | Yes (renders) | Usually yes |
| GPTBot (ChatGPT) | No | No |
| ClaudeBot (Claude) | No | No |
| CCBot (Common Crawl) | No | No |
| PerplexityBot (fetch mode) | Often no | Often no |
CCBot matters enormously: Common Crawl is a primary training corpus for many models. If CCBot sees an empty shell, your content may never enter the training data that shapes future answers.
So a CSR site is invisible to the biggest AI training and retrieval pipelines. You did all the work; the crawler reads a blank page.
How to check your own site in 10 seconds
curl https://yoursite.com/your-best-page | grep "<h1"
If your main heading and body text don't appear in the output, AI crawlers that don't render JS are seeing nothing. Open the page in a browser with JavaScript disabled for a visual gut-check.
The fix: render on the server
You want the real content in that first HTML response.
- SSR (Server-Side Rendering): the server builds the full HTML per request. Great for dynamic pages.
- SSG (Static Site Generation): pages are pre-built at deploy time. Perfect for blog posts and evergreen lessons — fastest and most crawler-friendly.
- ISR (Incremental Static Regeneration): static pages that refresh on a schedule. Best of both worlds.
In Next.js App Router, Server Components render on the server by default. Use generateStaticParams to pre-build your /blog/* and content routes:
// app/blog/[slug]/page.tsx — a Server Component
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>
{/* Real text in the server HTML — crawlers can read this */}
<div>{post.body}</div>
</article>
);
}
Keep interactivity (quizzes, menus, app UI) client-side — that's fine. Just make sure the citable content — headings, body copy, key facts — ships in the server HTML.
Verify the fix
curl https://yoursite.com/blog/your-post | grep -E "<h1|<h2"
If your headings and paragraphs now appear in the raw response, you've unlocked the highest-leverage GEO win there is. In that EdTech audit, this single fix was projected to add +15–20 points.
Next up: once crawlers can read your pages, you guide them with llms.txt — the new robots.txt for AI.
