JavaScript SEO: How JS Breaks Crawling, Rendering, and Indexing (and How to Fix It)

By Christoph Olivier, Founder, CO Consulting
Last reviewed: July 2026
JavaScript SEO is the practice of making JavaScript-generated content crawlable, renderable, and indexable by search engines. Most JS-SEO problems are not caused by JavaScript itself. They happen when the content, links, or metadata Google needs live only in the client-rendered version, and Google either renders it late or never sees it. This guide covers the technical mechanics: how Google processes JS in two waves, why client-side rendering fails, which rendering strategy to pick, and how to test what Google actually sees.
Unlike a general “do I need to code for SEO” overview, this is the rendering-mechanics deep dive. If your JavaScript-heavy pages rank on page 3 or refuse to index at all, the cause is almost always in the render step described below.
How does JavaScript affect crawling, rendering, and indexing?
JavaScript affects SEO at three separate stages: crawling (Google finding your URLs), rendering (Google executing your JS to build the page), and indexing (Google storing the rendered result). JS can break any of the three. If links are injected by JavaScript, Google may not discover them during crawling. If content is injected after load, Google may not see it until rendering, which can happen days later. If the render fails, the page indexes empty.
The core rule: Google indexes the rendered HTML, not the raw HTML your server sends. But it decides whether and when to render based on what it finds first. Anything critical that only exists after JavaScript executes is at risk. This includes body copy, internal links, title tags, canonical tags, meta robots directives, structured data, and pagination.
For a broader view of how storage and eligibility work once a page is rendered, see the SEO indexing pipeline guide. This page stays focused on the JavaScript render step that sits between crawling and indexing.
The two-wave rendering process explained
Google processes JavaScript sites in two waves. Wave one is the raw HTML crawl: Googlebot fetches the server response and indexes whatever is present in the initial HTML immediately. Wave two is rendering: the page joins a render queue, a headless Chromium instance executes the JavaScript, and Google indexes the rendered output. The gap between the two waves can be minutes, hours, or in rare cases weeks.
This delay is the root of most JavaScript SEO failures. If your content, links, and tags are only present after wave two, none of it counts until the render happens. On a fast-moving site, that lag can mean new pages sit undiscovered while competitors with server-rendered HTML index the same day.
Google has stated that its median render delay is short, often seconds. But median is not worst case. Crawl budget, page value, and render-queue load all push the delay around. The safe assumption for any page that must index reliably: put the important content in the HTML Google gets in wave one.
| Stage | What Google does | What can break |
|---|---|---|
| Crawl (wave 1) | Fetches raw HTML, parses <a href> links, indexes raw content | JS-injected links and content are invisible here |
| Render queue | Page waits for rendering resources | Delay of seconds to weeks; time-sensitive pages lag |
| Render (wave 2) | Headless Chromium executes JS, builds final DOM | Failed fetches, timeouts, blocked resources, errors |
| Index | Stores rendered HTML for ranking | Empty or partial render indexes thin or blank |
The most common JavaScript SEO problems
Most JavaScript SEO problems fall into a handful of repeat offenders. They share one trait: something Google needs is missing from the version it can render. Below are the failures that cause the most lost rankings, roughly in order of how often they appear in real audits.
- Links in onclick or buttons, not anchor tags. Google follows
<a href>. It does not reliably followonclickhandlers or<button>navigation. JS routers that hijack clicks without real hrefs can hide half your site from crawling. - Content injected after a user action. Anything behind a click, scroll, or tab that requires interaction may never render for Googlebot, which does not scroll or click. Content that appears only after “load more” is at risk.
- Slow client-side rendering. If content takes several seconds of JS execution to appear, the render can time out or the content can be missed. Aim to have primary content available fast, not after a long fetch chain.
- Blocked JS or API resources in robots.txt. If Googlebot cannot fetch the JavaScript files or the API endpoints that supply data, the render produces an empty shell.
- Metadata set by JavaScript. Title tags, canonicals, and meta robots injected client-side can be missed or applied inconsistently. Server-render these whenever possible.
- Soft 404s and status confusion. A JS app that returns a 200 status for a “not found” screen tells Google the empty page is valid. Google cannot see a 404 that only exists in the UI.
These overlap heavily with the broader technical SEO checklist, but the JavaScript versions are harder to spot because the raw HTML and the rendered HTML look different. You have to inspect the rendered output to catch them.
CSR vs SSR vs SSG vs ISR: which rendering strategy for SEO?
Rendering strategy is the single biggest SEO lever on a JavaScript site. Client-side rendering (CSR) is the riskiest for SEO because it depends entirely on wave two. Server-side rendering (SSR), static site generation (SSG), and incremental static regeneration (ISR) all send complete HTML on the first request, which is what Google indexes best. For most service businesses, SSR or SSG is the correct default.
The distinction that matters for SEO is simple: does the server send finished HTML, or does the browser build it? If the server sends it, Google indexes reliably in wave one. If the browser builds it, you are betting on the render queue.
| Strategy | Who builds the HTML | SEO reliability | Best for |
|---|---|---|---|
| CSR (client-side) | Browser, after JS loads | Weakest; depends on wave 2 | Logged-in apps, dashboards behind auth |
| SSR (server-side) | Server, per request | Strong; full HTML on first load | Dynamic pages that change per user or often |
| SSG (static) | Build time, pre-rendered files | Strongest; plain HTML, fast | Blogs, marketing pages, docs |
| ISR (incremental static) | Build time, regenerated on a schedule | Strong; static speed, fresh data | Large catalogs, frequently updated content |
Dynamic rendering, serving a pre-rendered version to bots and the JS app to users, was once Google’s recommended workaround. Google now treats it as a stopgap, not a long-term solution, because it doubles maintenance and can drift into cloaking territory if the two versions diverge. Prefer real SSR or SSG. If you are choosing a stack or a CMS, factor rendering strategy into the decision the same way you would in a full 2026 Google SEO plan.
Hydration: the failure mode nobody explains
Hydration is when the browser attaches JavaScript interactivity to server-rendered HTML. When it works, users get fast HTML plus full interactivity. When it fails, the framework can discard the server HTML and re-render on the client, which reintroduces every CSR risk and can serve Google different content than the server sent. A hydration mismatch is one of the sneakiest JavaScript SEO bugs because the page looks fine to a human.
A hydration mismatch happens when the HTML the server produced does not match what the client-side framework expects to produce. The framework throws away the good server HTML and rebuilds it in the browser. To Googlebot, the reliable wave-one content can vanish, replaced by whatever the client render produces, which may be slower or incomplete.
Newer approaches reduce this risk. Partial hydration only hydrates the interactive components and leaves static content as plain HTML. Resumability, the approach used by frameworks like Qwik, skips hydration entirely by resuming state the server already serialized. Both shrink the JavaScript that has to execute before content is stable, which is good for both Core Web Vitals and indexing.
How to test what Google actually sees
Never assume Google renders your JavaScript correctly. Test it. The fastest check is Google Search Console’s URL Inspection tool: inspect a live URL, open “View Tested Page,” and read the rendered HTML and screenshot. If your main content, internal links, or title tag are missing from the rendered HTML, Google cannot index them. This one test catches the majority of JS-SEO failures in two minutes.
- URL Inspection (Search Console). Inspect the live URL, click “Test Live URL,” then “View Tested Page.” Read the rendered HTML tab. Search it for a sentence you know is on the page. If it is not there, Google is not indexing it.
- Rich Results Test. Enter the URL and view the rendered screenshot and HTML. Fast way to confirm structured data survives the render.
- The disable-JavaScript check. In Chrome DevTools, open the command menu, run “Disable JavaScript,” and reload. What remains is close to your wave-one HTML. If the page is blank, you are fully client-rendered.
- View source vs Inspect Element. “View source” shows the raw HTML Google gets first. “Inspect Element” shows the rendered DOM. If your content is only in the second, it depends on rendering.
- A crawler with rendering. Tools like Screaming Frog can crawl in rendered mode and flag blocked resources and JS-dependent content across the whole site, not just one page.
Run the disable-JavaScript check first. It takes ten seconds and tells you immediately whether you have a rendering dependency worth investigating. If the page is blank with JS off, escalate to the URL Inspection test to see exactly what Google renders.
A worked example: page 3 to page 1 from one render fix
Here is a real pattern I see on service-business sites built on modern JS frameworks. A firm ships a new services page. It looks perfect in the browser. Three weeks later it still sits on page 3 for its target term, and Search Console shows it “Crawled, currently not indexed” or indexed with almost no content.
The two-minute diagnosis: inspect the URL in Search Console, open the rendered HTML, and search for the first paragraph of the page. It is not there. The content is injected client-side after a data fetch, and Google indexed the empty shell from wave one. The fix is not a marketing task. The developer switches that route from client-side rendering to server-side rendering or static generation, so the server ships complete HTML.
Once the server sends finished HTML, the content appears in wave one, Google indexes it on the next crawl, and the page moves. This is the highest-leverage technical SEO fix on JS-heavy sites, and it is invisible until you inspect the rendered output. It is also exactly the kind of issue a growth engagement surfaces in the first technical pass. This is original first-hand analysis from live client audits.
Frequently asked questions
Can Google index JavaScript content?
Yes. Google renders JavaScript with a headless Chromium and indexes the rendered HTML. The catch is timing and reliability. Google indexes raw HTML immediately in wave one, then renders JavaScript in wave two, which can lag from seconds to weeks. Content that only exists after JavaScript executes indexes late or not at all if the render fails, so put critical content in the server HTML.
Is client-side rendering bad for SEO?
Client-side rendering (CSR) is the riskiest rendering strategy for SEO because all content depends on Google completing the second render wave. It can work, but it removes your safety margin. Server-side rendering, static generation, and incremental static regeneration all send complete HTML on the first request, which Google indexes reliably. For public marketing and content pages, avoid pure CSR and use SSR or SSG instead.
How do I test if Google renders my JavaScript?
Use Google Search Console’s URL Inspection tool. Inspect a live URL, click “View Tested Page,” and read the rendered HTML and screenshot. Search the rendered HTML for a sentence you know is on the page. If it is missing, Google is not indexing it. A ten-second pre-check is disabling JavaScript in Chrome DevTools and reloading; if the page goes blank, you have a rendering dependency.
What is a hydration mismatch and why does it hurt SEO?
A hydration mismatch happens when the HTML a server renders does not match what the client-side JavaScript framework expects to produce. The framework discards the good server HTML and re-renders in the browser, which can hide reliable wave-one content from Google and serve different content than the server sent. It also degrades Core Web Vitals. Fix mismatches by keeping server and client output identical, or use partial hydration or resumability.
Does JavaScript slow down indexing?
It can. Google indexes raw HTML immediately but queues JavaScript rendering as a separate second wave. That render delay ranges from seconds to weeks depending on crawl budget and page value. For time-sensitive pages, news, launches, or fast-changing catalogs, the lag can mean competitors with server-rendered HTML index the same content first. Server-rendering the critical content removes the dependency on the render queue.
