TECHNICAL

JavaScript SEO: A Complete Guide for 2026

JavaScript-rendered pages present unique challenges for Google. Here's the complete JavaScript SEO guide: how Googlebot renders JS, SSR vs CSR vs SSG, the rendering queue delay, and how to check what Google actually sees.

JavaScript SEO covers the challenges that arise when a website uses JavaScript to render its content, metadata, or navigation — and how to ensure that search engines can discover, crawl, index, and rank those pages correctly. As JavaScript frameworks have become the default for web development, understanding how Googlebot handles JavaScript rendering has become a core technical SEO skill.

How Googlebot renders JavaScript

Googlebot operates in two waves:

First wave — HTML crawl. Googlebot fetches the URL and processes the raw HTML returned by the server. For server-rendered pages (Next.js with SSR, traditional PHP/Rails/Django), the first wave captures the full page content. For client-side rendered (CSR) pages — plain React, Vue without Nuxt, Angular without SSR — the first wave sees only the JavaScript shell: a mostly empty <div id="root"></div> or <app-root></app-root> with no content.

Second wave — JavaScript rendering. CSR pages enter a rendering queue where Googlebot executes the JavaScript, waits for the content to render, and then processes the resulting HTML. This second wave can be delayed by days or weeks depending on crawl priority. During that delay, the page may be indexed with no content — or not indexed at all if Googlebot doesn't return for the second wave.

The practical implication: CSR pages can rank poorly or take much longer to rank than equivalent server-rendered pages, not because Google can't execute JavaScript, but because there's an unpredictable delay between the first crawl and the second-wave render. For new sites and new content, this delay can mean weeks of non-indexing.

Client-side rendering (CSR) vs server-side rendering (SSR) vs static site generation (SSG)

CSR (Client-Side Rendering) — the server sends an HTML shell and the browser (or Googlebot) executes JavaScript to render the content. Default behaviour for React apps created with Create React App or Vite, and Vue.js apps without Nuxt. The rendering gap problem is most severe here.

SSR (Server-Side Rendering) — the server renders the full HTML for each request and sends it to the client. Content is in the HTML on the first wave. Next.js pages using getServerSideProps, Nuxt pages with SSR enabled, and traditional server frameworks (Express with EJS, Django, Rails, Laravel) all produce SSR output. No rendering gap.

SSG (Static Site Generation) — HTML is pre-rendered at build time and served as static files. The full page content is in the HTML on the first wave. Astro, Gatsby, Hugo, Jekyll, Eleventy, and Next.js pages using getStaticProps all produce static HTML. The fastest approach for content that doesn't change per-request, and the most reliable for SEO.

Hybrid (ISR / partial hydration) — Next.js Incremental Static Regeneration and similar patterns pre-render pages but revalidate on a schedule. Mostly static from Google's perspective — good for SEO as long as the on-demand revalidation happens within your desired freshness window.

The test: what does Google actually see?

Use URL Inspection in Google Search Console to see the rendered version of a page as Googlebot sees it after JavaScript execution. The "More info" section shows both the HTTP response (pre-JS) and the rendered HTML (post-JS). Differences between the two reveal what's missing from the first wave.

The second test: view the page source (Ctrl+U or Cmd+U) in a browser. If the meaningful content (headings, body text, metadata) is absent from the raw HTML and only appears after the page has loaded in the browser, it's CSR-rendered and affected by the rendering queue.

Google's Rich Results Test and the Mobile-Friendly Test both render JavaScript before analysing the page — they're useful for checking if structured data and meta tags are present after rendering.

Common JavaScript SEO problems

Metadata added via JavaScript only. If <title>, <meta name="description">, or canonical tags are set by JavaScript (via document.title = ... or React Helmet) and the server doesn't render them into the HTML, they may not be picked up on the first wave. Fix: use the framework's server-side metadata API — generateMetadata() in Next.js App Router, useHead() in Nuxt, <svelte:head> in SvelteKit — which injects these tags into the server-rendered HTML before it leaves the server.

Lazy-loaded content blocked from indexing. Intersection Observer-based lazy loading is supported by Googlebot. display: none / visibility: hidden CSS hiding of content is indexed but weighted lower. The pattern to avoid: conditionally rendering content based on a JavaScript state that doesn't apply on the server (e.g. isClient && <ImportantContent />) — this content never appears in the SSR HTML.

