--- title: "React SEO: Making Client-Rendered Apps Crawlable" description: "React SEO guide: why client-side rendering hurts crawlability and how SSR, SSG, frameworks, and metadata fix it so search and AI crawlers can index you." author: "Alec Lindsay" date: "2026-06-23" tags: "React SEO, SEO for Developers, Technical SEO" url: "https://seoagent.com/blog/react-seo" --- # React SEO: Making Client-Rendered Apps Crawlable **TL;DR —** A default client-rendered React app serves nearly empty HTML and builds the page in the browser, which means search engines and AI crawlers can see a blank shell. The fix is to render meaningful HTML on the server — via SSR, SSG, or a framework that does it for you — plus real metadata and structured data. - **The problem:** client-side rendering (CSR) hands crawlers an empty `
` and a JavaScript bundle. - **The fix:** server-render or pre-render your content with Next.js, Remix, or Astro, and set per-page metadata. - **The catch:** Googlebot renders JavaScript (slowly); most AI crawlers don't run it at all. If you build with React and care about organic and AI search, this is one of the highest-leverage technical issues to get right. It's a core piece of [SEO for developers](/blog/seo-for-developers) — the kind of problem that's invisible in the browser but decides whether you ever get indexed. ## The core React SEO problem Open the page source of a plain Create React App or Vite single-page app and you'll find something like this: ```html
``` That's it. No headline, no copy, no links — just an empty container and a script tag. Your content only exists *after* the browser downloads the bundle, executes it, fetches data, and React paints the DOM. This is **client-side rendering**: the server sends a near-empty document and the client does all the work. A human with a fast device barely notices. A crawler is a different story. **Search engines.** Googlebot can render JavaScript, but it does so in a deferred, two-wave process: it crawls the raw HTML first, then queues the page for rendering when resources free up. That render can lag hours or days behind, and anything that breaks — a slow API, a JS error, a blocked script — can leave your content unseen. Bing and most other engines render JavaScript far less reliably, if at all. **AI crawlers.** This is the sharper edge in 2026. The bots behind AI answers — GPTBot, ClaudeBot, PerplexityBot, Google-Extended — overwhelmingly fetch raw HTML and **don't execute JavaScript**. If your content isn't in the initial HTML response, it effectively doesn't exist to them. As more discovery shifts to AI assistants, a CSR-only app risks being invisible exactly where attention is moving. So the failure mode is simple: **your content is real, but the machines that decide visibility never see it.** ## Why it matters Three concrete consequences follow from shipping empty initial HTML: - **Delayed or skipped indexing.** Pages that depend on a second render wave get indexed later, or get dropped when rendering fails. - **Weak or missing snippets.** Without server-rendered `` and meta description, your search result can show a generic or empty snippet. - **Zero AI citations.** If ClaudeBot or GPTBot can't read your page, you can't be summarized or cited in an AI answer. For a marketing site, docs, or blog, this is the whole game. Crawlability isn't a nice-to-have — it's the precondition for everything else you do in SEO. ## The fixes, step by step The goal is the same in every case: make sure the crawler receives **meaningful HTML in the first response.** Here are the approaches, roughly in order of how most teams should reach for them. ### 1. Choose a rendering strategy These are the three core strategies and how they affect crawlability: | Strategy | When HTML is built | Crawler sees content | Best for | | --- | --- | --- | --- | | **CSR** (client-side) | In the browser, after JS runs | Only if the bot executes JS | App-like dashboards behind auth | | **SSR** (server-side) | On each request, on the server | Yes, immediately | Dynamic, frequently changing pages | | **SSG** (static generation) | Once, at build time | Yes, immediately | Blogs, docs, marketing pages | CSR is fine for the logged-in parts of a product no one needs to find in search. For anything you want crawled, you want SSR or SSG so the HTML arrives populated. ### 2. Reach for a framework You can wire up SSR by hand with `renderToString`, but in practice almost no one should. A React meta-framework gives you server rendering, routing, and metadata handling out of the box: - **Next.js** — the default choice for most React teams. The App Router server-renders by default; you opt into client behavior with `'use client'`. Supports SSR, SSG, and incremental static regeneration in one app. - **Remix / React Router** — server-rendering-first, with a strong data-loading model that keeps content in the initial HTML. - **Astro** — ships zero JavaScript by default and renders components to static HTML, with React "islands" only where you need interactivity. Excellent for content-heavy sites. If you're starting a new content or marketing site in React, pick one of these rather than a bare SPA. It removes the entire class of problem this article is about. If you're on [Vercel](/vercel), Next.js is the path of least resistance. ### 3. Pre-render an existing SPA (the stopgap) Already shipped a client-rendered app and can't migrate yet? You have intermediate options: - **Static prerendering at build time** — tools that crawl your routes during the build and save a fully rendered HTML snapshot per page. Good for sites with a finite, mostly static set of URLs. - **Dynamic rendering** — detect crawler user-agents and serve them a server-rendered or pre-rendered version while users get the SPA. Google treats this as a legitimate workaround, but it's a maintenance burden and a stopgap, not a destination. Prefer real SSR/SSG when you can. ### 4. Set real metadata per page Server-rendered HTML is necessary but not sufficient — each page still needs its own `<title>`, meta description, canonical, and Open Graph tags in that initial response. - **In a framework:** use the built-in head/metadata API (Next.js `metadata` export or `generateMetadata`, Remix `meta`, Astro frontmatter). These render the tags on the server, where crawlers will see them. - **In a plain SPA:** a library like `react-helmet-async` manages document head tags — but remember it only helps crawlers if those tags exist in server-rendered or pre-rendered HTML, not just after hydration. Per-page metadata is what turns a crawlable page into a good search result. ### 5. Add structured data Structured data (JSON-LD) helps both search engines and AI crawlers understand what a page *is* — an article, a product, an FAQ. Inject a `<script type="application/ld+json">` block, server-side, matching the page type (`Article`, `Product`, `FAQPage`, `BreadcrumbList`). Because it's plain text in the HTML, even JS-free AI crawlers can parse it, which makes it disproportionately valuable for AI search. ## Common mistakes 1. **Assuming "Googlebot renders JS" means you're fine.** It renders eventually and unreliably, and most other crawlers — including the AI ones — don't render at all. Don't lean on it. 2. **Hydration that overwrites server HTML.** A mismatch between server and client markup can blank out content or throw errors; keep the server and client trees identical. 3. **Metadata set only on the client.** If `react-helmet` runs after hydration, crawlers reading raw HTML never see your title or description. The tags must be in the server response. 4. **Blocking your own JS/CSS in `robots.txt`.** If Googlebot can't fetch the bundle, its render wave fails. Don't disallow `/static/` or `/_next/`. 5. **Treating dynamic rendering as permanent.** It's a bridge while you migrate to SSR/SSG, not the finish line. ## Frequently asked questions ### Is React bad for SEO? No — React itself is neutral. The problem is *client-side rendering*, which is React's default in a bare SPA. Render your content on the server with SSR or SSG and React is perfectly SEO-friendly. ### Does Google index client-side React apps? Sometimes, and slowly. Googlebot can execute JavaScript in a deferred second wave, so CSR pages *can* get indexed — but with delays and a real risk of failure. Server-rendered HTML is indexed immediately and reliably. ### Do I have to use Next.js for React SEO? No, but a meta-framework makes it dramatically easier. Next.js, Remix, and Astro all produce crawlable HTML out of the box. You *can* hand-roll SSR or prerender a SPA, but a framework removes most of the work and the footguns. ### Will AI search engines like ChatGPT see my React site? Only if your content is in the raw HTML. Crawlers like GPTBot and ClaudeBot generally don't run JavaScript, so a CSR-only app is invisible to them. SSR/SSG plus structured data is what gets you readable and citable. ### How do I check if my React app is crawlable? View the page source (not the rendered DOM) or fetch the URL with `curl` — if your content and metadata aren't in that response, crawlers may not see them. You can also check how your site reads to AI assistants with an [AI-readiness checker](/okf-checker), and lean on tools like [SEOAgent](/blog/seo-agent) to catch missing metadata and structured data as you build. ## Conclusion React's SEO problem isn't React — it's shipping an empty HTML shell and trusting machines to fill it in. Search engines do that unreliably; AI crawlers usually don't do it at all. Render your content on the server with SSR or SSG, set real per-page metadata, and add structured data, and you turn an invisible SPA into a page that gets indexed and cited. If you want a deeper map of how crawlability, performance, and metadata fit together, start with [SEO for developers](/blog/seo-for-developers) — and if your site lives in a codebase, an SEO engine that works alongside your coding agent can keep these fixes in place as the app evolves. For more on the broader landscape, see our roundup of the best [AI SEO tools](/blog/ai-seo-tools).