FREE INSURED SHIPPING WORLDWIDE
SEO for JavaScript Websites | SSR, Prerender & Indexing
Stage monitor · JS sites
Discover · crawl · render · index

SEO for JavaScript Websites Where Every Render Step Is Checked

A JavaScript site can load beautifully for a buyer and arrive at Googlebot as an empty div. We trace the four stages that decide indexation, fix the one that breaks, and prove the result by comparing what the crawler receives with what your visitors see.

01Server-rendered HTML for every template that earns traffic
02Real anchors in the initial response, not click handlers
03Hydration cost measured, then reduced where it hurts INP
04Log-file and rendered-DOM verification instead of assumptions

Send one URL. We return the raw HTML, the rendered DOM and the gap between them.

Pipeline · product templatestage 3 delayed
01 DISCOVER sitemap + anchors 02 CRAWL 200 + HTML body 03 RENDER queued, up to 14 days 04 INDEX canonical evaluated RAW HTML 1.8 KB RENDERED DOM 142 KB JS BUNDLE 864 KB FIRST PAINT 3.9 S
Stage 1–2 healthy Stage 3 queue delay Stage 4 canonical ok Risk content arrives late
StacksNext · Nuxt · React · Vue
First checkRaw HTML vs rendered DOM
DeliverableRendering strategy per route
ProofLogs + URL Inspection

What Googlebot receives is not what you see

Open your product page in a browser and everything is there: gallery, price, specs, reviews, related items. Fetch the same URL with JavaScript disabled and you get a title, a script tag and a root div. Google can render JavaScript, but rendering is a second, queued pass — and it does not always finish. For SEO for JavaScript websites, the whole game is closing that gap before the crawler decides your page is thin.

The symptoms are easy to recognise once you know to look for them. Pages appear in Search Console as "Crawled — currently not indexed". Titles and snippets use generic template defaults because the real ones are set client-side. Images never show in image search. Product variants compete with each other because canonical tags are injected after hydration. None of these look like speed problems, and none of them are fixed by a plugin.

Google's own guidance is consistent: JavaScript is supported, but it costs crawl budget and time, and not every render succeeds. The reliable answer is to deliver the content in the HTML response, then let JavaScript enhance it.

The four stages, and which one is failing

Indexation is a pipeline, not a single event. Debugging starts by finding the stage that breaks, because the fix for a discovery problem is nothing like the fix for a render problem.

Stage 1 — Discovery

If links only exist as JavaScript handlers, there is nothing for the crawler to follow. We check the sitemap, the rendered navigation and the body copy for real href attributes. A router that pushes state on click without an anchor is invisible at this stage, which is the most common cause of pages sitting unindexed for months.

Stage 2 — Crawl

The response has to be a 200 with a meaningful HTML body, correct status codes and no accidental noindex from a staging environment variable. We also check that the HTML is not a client-side redirect, and that Vary and cache headers do not serve a shell to bots and a full page to buyers.

Stage 3 — Render

This is where JavaScript sites lose weeks. Rendering is queued, budgeted and occasionally abandoned. A page whose main content only exists after hydration is competing for a limited resource. Server-side rendering removes the page from that queue entirely.

Stage 4 — Index

Even a correctly rendered page can be discarded if the canonical, the hreflang cluster or the robots directives contradict each other after hydration. We compare the canonical in the raw HTML against the one in the rendered DOM; when they disagree, Google usually takes the rendered value and may drop the page as a duplicate.

Client-side rendering versus server-side rendering

The choice is not ideological. It is a trade between build complexity and how much of your content exists without JavaScript. For pages that earn organic traffic, the answer is almost always server-side.

Client-side renderrisk
SERVER empty shell BROWSER JS builds DOM html content after hydration
  • Content missing from the first response
  • Rendering queued, sometimes deferred for days
  • Canonical and hreflang set too late to count
  • Large bundle delays the first meaningful paint
Server-side rendertarget
SERVER full HTML BROWSER hydrate only html crawler and buyer see the same page
  • Text, links and canonical in the response
  • No dependence on the render queue
  • Fast first paint, smaller perceived cost
  • Hydration becomes an enhancement, not a requirement

