
Key Takeaways
- 1Why React SEO problems happen in the first place
- 2SSR vs CSR for SEO: which rendering mode to pick per page
- 3App Router SEO: the Next.js SEO checklist
- 4Core Web Vitals for React sites: where the time goes
- 5Next.js international SEO: locales, hreflang and country pages
Quick Answer
Next.js SEO works when every page that should rank is delivered as complete HTML from the server, carries its own title, description and canonical through the Metadata API, appears in a generated sitemap, and loads in under 2.5 seconds on a mid-range Android phone. A React site that renders only in the browser can still be indexed, but Google queues it for a second rendering pass and often misses content that depends on client-side data. Our rule across more than 40 React and Next.js builds: server-render every public page and keep client components for interactive widgets only.
This guide is for founders, product managers and developers who run or are planning a React or Next.js website, in India or anywhere else, and want it to rank rather than merely work. After reading it you will be able to decide which rendering mode each page needs, how to set metadata, canonicals, sitemaps and structured data in the App Router, what to fix first for Core Web Vitals, and whether your single page app needs a rebuild or a repair.
Why React SEO problems happen in the first place
React builds a page in the browser. The HTML the server sends is often a near-empty shell with a root div and a JavaScript bundle, and content appears only after that bundle downloads, runs and fetches data. Humans never notice. Search engines do, because the first thing they read is the shell.
The React SEO problems we are asked to fix come down to five causes: content that exists only after a client-side fetch, one shared title for every route, URLs that change without the server knowing, links built as buttons instead of anchor tags, and bundles so heavy the page fails the speed thresholds. None of these are faults of React. They come from using a tool built for applications to publish content that needs to be found.
JavaScript SEO: how Googlebot actually renders your pages
JavaScript SEO means making content that depends on JavaScript readable by search engines. Googlebot crawls the HTML first, queues the page, and later runs it in a headless browser to see what the JavaScript produces. That second pass can happen minutes or days later and has limits: fetches that time out are abandoned, content that waits for a user action never appears, and anything behind a login is invisible.
Other crawlers are stricter. Most AI search crawlers, social preview fetchers and smaller search engines do not run JavaScript at all. The safe assumption is that only the HTML your server sends is guaranteed to be read.
Single page app SEO: what breaks and what still works
Single page app SEO is possible, but it is the hard version of the job. An SPA serves one HTML document and swaps views in the browser, so every route shares the same initial markup. Google usually indexes the routes eventually if they are linked with real anchor tags and the router updates the URL with the History API, not hash fragments. What breaks is everything that depends on per-route HTML: unique titles, social previews, structured data and fast first paint. If your SPA is a dashboard behind a login, none of this matters. If it is a marketing site or a store, it matters more than any other decision you will make.
SSR vs CSR for SEO: which rendering mode to pick per page
SSR vs CSR for SEO is not a site-wide choice in Next.js. You choose per route, based on how often the content changes and whether it is personal to the visitor. The table below is how we assign the four modes on client projects.
| Rendering mode | How it works | SEO result | Use it for |
|---|---|---|---|
| Static (SSG) | HTML built at deploy time | Best: complete HTML, instant response | Service pages, landing pages, blog posts, city pages |
| Incremental Static Regeneration (ISR) | Static HTML rebuilt in the background after a set interval | Same as static, with fresh data | Product listings, price pages, directories |
| Server-side rendering (SSR) | HTML built on every request | Good: complete HTML, slower response under load | Search results, stock-sensitive pages, personalised but public pages |
| Client-side rendering (CSR) | Shell HTML, content fetched in the browser | Weakest: second render pass, missed content | Dashboards, account areas, anything behind login |
ISR and SEO: fresh pages without a server hit on every visit
ISR and SEO fit together well for catalogue-style sites. A page is generated once, served as static HTML, and regenerated in the background after the revalidation period you set, say 600 seconds for a price list or a day for a blog post. Googlebot always receives complete HTML and your database is not queried on every crawl. The one trap is setting revalidation too long on pages where price or availability changes, which produces stale snippets in search results.
Hydration and SEO: why a correct server render can still fail
Hydration and SEO interact in a way that surprises many teams. Hydration is the step where React attaches event handlers to server-rendered HTML. If server HTML and client render do not match, React discards the server markup and re-renders from scratch, delaying interactivity and shifting layout. Common causes are date formatting that differs between server and browser, random IDs, and reading window or localStorage during render. Mismatches rarely stop indexing, but they hurt Interaction to Next Paint and Cumulative Layout Shift, and those are ranking inputs.
App Router SEO: the Next.js SEO checklist
App Router SEO is simpler than the older Pages Router once you know where each piece lives. Server Components are the default, so content renders on the server unless a component opts into the client with the use client directive. The items below are what we verify on every Next.js audit.
Next.js metadata: titles, descriptions and social previews
Next.js metadata is set by exporting a metadata object or a generateMetadata function from a layout or page. The root layout holds the title template that appends the brand name, the default description, and the metadataBase URL that resolves Open Graph image paths. Each page then exports its own title and description. Two mistakes we see constantly: a root title with no template, so every page gets the same title, and the brand name typed into page titles as well as the template, which produces a stacked title like "About | Brand | Brand".
Dynamic routes SEO: generateStaticParams and generateMetadata
Dynamic routes SEO is where most Next.js sites are won or lost, because segments like a product slug or a city slug create the bulk of indexable pages. Export generateStaticParams so Next.js prebuilds every known slug at deploy time, and generateMetadata so each slug gets its own title and description from your data. For unknown slugs, call notFound rather than rendering an empty template, or you will fill the index with thin pages.
Canonical in Next.js: one address per page
Canonical in Next.js is declared through the alternates key of the metadata object, set to the page's absolute URL. Set it on every indexable page and make it match the sitemap URL exactly: same trailing slash policy, same protocol, same host. Pages reached through filters or UTM parameters should canonicalise to the clean URL, and paginated pages each get their own canonical.
Sitemap in Next.js: generate it from your data
A sitemap in Next.js is a file named sitemap.ts in the app directory that exports a function returning an array of URL objects with lastModified, changeFrequency and priority. Build the array from the same data source that drives generateStaticParams so the sitemap and the real pages never drift apart. For sites above 50,000 URLs, use generateSitemaps to split the output. Add a robots.ts file that points to the sitemap and disallows admin, API and preview paths.
Structured data in Next.js: JSON-LD in a Server Component
Structured data in Next.js is simplest as a JSON-LD script tag rendered by a Server Component, with the object built in code and serialised with JSON.stringify, so it is present in the first HTML and does not depend on hydration. Build the schema from the same data as the page so a price or address change updates both: Organization on the root layout, Article on posts, Product with Offer on product pages, LocalBusiness on location pages, and FAQPage only where the questions are visible.
Core Web Vitals for React sites: where the time goes
Core Web Vitals for React sites fail for predictable reasons: a large bundle delays Largest Contentful Paint, heavy hydration raises Interaction to Next Paint, and images or fonts without reserved space cause layout shift. The fixes, in order of impact:
- Keep the hero image and headline in a Server Component and give the image priority loading so it is discovered in the initial HTML.
- Move interactive widgets to small client components near the leaves of the tree rather than wrapping whole pages in use client.
- Load third-party scripts such as chat widgets and analytics with the Next.js Script component using the lazyOnload or afterInteractive strategy.
- Self-host fonts through the built-in font loader so there is no external font request and no swap flash.
- Use dynamic imports for anything below the fold: carousels, maps, calculators, video players.
- Set explicit width and height on every image and iframe.
Image optimization in Next.js
Image optimization in Next.js runs through the Image component, which resizes to the viewport, serves WebP or AVIF where supported, lazy-loads off-screen images and reserves layout space from the width and height you supply. Three rules make it work: give the above-the-fold image the priority attribute, supply the sizes attribute on responsive images so phones do not download desktop sizes, and keep source files under about 300 KB. Images on an external domain must be listed in remotePatterns in next.config or the build fails.
Next.js international SEO: locales, hreflang and country pages
Next.js international SEO depends on giving each language or country version its own URL, usually a prefix such as /en-in/ and /en-ae/, and telling Google how the versions relate. In the App Router, put a dynamic locale segment at the top of the tree, detect the preferred locale in middleware and redirect only on the home page, and declare hreflang through the alternates.languages key so every version lists every other version plus an x-default. Avoid automatic redirects on deep pages: Googlebot crawls from the United States and would never reach your Indian version.
Do not copy English pages across country folders unchanged. If the UAE page and the Indian page differ only in currency, Google may fold them together, so change prices, contact details and examples for each version.
What we have seen on Next.js projects in Rajkot and abroad
JK Tech Hub's own website runs on the Next.js App Router, and most of this guide comes from auditing it against Search Console month after month. The biggest ranking gain in 2026 came from a boring fix: removing a stacked brand name from the title template so page titles stopped repeating the company name twice. Impressions on city pages moved within three weeks.
For a kitchenware exporter in Rajkot, we inherited a React single page app with 400 product pages that Google had indexed as 11 pages, all with the same title. We moved the catalogue to Next.js with ISR, kept the dealer portal as the existing SPA behind login, and pointed both at the same API. Within two months the catalogue pages were indexed individually and product-name searches started producing enquiries.
For a SaaS client serving US customers, the problem was hydration. Their pricing page rendered correctly on the server but a currency toggle read localStorage during render, so React threw the server markup away on every load. Moving the toggle into an effect cut Interaction to Next Paint from over 600 milliseconds to under 200 on phones.
How to decide: rebuild, repair or leave alone
If your React site is an application behind a login, leave the rendering alone and spend the effort on marketing pages. If it is a public single page app with fewer than 50 pages, a repair is usually enough: pre-render the public routes, add per-route metadata, fix links and submit a sitemap. If it is a catalogue, store or content site with hundreds of browser-rendered pages, a move to Next.js with static and ISR pages pays for itself.
A technical SEO repair of an existing React site in India typically sits between ₹40,000 and ₹1.5 lakh depending on page count. A rebuild of the public layer on Next.js starts around ₹1.5 lakh for a content site and ₹3 lakh for a store. Overseas clients get the same scope at Indian rates.
Related reading and next step
- Next.js development services: how we build and host App Router sites.
- React development: when React alone is the right choice.
- Next.js vs WordPress for SEO: the comparison owners ask for first.
- SEO audit checklist: the list we run before technical work.
- SEO services in Rajkot: technical SEO delivered with the development team in the same office.
Send your site URL through the contact page or WhatsApp +91 7265004040 for a rendering audit and a fixed quote within two working days.
Tags
Continue exploring
Pages on JK Tech Hub related to this article.
