A React site loses Google rankings not because of React itself, but because of how it delivers the page to the browser. If the user and the search bot both receive an almost empty HTML shell, and JavaScript builds all the content only after it reaches the browser, the first paint is delayed, and Googlebot pushes full rendering of that page into a queue. What decides the outcome isn’t the framework choice, but the rendering strategy - client-side, server-side, or static.
In site migration projects, Exceltic.dev regularly sees the same picture: the site is built in plain React through Create React App or Vite, with no server-side rendering, PageSpeed shows an LCP above 4 seconds on the mobile test, and some pages stay out of Google’s index for months. Developers almost always blame the framework version, a stale cache, or thin SEO markup, when the real cause usually runs deeper - the rendering model chosen at the very start of the project.
Below is what physically happens in the browser and in Googlebot’s queue when a site is built as an SPA in plain React, why this hits two Core Web Vitals metrics at once, and why the outcome depends not on the framework’s brand but on the rendering architecture - SSR, SSG, or the islands approach.
The pain is rarely visible right away. On a developer’s fast laptop with a warm cache, the site opens instantly. A real visitor on a mobile network sees several seconds of a blank white screen before any content appears - and the search bot sees the same picture, only with an even longer delay.
SPA (single-page application): an architecture where the browser loads one HTML document, and JavaScript on the client side builds all further content and page transitions without a full page reload.
MPA (multi-page application): an architecture where every URL returns a separate, already-complete HTML document from the server, and moving between pages means a full new request to the server.
What the browser sees when a site is a pure React SPA
In a classic CRA-style SPA, the server returns an HTML document that has almost nothing in it - just an empty <div id="root"></div> and a <script> tag pointing to the JS bundle. Content appears only after that bundle goes through four sequential steps: it downloads, parses, executes, and builds the component tree in the browser.
The difference between an SPA server response and an SSR one
<!-- Pure CSR SPA: server response -->
<body>
<div id="root"></div>
<script src="/static/js/bundle.a1b2c3.js"></script>
</body>
<!-- SSR/SSG: the same URL, server response -->
<body>
<div id="root">
<h1>Page title</h1>
<p>Content is already here, before a single line of JS runs</p>
</div>
<script src="/static/js/bundle.a1b2c3.js"></script>
</body>
LCP (Largest Contentful Paint): the moment when the largest content element within the viewport finishes rendering - usually a heading or a hero image. According to web.dev, Google considers an LCP under 2.5 seconds a good result.
In a pure SPA, the LCP element physically cannot render faster than the entire bundle-loading chain finishes. On fast Wi-Fi, this isn’t always obvious. On a 3G-latency mobile network or a budget phone’s weak processor, each of the four steps stretches out, and the total delay before the first paint easily runs past 4-5 seconds.
Why the same architecture hurts INP
INP (Interaction to Next Paint): the metric that replaced FID in March 2024. It measures the time from a user’s click or tap to the moment the browser paints a visible response. The threshold for a good result is under 200 milliseconds.
After the SPA’s content finally renders, the framework still has to attach event handlers to every interactive node - a process called hydration. While it runs, the browser’s main thread is busy, and clicks, scrolling, and animations get queued up. According to independent measurements, hydrating a page with 1,500 React nodes blocks the main thread for 150-300 milliseconds - and that’s before counting the time spent on the first render itself.
On a marketing site with several widgets - a calculator, a chat, a signup form - hydrating each one adds to the total delay. The user sees a button, clicks it, but the handler isn’t attached yet - and Chrome records that as a poor INP.
Why a React site gets indexed slowly in Google
Google processes JavaScript pages in two passes. The first pass happens almost immediately and parses the server’s raw HTML response - links, metadata, and any text that’s already in the markup without running scripts.
The second pass is actual rendering through the Web Rendering Service (WRS), the headless Chromium build Googlebot uses to execute JavaScript. This pass isn’t instant - it enters a queue and waits for rendering resources to free up. According to Google Search Central’s official documentation, rendering can take significantly longer than the initial crawl, and the exact delay depends on the site’s size and its current crawl budget.
The practical consequence: content that appears on the page only after JS runs may get indexed with a delay, or only partially - especially if the domain is new or hasn’t yet built up priority in Googlebot’s eyes. Content that’s already in the raw HTML response takes part in the first pass immediately, with no wait for the rendering queue.
Why this comes down to architecture, not the React brand
Choosing between SPA and MPA means choosing where the HTML actually gets built: only in the user’s browser, or also on the server before the page ever reaches it. Modern approaches don’t force you into one extreme.
Next.js with SSR or SSG solves the problem at the server-response level: HTML with the content already in place, including the LCP element, arrives in the very first response, and React hydration attaches on top of ready-made markup instead of building it from scratch. The difference between these two modes and Server Components is covered in detail in Astro Islands vs Server Components.
Astro with an islands architecture goes further: by default the page ships as static HTML with no JavaScript at all, and React or any other UI framework attaches only to specific interactive islands - a form, a calculator, a chat widget - not to the whole page. A direct comparison of the scenarios where each approach wins is in Next.js vs Astro for a marketing site.
In both cases, React stays part of the stack. What changes isn’t the framework - it’s who builds the first HTML and when: the server ahead of time, or the user’s browser in real time.
A real case - what changes when you move from CSR to SSR or SSG
In a typical project migrating from a pure CSR SPA to Next.js with SSR or to Astro, we usually see LCP drop from 4-5 seconds to 1.5-2.5 seconds on the PageSpeed Insights mobile test - because HTML with the content arrives from the server immediately, with no wait for the bundle to load and execute.
INP doesn’t improve as sharply, since it depends on the number and complexity of interactive elements, not just the rendering method. But time to interactivity usually drops 2-3x, because only the genuinely interactive parts of the page get hydrated instead of the whole thing. A detailed breakdown of optimizing this specific metric is in INP Optimization: The Core Web Vitals Metric Everyone Ignores.
The practical takeaway - it’s not about ditching React
The takeaway from all this isn’t that React is unfit for sites that need to rank well. A React site built on Next.js with SSR or SSG avoids most of the problems described here, while a site built the plain Create React App way doesn’t - even though both are technically written in the same framework.
When choosing or auditing a stack for a site that needs to bring in organic traffic, four things are worth checking:
- What actually arrives in the server response before JS runs - an empty
<div>or ready content. Check this through View Source in the browser or a simplecurlrequest. - Which rendering mode is enabled for the pages that need to be indexed - CSR, SSR, SSG, or ISR.
- How many kilobytes of JavaScript load on a page that doesn’t have a single form or calculator - check the Coverage tab in DevTools.
- Whether the site has pages that never show up in the Google Search Console coverage report weeks after publishing.
If a full rewrite of the site isn’t an option, a partial migration of the pages critical for SEO - the homepage, service pages, the blog - to SSR or SSG usually delivers most of the gain at the first stage, without reworking the entire product.
Who this matters most for
This problem hits hardest for companies building a marketing site or an organic-traffic site on the same codebase as their product’s React application. The engineering team already knows React and naturally reaches for it for the site too, without separating product rendering from public-page rendering.
It also matters for teams that already migrated off WordPress or Tilda to a modern stack, picked React for its flexibility, but didn’t notice that the project template they chose builds a pure CSR SPA with no server-rendering setup at all.
Frequently Asked Questions
Does this mean you need to ditch React for SEO?
No. The problem isn’t React as a library, it’s the rendering mode. Next.js with SSR or SSG, as well as React components inside Astro islands, use the same React, but they deliver ready HTML to the browser and Googlebot in the first server response. Fully client-side rendering with no server build at all is a choice made by the project template, not a property of React itself.
Does simply switching to SSR fully solve the problem?
SSR solves most of the LCP problem, because the content arrives in the first HTML response. It only partly solves INP: if the browser still has to hydrate a large tree of interactive components after getting the HTML, the click-response delay remains. For INP, selective hydration helps further - Suspense boundaries in React 18 or the islands approach in Astro.
Can Googlebot fail to index an SPA site at all?
Completely failing to index it - rarely, Google has been rendering JavaScript for years now. But rendering happens as a second, deferred step, and for low-priority pages or large sites with a limited crawl budget, that delay can stretch into weeks. In that time, a competitor whose first response already contains ready HTML gets indexed and starts ranking.
What’s the difference between SSR and SSG for SEO?
SSG (Static Site Generation) builds HTML ahead of time at build stage, and the server serves the finished file instantly - this is fastest for content that rarely changes: a blog, service pages, landing pages. SSR (Server-Side Rendering) builds HTML fresh on every request - suited to pages with personalization or frequently changing data, but it adds server response time compared to an already-built static file.
What if the site is already a CSR SPA and a full rewrite isn’t possible right now?
A partial migration is usually possible: pages critical for organic traffic - the homepage, services, the blog - move to SSR or SSG first, while the product part of the application can stay a CSR SPA, since it isn’t indexed and doesn’t get cold-search visits anyway. This cuts the scope of work and delivers the effect on the pages that matter most for SEO at the very first stage.
Bottom line
- A React site loses rankings not because of the framework, but because of the rendering mode - pure client-side rendering delays LCP, INP, and Googlebot indexing all at once.
- Googlebot renders JavaScript in two passes, and the second, deferred pass can take anywhere from hours to weeks - content that isn’t in the raw HTML waits its turn in the queue.
- Next.js with SSR/SSG and Astro with an islands architecture solve the problem at the architecture level, keeping React as part of the stack.
- A partial migration of SEO-critical pages to server or static rendering usually delivers most of the gain without rewriting the entire product.
If your site is built as a pure React SPA and you suspect it’s holding back your Google rankings - describe the architecture to the Exceltic.dev team. We’ll go through exactly what arrives in the server response and estimate the scope of work for a move to SSR or SSG.