There is a middle path. Static generation for pages that change rarely, incremental regeneration for catalogues, and dynamic rendering as a stopgap while a proper SSR migration is scheduled. We are explicit about which of these is a permanent architecture and which is a patch with an expiry date.

The delay that costs you a quarter

When content depends on rendering, publication and indexation stop being the same week. A page can be live on Monday and invisible for a month. That gap is invisible in analytics, because a page with no impressions simply does not appear in the report you are reading.

Day 0Published

URL in sitemap, linked from a hub page.

Day 2Crawled

Shell fetched, content not yet available.

Day 14Queued

Wait for the render pass. Nothing to index yet.

Day 21Rendered

Content found on the second attempt.

Day 45Ranking

Impressions start. Three weeks after launch.

With server-rendered HTML, days 14, 21 and 45 collapse into the first crawl. That is not a marginal improvement; for a product launch or a seasonal campaign it is the difference between being in the index and being absent from it.

Hydration, routing and state

Hydration is a tax, not a feature

Server-rendering solves indexation. Hydration then decides whether the page feels usable. A large component tree re-executing on the client delays interaction and hurts INP, especially on mid-range phones. We measure what hydration costs, then cut it: partial hydration, client components only where interaction exists, and heavy widgets loaded after the first interaction.

Routing has to produce URLs a crawler can find

A single-page app that switches views with pushState and no anchors is a black box. Every route that should rank needs a crawlable <a href> pointing at it from somewhere, plus a server response for that URL. Client-only routes with dynamic parameters deserve particular attention, because they are cheap to generate and expensive to control — faceted filters can multiply your URL space overnight.

State that changes the page is a risk

Currency, locale, login state and personalisation all change what renders. If the crawler sees a different state than the buyer, titles, prices and canonicals diverge. We define which state is indexable, serve that state to bots and first-time visitors, and keep the personalised version out of the index.

Metadata must be in the response, not in an effect

Titles, descriptions, canonicals and structured data set inside a client effect are the single most common bug on React and Vue sites. The fix is to generate them on the server — the framework metadata API, a head component rendered during SSR, or a route-level configuration. Then verify by fetching the page and reading the raw HTML.

Next.js and React pitfalls we meet every month

  • Too many client components. One "use client" at the top of a layout can push an entire page out of server rendering, and with it the content.
  • Data fetched in the browser. A useEffect fetch leaves the first response empty. Fetch on the server, cache the result, revalidate on a schedule.
  • Dynamic routes with no generateStaticParams. Thousands of product URLs render on demand, slow and uncached, so the crawler waits or gives up.
  • Suspense that streams nothing useful. A skeleton in the HTML is still a skeleton to a crawler. Stream the content, not the placeholder.
  • Image components without dimensions. Modern frameworks optimise format and size but not layout stability, so CLS creeps back in.
  • Preview flags leaking into production. A draft-mode cookie or a staging env var can serve noindex to everyone, including Googlebot.
  • Localised routes rendered client-side. hreflang set after hydration is frequently ignored, leaving language clusters disconnected.

None of these require a rewrite. They require someone to read the raw response, compare it with the rendered DOM, and fix the specific component that broke the contract.

How we verify what Googlebot sees

Every claim on this page is testable, and we test it before recommending anything. The process is deliberately boring:

  • Raw fetch. Curl the URL with no JavaScript and read the HTML. If the H1, body copy and canonical are not there, nothing else matters yet.
  • Rendered capture. Render the page in a headless browser with a mobile profile, save the final DOM, and diff it against the raw HTML.
  • URL Inspection. Request indexing on a sample URL and read the rendered HTML Google reports, not the one you expect.
  • Log files. Check which URLs Googlebot actually requests, how often, and whether the response was a 200 with content.
  • Framework-level tests. A small suite that asserts each template contains an H1, a title, a canonical and its links in the server response — run in CI, not once a year.

These checks belong inside the wider technical programme, which is why the work is scoped as part of Technical SEO Services rather than as a front-end ticket.

When the render changes, the URLs usually change too

Most SSR migrations arrive with a routing rewrite, and a routing rewrite is a URL migration in disguise. Trailing slashes shift, locale prefixes move, old query parameters get replaced by path segments. If those changes ship without a redirect map and a crawl comparison, the rankings you were trying to protect disappear in the same week as the improvement.

