You ship a beautiful React app, GSC shows the URLs as crawled, and three weeks later the impressions are still flat. View source on the page and you see a near-empty <div id="root"></div> — every heading, paragraph, and product description lives inside JavaScript that Googlebot may or may not have executed. JavaScript SEO is the discipline of making sure search engines and AI crawlers see the same content your human users see, without the rendering delay killing your rankings.
What is JavaScript SEO?
JavaScript SEO is the technical SEO practice of ensuring that content rendered by JavaScript — typically by SPA frameworks like React, Vue, Angular, or Svelte — is fully discoverable, crawlable, and indexable by search engines. It covers rendering strategy (CSR vs SSR vs SSG), hydration safety, structured data injection, and crawl-budget impact.
The discipline exists because client-side rendering reverses a key assumption of the web: that HTML returned by the server contains the page's content. With CSR, the server returns an empty shell and the browser builds the page from a JavaScript bundle. Googlebot can do that too — but at significant cost, with measurable failure rates, and on a delayed second pass.
JavaScript SEO: Key Facts
What it is: Making JavaScript-rendered content visible to search engines and AI crawlers
Affected sites: SPAs built with React, Vue, Angular, Svelte, SolidJS, Lit, or any framework that ships an empty HTML shell
Root cause: Googlebot must execute JS to see content; rendering is delayed, costly, and fails ~3-7% of the time
Primary solutions: Server-Side Rendering (SSR), Static Site Generation (SSG), or hybrid Incremental Static Regeneration (ISR)
Frameworks that solve it: Next.js, Nuxt, Remix, SvelteKit, Astro, Gatsby — when configured correctly
Testing tools: Google Search Console URL Inspection, Playwright, Chrome DevTools, Daylytix JS Rendering check
Related concepts: Hydration, Time to First Byte, Largest Contentful Paint, Dynamic Rendering
How Does Googlebot Actually Render JavaScript?
Googlebot uses a two-pass indexing model. On the first pass, it fetches the raw HTML and extracts whatever content is immediately visible — headings, links, structured data in the source. The page is then queued for rendering. On the second pass, a headless Chromium engine (currently based on Chrome 130+) executes the page's JavaScript, waits for the DOM to stabilise, and indexes the rendered content.
The second pass is where SPAs fall down. It is delayed: rendering happens hours to days after the initial fetch. It is rate-limited: only a fraction of crawled URLs ever reach the render queue. It is fragile: a single JavaScript error on the page can abort rendering with no log. The result is that JS-only content often appears in Google's index late, partially, or not at all.
CSR vs SSR vs SSG: Which Rendering Strategy Wins for SEO?
| CSR (Client-Side) | SSR (Server-Side) | SSG (Static) | |
|---|---|---|---|
| HTML on first load | Empty shell | Full content | Full content (pre-built) |
| SEO friendliness | Risky — depends on render queue | Excellent — content visible immediately | Excellent + fastest |
| TTFB | Fast (static shell) | Slower (server compute per request) | Fast (CDN edge) |
| Personalised content | Easy (client decides) | Easy (server decides) | Hard (rebuild per variant) |
| Hosting cost | Cheap | Moderate (Node runtime) | Cheapest |
| Best for | Authenticated apps, dashboards | E-commerce, news, dynamic content | Marketing sites, blogs, docs |
Choose SSR when your content changes per request (user-specific, regional, real-time pricing). Choose SSG when your content is the same for every visitor (blog posts, product pages with infrequent updates). Avoid pure CSR when SEO traffic matters — at minimum use prerendering or hybrid approaches.
What is Hydration and Why Does It Cause SEO Problems?
Hydration is the process where a server-rendered HTML page is taken over by client-side JavaScript after load. The server sends fully-rendered HTML; the React runtime then attaches event handlers, syncs state, and "hydrates" the static markup into an interactive app. When it works, users see content instantly and the page becomes interactive moments later.
When it does not work — a hydration mismatch — the client render produces different HTML than the server did, and React (or Vue or Svelte) discards the server output and re-renders from scratch. If Googlebot indexed during that brief mismatch window, it may have indexed the wrong content. Worse, hydration errors are usually silent in production; they only surface as ranking drops weeks later.
How to Diagnose JavaScript SEO Issues (Step by Step)
The diagnosis takes about an hour. The output is a clear list of pages where Googlebot sees less content than your users do.
Step 1: Compare Raw HTML vs Rendered HTML
For a representative page on your site, view the raw HTML (browser View Source, or curl -A "Googlebot" from the command line). Then open the same page in Chrome and run document.body.innerHTML.length in DevTools console. The ratio is your JavaScript dependency.
Rule of thumb: Rendered > 1.5× raw = significant JS dependency. Rendered > 3× raw = the page is essentially invisible to first-pass Googlebot.
Step 2: Test with Google Search Console URL Inspection
In GSC, paste your URL into the search bar at the top, click "Test live URL", then "View rendered page". Compare the rendered screenshot to what users see in a real browser. Missing sections (often hero text, product details, reviews) are content that did not render in time.
Step 3: Check Coverage Report for "Discovered — currently not indexed"
GSC → Pages → "Why pages aren't indexed". The category "Discovered — currently not indexed" is a classic JavaScript SEO signal: Google found the URL but skipped (or failed) rendering. If this category contains pages you expect to rank, JS dependency is almost certainly the cause.
Step 4: Run a JS Rendering Audit Across the Site
A single-page check only proves one example. Use a tool that renders every crawled page with Playwright or Puppeteer and diffs raw HTML against rendered HTML across the entire site. Daylytix's JS Rendering check does this automatically and flags pages with >50% content difference.
The 2026 Fix Playbook
Three patterns cover 95% of JavaScript SEO fixes. Pick based on how dynamic your content is.
Pattern 1: Migrate to SSG (Static Site Generation)
If your content does not change per visitor, pre-render every page at build time. Frameworks: Next.js with getStaticProps, Astro, Gatsby, SvelteKit with prerender = true. The output is a folder of static HTML files served from a CDN — fast, cheap, and trivially indexable. This is the right answer for marketing sites, blogs, documentation, and any catalogue under 10,000 pages.
Pattern 2: Adopt SSR (Server-Side Rendering)
If content varies per request (user, region, time, A/B test), render on the server per request. Frameworks: Next.js with getServerSideProps or App Router default, Nuxt, Remix, SvelteKit with default load functions. The trade-off is server cost and TTFB — your origin must respond within ~600ms for SEO.
Pattern 3: Hybrid ISR (Incremental Static Regeneration)
If you have thousands of pages that update occasionally — e-commerce product pages, news articles, programmatic SEO — use ISR. The first request renders and caches; subsequent requests serve the cache; a configurable revalidation interval rebuilds in the background. Next.js popularised this; Astro and Nuxt now support similar patterns.
Common JavaScript SEO Mistakes
Mistake 1: Loading Title and Meta in useEffect
Why it happens: Single-page-app router updates the document head client-side. Why it backfires: First-pass Googlebot sees the initial HTML title (often "React App") not the route-specific title set after render. What to do instead: Set titles in SSR/SSG output or use a framework helper (next/head, vue-meta, svelte:head) that runs during server render.
Mistake 2: Lazy-Loading Above-the-Fold Content
Why it happens: Default loading="lazy" on images, dynamic imports for hero components. Why it backfires: Googlebot may not scroll, so lazy-loaded content above the fold never triggers. LCP also tanks. What to do instead: Hero images get loading="eager" and fetchpriority="high"; never dynamic-import above-the-fold components.
Mistake 3: Blocking JS or CSS in robots.txt
Why it happens: Old SEO advice from 2010 about saving crawl budget. Why it backfires: Googlebot needs the JS and CSS to render the page correctly. Blocked assets = broken render = downgraded ranking. What to do instead: Leave assets crawlable; if bandwidth is a concern, use a CDN.
Mistake 4: Infinite Scroll Without Paginated URLs
Why it happens: Modern e-commerce defaults. Why it backfires: Googlebot does not scroll, so it only sees the first N items. Products from "page 2" of the infinite scroll never get crawled. What to do instead: Implement infinite scroll on top of paginated URLs (/products?page=2) so each batch has a crawlable address.
Limitation: AI Crawlers Are Even Worse at JavaScript
OpenAI's GPTBot, Anthropic's ClaudeBot, and Perplexity-User do not currently execute JavaScript — they only see your raw HTML. If your site is CSR-only, you are invisible to AI search regardless of how well Googlebot eventually renders you. SSR/SSG is now also an AI visibility play, not just a Google one.
TL;DR: JavaScript SEO Summary
What it is: Making JS-rendered content visible to search engines and AI crawlers.
The problem: Googlebot delays JS rendering, fails 3-7% of the time, and AI crawlers don't render at all.
Three solutions: SSR (per-request render), SSG (build-time pre-render), or hybrid ISR.
Best framework choices: Next.js (SSR + SSG + ISR), Astro (SSG + islands), SvelteKit, Nuxt, Remix.
Diagnostic tools: GSC URL Inspection, raw-vs-rendered diff, Daylytix JS Rendering check.
Top mistakes: title in useEffect, lazy-loading above the fold, blocking JS/CSS, infinite scroll without paginated URLs.
Bottom line: Pure CSR is now an SEO and AI-visibility liability. Migrate to SSR or SSG for any content you want indexed.
Frequently Asked Questions
Does Google render JavaScript?
Yes. Googlebot runs a recent Chromium engine and renders JavaScript on every crawled page. The catch is that rendering happens on a delayed second pass, can fail silently on heavy scripts, and consumes far more crawl budget than serving HTML directly.
Is SSR better than client-side rendering for SEO?
Yes for most content sites. SSR delivers the full HTML on the first request so search engines, AI crawlers, and users on slow connections all see content immediately. CSR forces a render round-trip that delays first paint and risks Googlebot timing out before content appears.
What is hydration and why does it cause SEO problems?
Hydration is the process where a server-rendered HTML page is taken over by client-side JavaScript after load. If hydration crashes or differs from the server render, Googlebot may index a different version than what users see — sometimes a broken or empty page.
How do I check if Googlebot can see my JavaScript content?
Use Google Search Console's URL Inspection tool. Click "Test live URL" then "View rendered page". Compare what you see to the raw HTML via "View source" in your browser. If content appears only in the rendered view, you have JavaScript dependency.
Does Next.js solve JavaScript SEO?
Next.js solves it when you actually use its SSR or SSG features. If you build a Next.js site that uses client-side useEffect to fetch all data, you have the same problem as plain React. The framework gives you the tools — you still have to configure them correctly.
Related Topics
- Core Web Vitals in 2026: Server-rendered HTML is also the fastest path to a good LCP score.
- Technical SEO Audit Checklist for 2026: JS rendering audit is one layer of the full technical audit.
- Crawl Budget Optimization: JS-heavy sites burn far more crawl budget per indexed page.
- llms.txt for AI Crawlers: Even with llms.txt, AI bots only see your raw HTML — SSR/SSG is non-negotiable for AI visibility.
Getting Started
I have done JavaScript SEO audits where a single missing getStaticProps call was responsible for a six-figure drop in monthly organic sessions. The fix took the dev team three days; the recovery took eight weeks. The longer you let CSR ship, the more expensive the cleanup gets.
Start by running the raw-vs-rendered diff on five representative pages. If even one page shows the rendered HTML is twice the size of the raw HTML, you have a problem worth solving now rather than later. Run a free audit with Daylytix — the JS Rendering check runs on every audit and flags exactly which pages are losing content to Googlebot.