Skip to content
SEO

React SEO: How to Rank a React App

A React app stays invisible to search until it renders on the server, gives each route its own metadata, and links pages with real anchor tags.

By Ibrahem HelalAI-assisted, reviewed by Jeremy Zava6 min read

A React app ranks when its HTML exists before a crawler runs any JavaScript, each route carries its own title, description and canonical tag, and internal links use real anchor tags instead of onClick handlers. Client-side rendering alone leaves crawlers an empty shell, then makes them wait for a render that may never come.

That is one piece of the broader WordPress SEO picture — the guide is written around WordPress, but the indexing and rendering rules apply just as much when the front end is a hand-built React app instead of a CMS theme.

On this page

Why does client-side rendering hurt React SEO?

Because the first response a crawler gets is close to empty. A default Create React App or Vite build ships a single <div id="root"></div> and a JavaScript bundle; everything a visitor reads gets injected after that script runs [3].

Google's own crawler can execute JavaScript and usually will, but it does so in a second pass, on its own schedule, and not every system that reads your pages does the same [2]. Social share previews, some AI crawlers and most SEO auditing tools read the first response only. If your content is not in that response, it does not exist to them.

This is not a React-specific flaw — Vue and Angular apps have the identical problem — but React's popularity for marketing and content sites is why it comes up constantly. The fix is not to abandon React. It is to stop asking the browser to build your first HTML from nothing.

How do you render a React app so crawlers can read it?

You move the first render to the server or to build time, so the HTML that answers the very first request already contains your content. There are three ways to do this, and they trade off differently.

Rendering strategies for a React app, and what each one costs you
StrategyWhat a crawler sees firstCost
Client-side rendering (CSR)Empty shell, content arrives after JS runsSimplest to build, worst for SEO
Server-side rendering (SSR)Full HTML, rendered fresh per requestNeeds a Node server or edge runtime
Static generation (SSG)Full HTML, built ahead of timeFastest to serve, rebuild needed on content change
Prerendering / hybridFull HTML for crawlers, CSR for users after loadA patch on an existing CSR app, not a rebuild

Server rendering and static generation both solve the actual problem: real content in the first response [1]. A prerendering service that only serves rendered HTML to known bot user agents is a legitimate stopgap on an app you cannot fully rebuild yet, but it is one more moving part to keep in sync, and it fails quietly if a crawler's user agent changes.

If you are choosing a framework rather than retrofitting one, React alone does not render on the server. You need React plus a framework that does — Next.js is the common choice, and our migration guide covers what that move looks like coming from a CMS.

What does every route need in its <head>?

A title, a meta description, and a canonical tag, set per route rather than once in index.html. A single-page app usually starts with one static <head> for every URL, which means every page shares the same title and description — effectively invisible to search from day one.

  1. Set the title and description per route

    Whatever renders your `<head>`, tie it to the current route's data, not a hardcoded value in your HTML template.

  2. Add a canonical tag on every route

    Especially where the same content is reachable at more than one URL — with and without a trailing slash, or through a filter parameter.

  3. Render structured data server-side where it applies

    Product, article or FAQ schema is only useful to a crawler if it is present in the first HTML response, same as the content itself.

  4. Confirm the tags actually change between routes

    View source on two different pages and diff the `<head>` blocks. If they are identical, your routing isn't reaching your metadata logic.

How do you avoid duplicate and orphaned URLs in a single-page app?

By using real routes with real paths, and by linking between them with anchor tags. A router that maps clean, unique paths to each view avoids the duplicate-content problem outright — the harder mistake is usually in how pages link to each other, not how they're addressed.

A <button onClick={...}> that changes the view without changing the URL, or without using an <a href> under the hood, is invisible to a crawler that only follows real links. It also means that page can never be shared, bookmarked or ranked on its own, because from the outside it does not have a URL.

How fast does a React app need to load?

Fast enough that Core Web Vitals pass on a real mid-range phone, not just on your laptop. A large JavaScript bundle that has to download, parse and execute before anything is interactive is the most common way a React app fails on speed, independent of whether it also has a rendering problem.