We run migrations as a controlled sequence: crawl the old site, build a one-to-one map, ship redirects before the new routes, keep both versions crawlable long enough to verify, then monitor indexation week by week. That work is described in SEO Migration Services, and it almost always overlaps with a render change.

Five stages to a crawlable front end

STAGE 01Audit raw HTML per template›
STAGE 02Choose a render strategy per route›
STAGE 03Ship SSR or SSG for money pages›
STAGE 04Fix links, canonical and metadata›
STAGE 05Verify with render diff and logs
  1. Odd days, not all pages. One representative URL per template, fetched raw and rendered, with the gaps written down.
  2. Route-level decisions. Catalogue pages static or incremental, search results always noindex, account pages excluded, marketing pages server-rendered.
  3. Implementation with the framework's own primitives. Server components, metadata exports, route handlers — not a client-side patch layered on top.
  4. Link and metadata repair. Anchors in the HTML, canonicals generated server-side, hreflang in the head, structured data rendered with the page.
  5. Verification and handover. Render diff, log sample, a CI test suite and a short document explaining which route uses which strategy and why.

What changed when the shell stopped being empty

"A valve manufacturer on a React catalogue, 5 months: raw HTML went from 1.8 KB to 96 KB of real content, indexed product pages 340 to 2,180, organic inquiries 4 to 19 per month."

Industrial valves · US

"A furniture exporter mid-migration, 4 months: 1,940 redirects shipped with the new routes, index coverage recovered in 6 weeks, organic sessions held within 4% through the switch."

Furniture · DE

"A lab supplier on Nuxt, 3 months: client-fetched metadata moved to SSR, duplicate canonicals removed, brand-query CTR up 27% with no design change."

Lab supplies · UK

Scope depends on how much of the app is client-only

A marketing site with a React front end and an SSR framework already in place is a short engagement: fix the components that dropped out of server rendering, repair the metadata, verify. A marketplace where every route is client-rendered, with personalisation and five filters per category, is a rendering strategy project with a migration attached.

We scope by route type, by the number of templates and by whether the framework can support the target strategy without a rebuild. If the honest answer is that the current architecture cannot be fixed incrementally, we say so and price the migration separately instead of selling an endless patch.

Send one URL and we will show you the gap

Raw HTML, rendered DOM, and the three fixes that would put your content in the first response.

Pipeline questions

Q1

Does Google index JavaScript at all?

Yes, through a rendering pass, but that pass is queued and budgeted. It is not guaranteed for every URL, and it can lag by days or weeks. Relying on it for primary content is a business risk, not a strategy.

Q2

Do we have to rebuild the whole front end?

Rarely. Most frameworks already support server rendering; the problem is a handful of components, a layout marked client-side, or a data fetch in the wrong place. We fix those first and only recommend a rebuild when the architecture genuinely cannot deliver HTML.

Q3

Is dynamic rendering still allowed?

It is a recognised stopgap, not a destination. Google's guidance has shifted toward rendering the same content for everyone. We use it only as a dated bridge during a migration, with a plan to remove it.

Q4

How long does the fix take to show?

Indexation of server-rendered pages usually starts within one to three weeks of deploy. Ranking and traffic follow over a quarter. Migration work is different: expect four to eight weeks of careful monitoring before declaring it stable.

Q5

Will server rendering slow the site down?

Not if it is cached. We pair SSR with page caching or incremental regeneration so the server does the work once, not on every request. Uncached SSR is a real problem, and we measure TTFB after the change rather than assuming it improved.

Q6

What do you need from our developers?

Repository access or a staging deploy we can test, plus one person who can merge a pull request. If we cannot touch the code, we deliver route-level tickets with acceptance criteria and verify the result after each release.

Q7

How do you prove the crawler sees the content?

Three artefacts: a raw HTML fetch showing the content, a rendered DOM diff, and URL Inspection output from Google. We also keep a CI test that fails if a template ships without its H1, canonical or internal links.

Who monitors the pipeline

A technical team that works inside React, Next.js, Nuxt and Vue front ends, and has cleaned up the indexation aftermath of three framework migrations. We read responses before we read dashboards, and we write checks that keep a template crawlable after the next release.

If your pages are indexed but your snippets are generic, your canonical is inconsistent or your product variants are competing, the pipeline diagram above is where the answer lives.