JavaScript-dependent internal links. If navigation links are rendered by JavaScript and the HTML shell contains no <a href="..."> tags, Googlebot may not discover those linked pages on the first wave. Ensure navigation links are in the server-rendered HTML so Googlebot can discover them without JavaScript execution.

Soft 404s from JavaScript redirects. window.location.href = '/not-found' executed client-side doesn't produce an HTTP 404 status code — Googlebot sees a 200 response and attempts to index the error page. Fix: return HTTP 404 status on the server for pages that don't exist. In Next.js App Router: notFound() from next/navigation in a Server Component.

Infinite scroll instead of pagination. Content loaded via infinite scroll as a user scrolls is typically not indexed — Googlebot doesn't simulate scrolling. The fix: implement proper URL-based pagination (?page=2, /page/2/) with canonical tags, or a "View All" page, or numbered pagination links in the server-rendered HTML.

Single Page Application (SPA) routing. SPAs update the URL via the History API without making HTTP requests. Googlebot can follow these routes — but only if the server correctly renders the full page content for each URL, not just the app shell. Verify that direct navigation to any URL on the SPA returns the expected content in the server-rendered HTML.

The JavaScript SEO checklist

  1. Audit rendering mode: is your framework SSR, SSG, CSR, or hybrid?
  2. View the page source — is critical content in the HTML before JS runs?
  3. Use URL Inspection in GSC to compare HTTP response vs rendered HTML
  4. Ensure title, meta description, and canonical are in the server-rendered HTML
  5. Navigation links are <a href="..."> elements in the server-rendered HTML
  6. No content gated behind client-only isClient / typeof window checks for indexable content
  7. Pagination uses URL-based pages, not infinite scroll loading
  8. Error pages (404, 500) return correct HTTP status codes from the server
  9. Structured data (JSON-LD) is in the server-rendered HTML, not added client-side
  10. If using CSR, consider migrating to SSR or SSG for content pages that need to rank

Run the DeepSEOAnalysis free audit to check your rendering mode detection, whether content and metadata appear in the server-rendered HTML, and all 80+ technical SEO signals with specific fix recommendations.


Frequently asked questions

Can Google index JavaScript-rendered content?

Yes — Google can execute JavaScript and render pages. The issue isn't capability but timing: CSR pages enter a second-wave rendering queue that can delay indexing by days or weeks. Server-rendered (SSR) and statically generated (SSG) pages avoid this delay entirely because the full content is in the HTML on the first crawl. For content pages where ranking speed and reliability matter, SSR or SSG is strongly preferred over CSR.

Does React/Vue/Angular hurt SEO?

Not inherently — the framework doesn't determine SEO quality, the rendering mode does. A Next.js (React) site with SSR or SSG ranks just as well as a server-rendered PHP site. A plain Create React App site with CSR has the rendering gap problem regardless of how good the content is. The fix for React is Next.js with SSR/SSG. For Vue, it's Nuxt. For Angular, it's Angular SSR (ng add @angular/ssr).

How do I check if my site has JavaScript SEO issues?

Three checks: (1) View the raw HTML source (Ctrl+U) — if your content doesn't appear in the source, it's CSR and potentially delayed. (2) Use URL Inspection in Google Search Console → "Test Live URL" → compare the HTTP response screenshot (pre-JS) with the rendered screenshot (post-JS). (3) Run the DeepSEOAnalysis audit — it detects CSR rendering gaps, checks whether metadata appears in the server-rendered HTML, and surfaces all JavaScript-related technical issues.

What is the difference between SSR and SSG for SEO?

Both deliver complete HTML to Googlebot on the first wave, so both avoid the CSR rendering gap. The difference is when the HTML is generated: SSR generates it per-request at runtime (always fresh, can use request-specific data), SSG generates it at build time (fast, cacheable, but requires a rebuild to update). For SEO, both are effective. SSG is faster (served from CDN cache), making it better for Core Web Vitals on content that doesn't need per-request data.

Run DeepSEOAnalysis on your own site.

Free, no signup. Technical SEO, Core Web Vitals, structured data, and AI visibility in one report.

Run a free audit →