All posts
Web design & development

Server-Side Rendering for AI Crawlers: Why Your React Site May Be Invisible

Why a client-rendered React site can look empty to ChatGPT and Perplexity, how to test it with curl, and how SSR or static rendering in Next.js fixes it.

By Mehdi Hassan7 min read

The short answer

SSR for AI crawlers matters because most AI crawlers, including the bots behind ChatGPT, Claude and Perplexity, fetch a page's raw HTML and don't run JavaScript. A client-rendered React site sends a near-empty HTML shell, so those crawlers see no headings, copy or prices. Server-side or static rendering puts the content in the HTML, so every crawler can read and cite it.

Key takeaways

  • Googlebot renders JavaScript; most AI crawlers don't, so a site can rank in Google and be invisible to ChatGPT.
  • Test in a minute: fetch the page with curl and search the HTML for a sentence from the page.
  • Static generation is the right default for marketing pages: fast, cacheable and fully readable.
  • In the Next.js App Router, server components render on the server by default; don't undo it with client fetching.
  • Framer and Webflow publish static HTML, so the risk is mainly custom React and Vite builds.

Part of How to Build an AI-Search-Ready Website: Structure, Schema and Crawlability

Why might a JavaScript-rendered website be invisible to AI crawlers?

A JavaScript-rendered website can be invisible to AI crawlers because those crawlers read the HTML the server sends and stop there. In a client-rendered app, that HTML is an empty container and a script tag; the browser downloads the script, runs it and only then builds the page. A crawler that doesn't run the script sees the container and nothing else.

Google is the exception that hides the problem. Googlebot renders JavaScript in a second pass, so a single-page React marketing site can rank in Google and still be blank to OAI-SearchBot, ClaudeBot and PerplexityBot. Rendering is the first layer of an AI-search-ready website, because no amount of good writing helps if the words aren't in the HTML.

Crawler

Runs JavaScript?

What it sees on a client-rendered page

Googlebot

Yes, in a later rendering pass

The full page, eventually, if scripts and APIs load

Bingbot

Partly, with limits

Often the page, but less reliably than Google

OAI-SearchBot and ChatGPT-User

Generally no

The empty shell and any text in the initial HTML

ClaudeBot and Claude-User

Generally no

The empty shell

PerplexityBot

Generally no

The empty shell

How do you test whether AI crawlers can see your content?

Test by fetching the page the way a non-rendering crawler does and checking whether your content is there. It takes a minute per page and needs no special tools. Test your homepage, one product page, the pricing page and one blog post, since each often uses a different template.

  1. Fetch the raw HTML with curl

    Run curl with the -s flag on the page URL and pipe it to grep with a phrase from the page, such as your hero headline or a price. No match means the text isn't in the HTML.

  2. Try a crawler user agent

    Repeat with the -A flag set to a crawler user agent string, such as one containing GPTBot. Some sites serve bots differently, and some CDNs block them with a 403.

  3. Disable JavaScript in the browser

    In Chrome DevTools, open the command menu, choose Disable JavaScript and reload. A blank or skeleton page is what most AI crawlers get.

  4. Compare view-source with the inspector

    View-source shows the server HTML; the Elements panel shows the page after scripts ran. Text that's only in the second one is client-rendered.

  5. Check the details

    Look at the title tag, meta description, canonical, JSON-LD and FAQ answers in view-source. These are often injected by scripts and missed.

What a failing result usually looks like

In a typical client-rendered app built with Create React App or a default Vite setup, view-source shows a head with a generic title, a body with a single empty div with an id like root, and one or two script tags. Everything a buyer reads, from the headline to the pricing table, is created after the script runs.

A passing result shows the same headings, paragraphs and table rows in view-source that you see on screen. Interactive parts like a pricing toggle can still be JavaScript, as long as the default state is in the HTML.

What's the difference between CSR, SSR and SSG?

They differ in where and when the HTML is built. Client-side rendering builds it in the visitor's browser, server-side rendering builds it on the server for each request, and static site generation builds it once at deploy time and serves the same file to everyone. Only CSR leaves crawlers with an empty page.

Approach

Where HTML is built

AI crawlers see content?

Best for

Client-side rendering (CSR)

In the browser, after JavaScript runs

No

Logged-in app screens

Server-side rendering (SSR)

On the server, per request

Yes

Personalized or fast-changing pages

Static site generation (SSG)

At build or deploy time

Yes

Marketing pages, blog, docs

Incremental static regeneration (ISR)

Statically, refreshed on a schedule or on demand

Yes

Large CMS-driven sites

