JavaScript SEO: Best Practices for Crawlable and Indexable Websites

JavaScript SEO search visibility icon

JavaScript SEO is the work of making sure search engines and AI crawlers can find, render and index content that a website builds or changes with JavaScript. Google can run JavaScript, but it does so in a separate rendering step with its own limits and many other crawlers do not run it at all. For organisations investing in SEO services for B2B organisations, that gap between what a visitor sees and what a crawler receives is often the reason a well-built website struggles to rank.

This guide is written for marketing leads, IT managers and developers responsible for websites built with React, Vue, Angular, Next.js or similar frameworks, as well as WordPress websites that rely heavily on scripts. It draws on Google Search Central’s own documentation and sets out the practices that keep JavaScript content crawlable and indexable, starting with the short list below.

  • Serve the main content, title, meta description and canonical tag in the initial HTML wherever possible.
  • Choose server-side rendering, static rendering or hydration over pure client-side rendering for pages that need to rank.
  • Use real anchor elements with an href attribute for every internal link.
  • Use the History API for routing instead of URL fragments.
  • Return meaningful HTTP status codes and avoid soft 404 errors in single-page applications.
  • Never block JavaScript or CSS files that are needed for rendering in robots.txt.
  • Test the rendered HTML with Google’s tools, not just the page in a browser.

Each of these is explained below, along with the reasoning behind it. The common thread is that content which exists in the server response is easier for every crawler to process than content which only appears after scripts run.

How Google Processes JavaScript Pages

Google processes JavaScript websites in three phases, which are crawling, rendering and indexing. Google’s JavaScript SEO basics guide explains that Googlebot first fetches a URL, checks robots.txt and reads links from the raw HTML, then queues pages with a 200 status code for rendering in a headless version of Chromium.

Once rendering is complete, Google reads the rendered HTML for further links and uses it to index the page. The guide notes that a page may stay in the rendering queue for a few seconds or for longer, which is why content in the initial HTML response is picked up more reliably than content that depends on JavaScript. It also notes that if the HTTP status code is not 200, rendering might be skipped altogether.

Independent research gives a sense of how long that queue can be. A study by Vercel and MERJ into how Google handles JavaScript throughout the indexing process analysed over 37,000 rendered pages on nextjs.org and found the following.

10 seconds

Median delay between Googlebot’s first crawl and the completed render. A quarter of pages rendered within 4 seconds.

~3 hours

Rendering delay at the 90th percentile of pages. Most pages were rendered far sooner than this.

~18 hours

Rendering delay at the 99th percentile of pages. These long waits were the exception in the study.

Sources: Vercel and MERJ, How Google handles JavaScript throughout the indexing process, July 2024. Figures are based on over 37,000 rendered pages on nextjs.org.

Those figures come from a single, well-maintained website, so a larger or slower website may see different results. The useful conclusion is that Google renders JavaScript reliably in most cases, but rendering adds a step where timeouts, errors and blocked resources can stop content from being indexed.

Is JavaScript Bad for SEO

JavaScript is not bad for SEO in itself and frameworks such as React can rank well when they are implemented with search in mind. Problems arise when important content, links or metadata only exist after client-side scripts run, because that makes indexing depend on a rendering step that can fail.

Google is not the only crawler that matters either. Google’s documentation on rendering workarounds notes that other search engines may choose to ignore JavaScript and will not see content generated by it. AI crawlers are a growing concern here. Vercel’s analysis of AI crawler behaviour found that none of the major AI crawlers it measured, including those from OpenAI, Anthropic and Perplexity, rendered JavaScript, while Google’s Gemini uses Googlebot’s infrastructure and does.

For any organisation that wants to be cited in ChatGPT or Perplexity answers, that finding matters as much as Google rankings. Content that only appears after client-side rendering is likely to be invisible to those systems, which is why AI search visibility work starts with checking what the raw HTML contains.

Choosing a Rendering Strategy

The rendering strategy has more influence on JavaScript SEO than any other decision, because it determines whether crawlers receive finished HTML or an empty application shell. Google now recommends server-side rendering, static rendering or hydration as the long-term solution and describes serving pre-rendered pages only to bots as a workaround rather than a recommended approach.

