JavaScript SEO: Server Rendering, Client Rendering and Crawlers

Crawvix Editorial Team · Published October 29, 2026 · Last updated October 29, 2026 · 9 min read

Modern websites often build their pages in the browser. The server sends a nearly empty HTML file and a bundle of JavaScript, and the script fetches data and draws the content. Visitors never notice. A search engine, though, has to do extra work to see what a visitor sees, and anything that blocks that work can leave your content out of search.

JavaScript SEO is the practice of making sure that the content, links, titles and status codes of a script-driven site reach search engines intact. This guide is for developers and site owners who use a framework such as React, Vue, Angular or Svelte, or who inherited a site that loads content with scripts. You will learn how Google processes JavaScript pages, the trade-offs between rendering strategies, which mistakes cause missing content, and how to test what Google sees.

JavaScript is not bad for search. Google runs it. The problems come from specific patterns, and most are avoidable.

Before you begin

  • Access: the ability to view your site's source code or at least its build setup, and access to Google Search Console for the URL Inspection tool.
  • Know your rendering approach: find out whether your pages are rendered on the server, in the browser, or at build time. Ask a developer, or compare "view source" with the page you see in the browser.
  • Time and risk: testing takes an hour. Changing the rendering strategy of a site can be a large project with real risk. Do the checks first and change only what is broken.
  • Back up your repository state and deploy to a staging copy before any rendering change.

How Google processes a JavaScript page

Google describes three main phases: crawling, rendering and indexing.

  1. Crawling. Googlebot checks robots.txt, then requests the URL. It reads the HTML and collects links from href attributes to add to its crawl queue.
  2. Rendering. Pages that return a 200 status are queued for rendering unless a robots meta tag or header says not to index them. Google says the wait can be a few seconds or longer. A headless Chromium then runs the JavaScript. Google says Googlebot uses an evergreen version of Chromium. Pages with non-200 status codes, such as 404 error pages, may skip rendering.
  3. Indexing. Google uses the rendered HTML to index the page.

Two consequences follow. Content that exists only after your scripts run is seen later than content in the first HTML, and anything that stops the scripts from running means that content is not seen at all.

Rendering strategies compared

Strategy What the first HTML contains Main trade-off
Client-side rendering Mostly empty shell; content appears after scripts run Depends entirely on rendering working for every crawler
Server-side rendering Full content for each request More server work and complexity
Static rendering (pre-rendering at build time) Full content, saved as files Content changes require a rebuild
Hydration Full HTML from the server or build, then scripts make it interactive Needs careful setup so server and browser output match
Dynamic rendering Crawlers get a rendered copy; users get the client version Google calls it a workaround, not a long-term solution

Google's documentation says server-side or pre-rendering is still a good idea because it makes the site faster for users and crawlers, and not all bots can run JavaScript. It calls dynamic rendering a workaround that creates extra complexity and resource needs, and recommends server-side rendering, static rendering or hydration instead. Dynamic rendering is generally not treated as cloaking as long as the rendered content is similar to what users get.

For most sites that depend on search, serving meaningful HTML in the first response is the safest design. That is a design judgement, not a rule, and a well-built client-rendered page can be indexed.

Step-by-step instructions

Step 1: Compare the raw HTML with the rendered page

Fetch the raw HTML and see what is in it before any script runs:

curl -s https://example.com/products/blue-widget | head -n 60

Look for your main heading, body copy and key links. If the response contains only a root <div> and script tags, your content depends on rendering. Note this; it is not automatically a problem, but it sets the stakes for the remaining steps.

You have succeeded when you know whether your key content is in the first HTML response.

Step 2: Inspect the page as Google renders it

Open Search Console, paste the URL into the URL Inspection tool, run the live test and view the rendered HTML and screenshot. Google's troubleshooting page points to this tool and to the Rich Results Test for seeing the rendered DOM, loaded resources and console output.

Check that the rendered HTML includes your main text, links, title, meta description and structured data. Google lists several reasons content may be missing: web components that do not use the <slot> mechanism, features Googlebot lacks, WebSocket or WebRTC connections (Googlebot supports HTTP only), permission prompts that Googlebot declines, and reliance on local storage, session storage or cookies, which are cleared across page loads.

You have succeeded when the rendered HTML in the tool contains every piece of content you expect a visitor to read.

Google discovers URLs through <a> elements with an href attribute. A link that works only through a click handler, with no href, is not something Google's documentation says it will follow.

<!-- Crawlable -->
<a href="/products/blue-widget">Blue widget</a>

<!-- Not crawlable as a link: no href -->
<span onclick="goTo('/products/blue-widget')">Blue widget</span>

Also give each view its own URL. Do not load different content behind URL fragments such as #/products, because Googlebot cannot reliably resolve those. Use the History API so that each view has a real path:

window.history.pushState({}, "", "/products/blue-widget");

You have succeeded when every page you want indexed is reachable through ordinary href links to a distinct path.

Step 4: Return correct status codes and avoid soft 404s