Prerendering service

A headless browser snapshots pages for bots

Yes, if configured well

A stopgap for an existing SPA

For a marketing site, static generation is usually the right default: pages are fast, cache well and are complete for every crawler. Our comparison of static and server rendering in Next.js goes deeper on when each makes sense.

How do you set up SSR for AI crawlers in Next.js?

In Next.js, the fix is mostly about not fighting the framework. In the App Router, components are server components by default, so a page that fetches its content on the server and renders it ships complete HTML. The problem appears when a page is marked as a client component and loads its content in the browser.

  • Fetch content in server components. Load CMS data in the page component on the server, not in a browser effect after mount.
  • Keep client components small. Mark only interactive pieces, like a menu or a pricing toggle, as client components, and pass them content as props.
  • Pre-build dynamic routes. Use generateStaticParams for blog posts and case studies so each one is built as a static page.
  • Revalidate rather than re-render. Use time-based or on-demand revalidation so CMS edits go live without making every page dynamic.
  • Render metadata and JSON-LD on the server through the metadata API and the page component, so titles and schema are in the HTML.
  • Avoid content behind client-only tabs. If tab content is fetched on click, crawlers never see it. Render all tabs in the HTML and toggle visibility.

The Next.js documentation on rendering covers server and client components in detail. For the wider search picture, our JavaScript SEO guide explains how Google handles rendering.

What if your marketing site is a React SPA?

If your marketing site is a single-page React app, you have three options: move it to a framework that renders on the server, add a prerendering layer, or move the marketing pages to a different platform and keep the app where it is. For most startups, splitting the marketing site from the product app is the cleanest fix.

Pros

  • Rebuilding in Next.js keeps your React components and fixes rendering at the root.
  • Prerendering services can fix crawler visibility quickly without a rebuild.
  • Moving marketing pages to Framer or Webflow gives static HTML and easier editing for marketers.

Cons

  • A rebuild needs redirects and SEO checks so you don't lose existing rankings.
  • Prerendering adds a moving part that can serve stale or broken snapshots to bots.
  • Splitting platforms means two codebases and a shared design system to keep in sync.

Our guide to turning a React SPA into an SEO-friendly website covers the migration path, and if a rebuild is on the table, read about keeping AI Overview and ChatGPT citations through a migration.

Do Framer and Webflow sites have this problem?

Generally no. Framer and Webflow both publish pages as pre-built HTML, so the text, headings and CMS content are in what the server sends. The risks on those platforms are smaller and specific: content loaded by embedded third-party widgets, text inside images, and custom code that fetches data in the browser.

If you use an embed for reviews, pricing or FAQs, check it with the same curl test. Embedded widgets often load in an iframe or by script, which means the content belongs to another domain or doesn't exist in your HTML at all. When the content matters for buyers, put it in the page itself. Then run a full AI visibility audit to check crawler access and structure.

Frequently asked questions

Does Google still have trouble with JavaScript sites?
Google renders JavaScript reliably for most sites, but rendering happens in a later pass, can be delayed and fails if scripts or APIs error or are blocked. Server-rendered HTML removes that risk and gets content indexed sooner. The bigger issue in 2026 is other engines: most AI crawlers don't render at all, so client-rendered content is missing for them entirely.
Is dynamic rendering for bots considered cloaking?
Serving bots a prerendered version of the same content isn't cloaking, as long as the content matches what users see. Google has described dynamic rendering as a workaround rather than a long-term solution and recommends server-side or static rendering instead. Showing bots different content from users is cloaking and can get pages penalized.
Will server-side rendering make my site slower?
Usually the opposite. Static generation serves ready-made HTML from a CDN, which is faster than shipping a large JavaScript bundle that builds the page in the browser. Per-request SSR adds server work, but caching handles most of it. The slowest pattern for visitors is often client-side rendering, because they wait for scripts before seeing any content.
Do I need to rebuild my whole app to fix this?
No. Only the pages you want found need server or static rendering: the homepage, product pages, pricing, comparisons and blog. The logged-in app can stay client-rendered, since crawlers shouldn't index it anyway. Many startups move the marketing pages to a separate Next.js, Framer or Webflow site on the main domain and leave the app untouched.

· CEO & Design Director

Copywriter, designer and developer, and founder of Designify Studio. Over five years, 60+ projects across 14+ industries, for startups that have raised $300M+.

Want this done for you? Website, $8,000.

A multi-page marketing site, written and designed by us, developed in Next.js and animated. $8,000, one-time, up to 6 pages. Book a free 30-minute call to see if it fits.

Schedule Call