The web.dev guide to rendering on the web defines the main options. Server-side rendering generates the full HTML for each request, prerendering captures pages as static HTML at build time and hydration adds interactivity to HTML that the server has already delivered. Client-side rendering builds the page in the browser using JavaScript, which works well for logged-in tools but leaves crawlers reliant on rendering.

Approach What crawlers receive Suits
Client-side rendering A minimal HTML shell until scripts run Dashboards, account areas and tools that do not need to rank
Server-side rendering Complete HTML on every request Content that changes often, such as listings and search results
Static rendering Complete HTML generated at build time Service pages, articles, documentation and marketing pages
Hydration Complete HTML, with interactivity added afterwards Frameworks such as Next.js and Nuxt that combine both
Bot-only pre-rendering A separate pre-rendered version for detected bots A temporary fix only, as Google describes it as a workaround

There are trade-offs with each option. Server-side rendering adds load on the server and needs careful caching, while static rendering can make frequently updated content slower to publish. For marketing websites, a server-rendered CMS such as WordPress avoids most of these problems and our guide to when headless WordPress makes sense covers the point at which a JavaScript front end is worth the added complexity.

Links, URLs and Client-Side Routing

Google can only reliably discover pages through anchor elements with an href attribute that resolves to a real URL. Google’s link guidance confirms that links injected with JavaScript are crawlable as long as they use that markup, but elements that act as links through click events alone are not parsed reliably.

Single-page applications need particular care. Google’s JavaScript guidance recommends the History API for routing between views, because URLs built on fragments, such as example.com/#/products, cannot be resolved reliably by Googlebot. Each view that should rank needs its own clean URL, its own title and its own content in the rendered HTML.

✓ Do
  • Anchor elements with a real href
  • History API routes such as /products
  • Paginated URLs behind infinite scroll
  • Descriptive anchor text in the link
✕ Don’t
  • Buttons or spans with onclick handlers
  • Fragment routes such as /#/products
  • Content that only loads on scroll
  • Empty links with icons and no text

These link practices also support accessibility. Proper anchor elements work with keyboards and screen readers by default, whereas script-driven click handlers often need extra work before assistive technology can use them, so the same fix serves crawlers and people.

Titles, Canonicals and Robots Directives

Page titles and metadata icon

Titles, meta descriptions and canonical tags should be present in the initial HTML wherever possible. Google confirms that JavaScript can set or change the title and meta description, but crawlers that do not render JavaScript will only see whatever the server sent and many JavaScript applications ship one generic title for every route.

Canonical tags need more caution. Google advises setting the canonical URL in HTML and states that if JavaScript is used, it should never change the canonical to a different value from the one in the original HTML. Injecting a second canonical tag, or rewriting an existing one, can create conflicting signals with unpredictable results.

Robots directives carry the highest risk. According to Google, when it finds a noindex tag it may skip rendering and JavaScript execution, so a script that removes noindex after the page loads may never run. If a page should be indexed, the original page code must not contain a noindex tag at all and this is a common cause of pages disappearing after a framework release.

Status Codes and Soft 404 Errors

Every URL should return an HTTP status code that matches its content, such as 404 for a missing page or 301 for a permanent move. Server-rendered websites usually handle this by default, but client-side routing in single-page applications often returns a 200 code for every route, including error pages.

Google’s guide to fixing search-related JavaScript problems explains that this can lead to error pages being indexed and shown in results. It recommends two fixes, either a JavaScript redirect to a URL where the server returns a 404, or adding a noindex robots tag to the error view with JavaScript. The same guide notes that Google’s renderer does not keep cookies, local storage or session storage between page loads, so content must not depend on state saved during an earlier visit.

Blocked resources cause similar problems. Google will not render JavaScript from files or pages disallowed in robots.txt, so a rule that blocks a scripts folder can leave Googlebot with an incomplete page even though visitors see everything.

Lazy Loading, Infinite Scroll and Structured Data

Lazy loading is good for performance, provided content loads when it enters the viewport rather than when someone scrolls or clicks. Google’s guidance on lazy-loaded content recommends native browser lazy loading or the IntersectionObserver API, because Google Search does not interact with the page the way a person would.

Infinite scroll needs a paginated fallback. Google advises giving each chunk of content its own persistent URL, such as ?page=12 and linking to those pages in sequence so crawlers can reach products or articles beyond the first screen. Without that, anything a visitor would only see after scrolling may never be indexed.