Client-side routers often return 200 for every address, including ones that do not exist. Google calls out this case and gives two workarounds: redirect to a URL where the server returns a real 404, or add a noindex robots meta tag to the error view. The first is cleaner. Our custom 404 page guide shows how to serve a true 404, and the 410 vs 404 guide covers removed content.

You have succeeded when a made-up URL returns a 404 status, checked with curl -I.

Step 5: Keep indexing directives in the first HTML

Google's documentation warns that it may skip rendering when it sees noindex, so changing or removing a noindex with JavaScript may not work. If a page should be indexed, do not put noindex in the original HTML and plan to remove it with a script. The same logic applies to canonical tags. Google does not recommend setting canonical URLs with JavaScript. If you must, the injected value should match the one in the original HTML, and the page should have only one canonical tag. See canonical URLs and duplicate pages.

Titles, meta descriptions and JSON-LD structured data can be set with JavaScript, but test them in the rendered output.

You have succeeded when directives that matter are in the raw HTML or confirmed in the rendered HTML.

Step 6: Do not block the files your pages need

Google says it will not render JavaScript from blocked files or on blocked pages. If robots.txt disallows your script or CSS folders, rendering cannot work properly. Check your robots.txt and your robots.txt blocking checks for rules that cover /static/, /assets/ or /js/.

Also fingerprint file names with a content hash, such as main.2bb85551.js. Google says its renderer may ignore caching headers, so it can end up with outdated script or style files. A new file name for each build avoids that.

You have succeeded when robots.txt allows your scripts and styles, and build output file names change when content changes.

Step 7: Handle lazy-loaded and interaction-gated content

Google Search does not interact with your page: it does not scroll, click or type. Content that appears only after a click, or that loads only when a user scrolls, can be missed. For lazy loading, use methods that load content when it enters the viewport, such as browser-native lazy loading or an IntersectionObserver. Our lazy loading guide covers images in detail. Google's guidance for infinite scroll is to give each chunk its own unique, persistent URL and link them sequentially.

You have succeeded when the rendered HTML in URL Inspection includes content that sits low on the page or in later sections.

Step 8: Decide whether to change the rendering strategy

If Steps 1 to 7 show that the content reaches Google, you may not need to change anything. If key content is missing or inconsistent, consider server-side rendering or static rendering for the affected page types first, not the whole site. Test each change in staging with the same URL Inspection checks.

You have succeeded when affected pages show full content in the raw HTML or, at minimum, in the rendered HTML.

Final verification checklist

  • The raw HTML or the rendered HTML in URL Inspection contains the main content of each key page.
  • Every indexable page is linked with an <a href> to a distinct path.
  • URL fragments are not used to load different content.
  • Missing pages return a real 404 status, or are clearly marked noindex.
  • No noindex is added or removed by JavaScript on pages that should be indexed.
  • Only one canonical tag exists per page, and it matches the raw HTML if both exist.
  • robots.txt does not block script, style or data files used for rendering.
  • Build output files have content hashes in their names.
  • Content behind scrolling or clicking is also reachable by links or loads when visible.

Common mistakes to avoid

  • Assuming Google sees what you see. Always check the rendered HTML in URL Inspection.
  • Click handlers instead of links. Without href, crawlers have nothing to follow. Use anchors.
  • Hash-based routes. Fragment URLs are unreliable for crawling. Use the History API.
  • Soft 404s from client routing. A 200 for a missing view gets error pages indexed. Return 404 or use noindex.
  • Removing noindex with a script. Google may not run the script. Keep the original HTML correct.
  • Blocking JavaScript in robots.txt. Google will not render blocked files.
  • Forcing permissions. Googlebot declines prompts such as location or notifications. Offer content without them.
  • Relying on dynamic rendering long-term. Google calls it a workaround. Plan a move to server or static rendering.

Frequently asked questions

Does Google index JavaScript content?

Yes. It runs pages in an evergreen Chromium and indexes the rendered result. Delays and failures happen when the setup blocks, breaks or hides the content.

Is server-side rendering required for SEO?

No, but Google says server-side or pre-rendering is still worthwhile for speed and because not all bots run JavaScript. It is a sensible default, not a requirement.

Do other search engines render JavaScript?

This guide covers Google. Google notes that not all bots can run JavaScript, so check the documentation of any other engine that matters to you, and favour content in the first HTML if you depend on it.

Can I use JavaScript to set titles and meta descriptions?

Yes, according to Google, but verify the rendered output. Setting them in the initial HTML removes a point of failure.

How do I find JavaScript errors that block rendering?

Use the URL Inspection tool to see console output and exceptions, and read our guide on JavaScript console errors. Google also suggests logging errors with a global error handler while debugging, though parse errors cannot be captured that way.

Will fixing rendering improve rankings?

It can only help content get seen. Rankings depend on many other things, so no change in rankings should be expected from this work alone.

Official references


Next step: See how Crawvix checks a website and capture a baseline once scanning opens. This guide provides technical information, not a guarantee of rankings, traffic or index inclusion.