Guides

SEO for a React SPA without migrating to Next.js

The usual advice for React SEO is "just use Next.js." That's fine for a new project. If you already have a working Vite or Create React App single-page app, rewriting routing, data fetching, and deployment is a big job. Here's how to get the same result for crawlers without the migration.

The core problem: an empty root div

A client-side rendered (CSR) React app ships one HTML file for every route:

<head><title>Vite + React</title></head>
<body><div id="root"></div><script type="module" src="/assets/index.js"></script></body>

ReactDOM.createRoot(...).render(<App />) fills that div in the browser. Anything that reads only the raw HTML sees an empty page with a generic title: link preview bots, most AI crawlers, and Google's first pass before rendering. Google renders JavaScript later, but it's deferred, and pages can stay "Discovered" or "Crawled – currently not indexed" for a long time.

Step 1: Confirm it

curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://www.yourdomain.com/about

Check whether the response has your real text and a page-specific <title>. Then in Google Search Console, use URL Inspection → Test live URL → View tested page to see what Google rendered. Or run the free CrawlFixer scan, which compares raw and rendered output for you.

Step 2: Fix the metadata layer

Even with perfect rendering, SPAs often have weak metadata:

Step 3: Choose a rendering strategy (no migration)

Option How it works Good for Trade-offs
Build-time prerendering A plugin or script loads each route in a headless browser during the build and saves HTML A small set of static pages Every route must be known at build time; dynamic data goes stale
Self-hosted dynamic rendering You run headless Chrome (e.g. Puppeteer) and route crawler user agents to it Teams comfortable running infrastructure You maintain caching, timeouts, and browser updates
Managed edge prerendering A service in front of your site serves rendered snapshots to crawlers Any SPA, no code changes Monthly cost; needs a custom domain

Google documents dynamic rendering as a workaround and says it isn't cloaking as long as crawlers and users get the same content. Long-term, Google recommends server-side rendering, static rendering, or hydration where practical, so treat prerendering as the pragmatic fix when a rewrite isn't worth it.

Where CrawlFixer fits

CrawlFixer is managed edge prerendering for React SPAs, including apps built with Bolt, Replit, and Lovable (hosted off Lovable). Point www at customers.crawlfixer.com, keep your current host, and crawlers get rendered HTML with titles, descriptions, canonical and social tags filled in, plus a sitemap if you don't have one. Compare it with Prerender.io or Rendertron.

Check your app

Run the free scan (no signup). If crawlers see an empty root div, try it free for 7 days with no card required. Plans are $12/month or $120/year per site.

Related: Lovable site not indexed by Google · Replit app SEO · Why your Bolt.new site isn't on Google

See it for your own site: What Googlebot Sees shows the raw HTML Google downloads next to the rendered page, free. Or run the free SEO checker, or start a free 7-day trial.