Structured data can be added with JavaScript, including through Google Tag Manager. Google’s guide to generating structured data with JavaScript warns that Product markup generated this way can make Shopping crawls less frequent and less reliable, so schema for prices and stock levels is better delivered in the server response.

Performance and Third-Party Scripts

Heavy JavaScript affects rankings indirectly through page experience, because large bundles delay rendering and keep the main thread busy. That shows up in Core Web Vitals, particularly Interaction to Next Paint and our practical guide to Core Web Vitals covers how to measure and improve them.

Third-party scripts deserve regular review. Chat widgets, tag managers, consent tools and advertising code can slow rendering or throw errors that interrupt the scripts that build the page and these problems often appear after deployment rather than in testing. Setting a performance budget for bundle size and load time makes it easier to spot when a new feature or integration starts to cause harm.

Caching is a less obvious issue. Google’s renderer caches aggressively and may ignore caching headers, so it can use outdated JavaScript or CSS after a release. Content fingerprinting, where the file name changes whenever the file changes, avoids that risk.

How to Test JavaScript SEO

JavaScript SEO testing and fixing icon

Testing JavaScript SEO means comparing what the server sends with what Google renders, then checking that both contain the content you need indexed. Google recommends the URL Inspection Tool in Search Console and the Rich Results Test, both of which show the rendered DOM, loaded resources and JavaScript console errors.

A site-wide crawl with JavaScript rendering switched on shows the same comparison at scale and server logs show how often Googlebot requests your JavaScript files and priority URLs. Our article on log file analysis for SEO explains how to read that data. The sequence below works well as a repeatable check after any significant release.

  1. 1

    Compare source and render

    View the raw HTML and the rendered HTML for key templates and note what only exists after rendering. Any content, links or tags missing from the source are at risk.

  2. 2

    Inspect in Search Console

    Run the URL Inspection Tool on sample pages from each template. Check the rendered DOM, blocked resources and console errors.

  3. 3

    Crawl with rendering

    Crawl the website with JavaScript rendering enabled. Look for missing titles, canonicals, links and soft 404 pages.

  4. 4

    Monitor after release

    Watch indexing reports, crawl stats and server logs after each deployment. Regressions are far easier to fix when caught early.

Our technical SEO team audits rendered HTML against source code for websites built on JavaScript frameworks, then fixes the indexation gaps it finds. If your rankings have dropped after a rebuild, or important pages are missing from search, our technical SEO services cover JavaScript rendering, indexation control, structured data and Core Web Vitals alongside the wider crawl and site architecture work.

FAQs

What is JavaScript SEO?

JavaScript SEO is the practice of making sure search engines and AI crawlers can find, render and index content that a website builds with JavaScript. It covers rendering strategy, crawlable links, metadata, status codes and testing what crawlers receive.

Can Google crawl JavaScript websites?

Yes, Google renders JavaScript using a recent version of Chromium, but rendering happens in a separate step after the initial crawl. Content, links and tags that exist in the initial HTML are processed more reliably than those that depend on scripts running successfully.

Is React bad for SEO?

React is not bad for SEO when pages are rendered on the server or at build time, for example with Next.js. Problems usually come from pure client-side rendering, where crawlers receive an empty shell and depend on a rendering step that other search engines and many AI crawlers do not perform.

Do AI crawlers render JavaScript?

Most do not. Research published by Vercel found that crawlers from OpenAI, Anthropic and Perplexity fetched JavaScript files without executing them, while Gemini uses Google’s rendering infrastructure. Serving main content in the initial HTML is the most reliable way to be visible in AI answers.

Avatar for Paul Clapp Paul Clapp
Co-Founder at Priority Pixels

Paul leads on development and technical SEO at Priority Pixels, bringing over 20 years of experience in web and IT. He specialises in building fast, scalable WordPress websites and shaping SEO strategies that deliver long-term results. He’s also a driving force behind the agency’s push into accessibility and AI-driven optimisation.

Related All Insights

The main Priority Pixels insight feed. Practical, senior-level thinking on B2B digital marketing across SEO, paid media, content, web design and AI search. Written by the people who deliver the work, based on what has actually worked for our clients.

Technical SEO Automation and What Should Stay Manual
B2B Marketing Agency
Have a project in mind?

Every project starts with a conversation. Ready to have yours?

Get in Touch
Web Design Agency