JavaScript SEO: how Google renders your site and what to fix first
The three phases Google uses on a JavaScript site, the failures that cost indexing, the rendering choices compared, and how to test what a crawler really sees.
Published by AI Knows Us · Updated 12 October 2026
JavaScript sites rank. Google crawls the HTML, queues the page for rendering in a headless browser, runs your JavaScript, then indexes what the rendered page contains. The failures come from three places: content that only appears after a user action, navigation built from click handlers instead of real links, and data fetched in the browser from an endpoint that is blocked or slow. Fix those by serving your primary content and metadata in the initial HTML, using real anchor tags with href attributes, and returning proper status codes from the server. Everything else in JavaScript SEO follows from those three.
This guide covers how Google actually processes JavaScript, the specific failures to look for, how the rendering strategies compare, and how to test what a crawler sees rather than what you see.
How Google processes a JavaScript page
Google describes the process in three phases in its JavaScript SEO documentation, and knowing the order explains most of the problems.
- Crawl. Googlebot requests the URL and reads the HTML it gets back. It finds links in that HTML and adds them to the crawl queue. Anything that is not in the HTML and not reachable through a real link is invisible at this point.
- Render. The page goes into a render queue and is processed by a headless browser running a current version of Chromium. Your scripts execute, your fetches run, and the DOM that results is what gets passed on. Rendering happens after crawling, not at the same time.
- Index. Google indexes the rendered HTML, and extracts links it found during rendering into the crawl queue as well.
Two consequences matter. The render step costs resources, so pages that depend on it can be indexed later than pages that do not. And if a script fails, times out, or requests a resource that is blocked, the rendered page is whatever was there when the attempt ended, which is often an empty shell.
The failures worth checking first
- Navigation that is not a link. A div with an onclick handler, a button that calls a router, or a span styled to look like a link gives a crawler nothing to follow. Use an anchor tag with an href to a real URL and attach your router behaviour to it.
- Content behind an interaction. Tabs, accordions and "load more" buttons are fine as long as the content is in the DOM and merely hidden by CSS. If the content is fetched only when the user clicks, it is not indexed, because nobody clicks.
- Infinite scroll with no URLs. If page two of a listing exists only after scrolling, it is unreachable. Give every page of the listing its own URL and link to them.
- Soft 404s in single page applications. A missing product that renders a "not found" message while the server returns 200 teaches Google to index your error state. Return a real 404 from the server, or redirect to a page that returns 200 legitimately.
- Metadata written by JavaScript. Titles, canonical tags and robots meta tags injected after load are unreliable. A noindex tag in the initial HTML that JavaScript later removes is especially damaging, because Google may drop the page before your script runs. Put all of it in the server response.
- Blocked resources. Scripts, APIs and stylesheets disallowed in robots.txt cannot be used during rendering. Check that your own bundle and data endpoints are crawlable.
- Lazy loading that never triggers. Images and components that load only on a scroll event may not load in a headless render. Use native loading attributes on images and keep above the fold content eager.
- Hash based routing. URLs built with a fragment are treated as the same page. Use the History API and clean paths.
Comparing the rendering choices
| Approach | What the crawler receives | Suits |
|---|---|---|
| Static generation at build time | Complete HTML, fastest possible response | Marketing sites, documentation, blogs, anything that changes on a release cycle |
| Server side rendering per request | Complete HTML, built fresh | Catalogues, listings, personalised pages, anything with changing stock or prices |
| Incremental or cached regeneration | Complete HTML from cache, refreshed on a schedule | Large catalogues that change often but not per request |
| Client side rendering only | An empty container until the render step completes | Logged in applications, dashboards and tools that do not need to rank |
| Prerendering for crawlers | A cached HTML snapshot | Legacy applications you cannot rebuild yet, as a bridge rather than a destination |
The practical rule for any page you want in search results: the main heading, the body text, the canonical tag, the title, the structured data and the internal links should all be present in the HTML the server returns. Everything interactive can arrive afterwards.
Write links the crawler can use
This is the single highest value change on most JavaScript sites.
A crawler cannot follow this:
<div class="nav-item" onclick="router.go('/pricing')">Pricing</div>
A crawler can follow this, and your router still works:
<a class="nav-item" href="/pricing">Pricing</a>
How to test what a crawler sees
- URL Inspection, live test, rendered HTML. In Search Console, run a live test on the URL and read the rendered HTML and the screenshot. If your body copy is absent there, it is absent from the index.
- Disable JavaScript in your browser and load the page. What remains is roughly what every crawler that does not render sees. This takes seconds and finds most problems.
- View source, not inspect element. The source is the server response. The element inspector shows the DOM after your scripts have run, which is why pages look fine there and fail in search.
- Rich Results Test for structured data, which also shows rendered output.
- Server logs. Confirm Googlebot is actually requesting your JavaScript bundles and data endpoints, and is getting 200 responses rather than 403s from a firewall or bot protection rule.
- A crawler that can render, run with rendering both on and off. The difference between the two crawls is your exposure.
Framework notes
Next.js, Nuxt, SvelteKit, Remix and Angular Universal all support server rendering and static generation, so the question is whether your pages are configured to use it, not whether the framework can. A plain React or Vue application built with a client only bundle needs either a move to a rendering framework or a prerender layer in front of it. Check one commercial page per template, because a site often server renders the home page and client renders the product pages that actually need to rank.
This page covers rendering, crawling and indexing for JavaScript sites. For speed and Core Web Vitals, which JavaScript also affects heavily, see a site speed guide.
The JavaScript SEO questions worth an answer
Can Google index JavaScript content?
Yes. Googlebot renders pages with a current Chromium and indexes the resulting DOM. The content needs to be reachable without a user action, and the scripts and data endpoints it depends on need to be crawlable and reliable.
Is server side rendering better for SEO than client side rendering?
Server rendering is the safer default for anything you want in search results, because the content and metadata arrive in the first response and nothing depends on a render step succeeding. Client side rendering is the right choice for application screens behind a login, which do not need to be indexed.
Why does my page look fine in the browser but not in search?
Because your browser runs your JavaScript immediately and a crawler renders later and under resource limits. Compare view source with the rendered HTML in the URL Inspection live test, and the gap between them is almost always the answer.
Does JavaScript slow down indexing?
Pages that need rendering go through an extra queue, so they can be indexed later than pages that deliver their content in the HTML. For news, stock levels and anything time sensitive, serving the content in the server response is the practical way to get indexed sooner.
Should I still use dynamic rendering?
Treat it as a bridge for an application you cannot rebuild yet, and keep the snapshots fresh so crawlers and users see the same content. Where you have the choice, server rendering or static generation is simpler to run and easier to debug.
One more set of crawlers to render for
Assistants read the web with their own crawlers, and those crawlers are not Googlebot. ChatGPT, Gemini, Perplexity, Claude and Google's AI Overviews answer buyer questions directly, they answer differently from one another, and they cite different sources. The crawlers behind several of them fetch HTML without executing JavaScript at all, so a page whose content appears only after hydration can be read as blank by them while ranking perfectly well in Google.
That makes server rendered content worth more than it used to be, and it makes the check easy to run. Ask your buyers' real questions in two or three assistants, keeping your company name out of the prompt so the answer is not led, and see whether your pages are being cited at all. AI Knows Us is a tool built for running that check on a schedule.