Code-splitting by route, so a visitor only downloads the JavaScript the current page needs, is the single highest-leverage fix on most React apps. Image sizing and font loading matter too, but they matter on every site; the bundle is the part that is particular to a JavaScript-heavy front end.

Do you need a full framework, or can you retrofit an existing app?

It depends on how much of the app is public-facing. If most of your traffic lands on marketing and content pages, moving those specific routes onto a framework with server rendering, and leaving an authenticated dashboard as plain client-side React, is usually less work than rebuilding everything.

A full migration to Next.js or Remix makes sense when the whole site needs to be crawlable, or when the team is already maintaining two different rendering setups and the complexity itself has become the cost. Either way, the fix is architectural, not cosmetic — a meta tag library alone will not make an empty page render its content.

Budget for this honestly. A hybrid setup, where marketing routes render server-side and the authenticated app stays client-side React, is usually a few weeks of work for a mid-sized site: new build tooling, a hosting change if you were serving static files only, and testing that nothing in the authenticated app assumed a client-only render. A full framework migration is closer to a rebuild, and it touches routing, data fetching and deployment all at once, so treat it as its own project rather than a task inside a sprint.

There is a middle option worth naming: keep the existing React app exactly as it is and put a reverse proxy in front of it that serves a prerendered snapshot to known crawler user agents while everyone else still gets the client-rendered app. It buys time on a large legacy codebase, and it is genuinely fine as a permanent answer for a site that cannot justify a rebuild. Just monitor it — a proxy rule that silently stops matching a crawler's user agent after a change on either side fails invisibly, and nobody notices until traffic has already dropped.

How do you know if Google can actually see your content?

Fetch the URL the way a crawler does, with no JavaScript execution, and read what comes back. A plain curl request or a browser's "view source" (not "inspect element," which shows the post-JavaScript DOM) shows you the real first response.

If your product name, price or article text is missing from that raw HTML, a large share of what reads your pages is missing it too. This is the fastest possible test, it costs nothing, and it tells you in thirty seconds whether the rest of this page even applies to your site.

Every React SEO problem I've diagnosed started with the same step: fetch the page without JavaScript and see what's actually there. It settles the argument about whether rendering is the issue before we spend a day on anything else.
Ibrahem HelalCo-founder, RankPearl

If your CMS is headless rather than a custom React build, headless CMS SEO covers the content and delivery side of the same problem, and HubSpot's CMS is worth a look if you want rendering handled for you rather than owned by your team.

Questions people also ask

  • Does React hurt SEO by default?

    A plain client-side React app can, because the initial HTML is nearly empty until JavaScript runs. It is fixable with server rendering or prerendering; the framework itself is not the problem.

  • Do I need Next.js for React SEO?

    No, but you need something that renders HTML on the server or at build time. Next.js, Remix and similar frameworks do this for you; without one, you build and maintain that layer yourself.

  • Is client-side rendering ever fine for SEO?

    Yes, for pages nobody needs to find through search: logged-in dashboards, internal tools, checkout flows past the product page. Anything meant to rank needs HTML that exists before a script runs.

  • How do I check if Google can actually see my React content?

    Fetch the page with a plain HTTP request and no JavaScript, the way a crawler first sees it, and read the raw HTML. If your content is missing from that response, so is it to most crawlers.

  • Does switching to server rendering guarantee better rankings?

    No. It removes a technical barrier to being indexed and understood, which is necessary but not sufficient — content quality, links and the rest of on-page SEO still decide where you rank.

Sources

  1. Rendering on the web — web.dev (Google) (checked 23 September 2026)
  2. Understand JavaScript SEO basics — Google Search Central (checked 23 September 2026)
  3. Server APIs for React DOM — react.dev (checked 23 September 2026)

Find out what a crawler actually sees on your React app

Book a free 30-minute consultation with Ibrahem and Jeremy. We look at your site while we talk, and you leave with a prioritised plan.

Who wrote this

Ibrahem HelalCo-founder

Leads strategy and delivery.

Works on: SEO, GEO

Reviewed before publishing by Jeremy Zava, Co-founder.

Posts by Ibrahem Helal

More on this