# JavaScript SEO Rendering Problems: How to Find and Fix Them

> JavaScript SEO rendering problems hide content, links and tags from Google and AI crawlers. Learn the 9 common causes, how to test them and how to fix each one.

URL: https://seorecheck.com/blog/javascript-seo-rendering-problems · Published: 2026-10-28 · [Українська](https://seorecheck.com/ua/blog/javascript-seo-rendering-problems.md), [Español](https://seorecheck.com/es/blog/javascript-seo-rendering-problems.md)

JavaScript SEO rendering problems happen when the content, links or meta tags of a page only appear after JavaScript runs in the browser. Google has to render the page before it can see them, which can be delayed or go wrong, and many AI crawlers don't run JavaScript at all. The fix is to put critical content in the HTML the server sends.

This guide covers how Google processes JavaScript, the nine rendering problems that cost sites the most, how to test what crawlers actually see, and which fix to pick.

## How does Google render JavaScript pages?

Google processes JavaScript pages in three phases: crawling, rendering and indexing. It first fetches the raw HTML, then puts the page in a queue to be rendered by a headless Chromium browser, and only then indexes what the rendered page shows. Anything that fails in the rendering step never reaches the index.

According to Google's [JavaScript SEO basics](https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics), Googlebot queues all pages with a `200` status code for rendering unless a robots meta tag or header says not to index the page. A page "may stay on this queue for a few seconds, but it can take longer than that." Rendering runs on an evergreen version of Chromium, so modern JavaScript is generally supported.

That sounds reassuring, but it has three consequences:

- **Two chances to fail.** The raw HTML and the rendered DOM can disagree, and Google uses the raw HTML for some decisions (status codes, `noindex`) before it ever renders.
- **Delay.** Content that exists only after rendering is picked up later than content in the HTML.
- **No interaction.** Googlebot loads the page; it doesn't click, scroll or log in.

## Why do JavaScript rendering problems matter for AI search too?

Many AI crawlers fetch your HTML but don't execute JavaScript, so content that only appears after rendering is invisible to them. A page that Google indexes perfectly can still be blank to the bots that feed ChatGPT, Claude or Perplexity answers.

Vercel's study [The rise of the AI crawler](https://vercel.com/blog/the-rise-of-the-ai-crawler) (December 2024) analysed crawler traffic across its network and found that "none of the major AI crawlers currently render JavaScript", including OpenAI's GPTBot and Anthropic's ClaudeBot. They downloaded JavaScript files in some requests but did not execute them. Gemini was the exception, because it uses Google's rendering infrastructure. Crawler behaviour can change, and the vendors don't all document it, so treat this as a measured snapshot, not a guarantee.

The practical rule is the same for both audiences: if a sentence matters for ranking or for being quoted in an AI answer, it should be in the server response. For the wider picture, see our guide to [GEO vs SEO](https://seorecheck.com/blog/geo-vs-seo-differences).

## What are the most common JavaScript SEO rendering problems?

The most common problems are content and links that load only in the browser, JavaScript-only navigation, error pages returning `200`, `noindex` tags changed by script, blocked resources, content that needs a click or scroll, and stale cached bundles. Each one either hides content from Google or sends it a wrong signal.

| Problem | What Google or AI crawlers see | Typical fix |
|---|---|---|
| Content rendered only client-side | Empty shell in raw HTML; content later or never | SSR, static rendering or prerendering |
| Links without `<a href>` | No URLs to follow, orphaned pages | Real `<a href="/path">` links |
| Hash-based routing (`/#/products`) | One URL for the whole app | History API with real paths |
| SPA error pages return `200` | Soft 404s, error pages indexed | Server 404 or JS-added `noindex` |
| `noindex` removed by JavaScript | Page may stay out of the index | Correct robots tag in raw HTML |
| Blocked JS/CSS/API in robots.txt | Broken or empty render | Allow rendering resources |
| Content behind click, scroll or permissions | Content never loaded | Load on viewport visibility, paginated URLs |
| Stale cached bundles | Old or broken render | Fingerprinted filenames |
| State in cookies/localStorage | Fresh, empty session every time | Don't gate content on stored state |

### 1. Critical content exists only after rendering

The classic single-page app sends a `<div id="root"></div>` and a bundle. Google may render it fine, but the content arrives later, and non-rendering crawlers see nothing. Product descriptions, prices, headings and article bodies are the usual casualties.

### 2. Links Google can't follow

Google says it [can only discover links](https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics) that are `<a>` elements with an `href` attribute. Menus built with `<span onclick>` or buttons that call `router.push()` give Google nothing to crawl, so deeper pages become orphans. Our [internal linking guide](https://seorecheck.com/blog/internal-linking-seo-guide) covers how to fix the structure once the links are crawlable.

```html
<!-- Crawlable -->
<a href="/pricing">Pricing</a>

<!-- Not crawlable -->
<span onclick="goTo('/pricing')">Pricing</span>
<a onclick="goTo('/pricing')">Pricing</a>
```

### 3. Hash fragments instead of real URLs

URLs like `example.com/#/services` look like separate pages to users, but Google's [guide to fixing JavaScript problems](https://developers.google.com/search/docs/crawling-indexing/javascript/fix-search-javascript) notes that the AJAX crawling scheme has been deprecated since 2015, so fragment-based routing can't be relied on. Use the History API so every view has its own path.

### 4. Soft 404s from single-page apps

When a SPA shows "Product not found" but the server still returns `200`, Google can index the error page. Google recommends either redirecting to a URL where the server returns a real `404`, or adding `<meta name="robots" content="noindex">` with JavaScript on error views. See [404 errors and SEO](https://seorecheck.com/blog/404-errors-seo-impact) for when a 404 is the right answer.

### 5. `noindex` that JavaScript is supposed to remove

This one catches many teams. Google states that when it encounters a `noindex` tag, "it may skip rendering and JavaScript execution", so using JavaScript to remove `noindex` "may not work as expected." If the raw HTML says `noindex`, assume the page stays out of the index whatever your script does later.

### 6. Blocked resources

If robots.txt disallows `/static/`, `/_next/`, `/api/` or a third-party script that renders content, Google renders a broken page. Check that every file needed to build the main content can be fetched. Our [robots.txt guide](https://seorecheck.com/blog/robots-txt-seo-guide) explains the safe patterns.

### 7. Content that needs user interaction

Google's [lazy-loading guidance](https://developers.google.com/search/docs/crawling-indexing/javascript/lazy-loading) says Google Search "does not interact with your page", so content must load when it's visible in the viewport, not on scroll or click. "Load more" buttons, tabs that fetch content on click and [infinite scroll](https://seorecheck.com/blog/pagination-seo-best-practices) without paginated URLs all hide content. For infinite scroll, Google recommends a persistent URL per chunk, such as `?page=12`, linked sequentially. Googlebot also declines permission requests such as camera or location, so content must not depend on them.

### 8. Stale cached JavaScript

Google notes that its Web Rendering Service may ignore caching headers and use outdated JS or CSS. If you deploy a new bundle under the same filename, Google may render the page with old code that calls a removed API endpoint. Content fingerprinting (`main.2bb85551.js`) solves this.

### 9. Depending on cookies, storage or WebSockets

Google says local storage, session storage and cookies are cleared across page loads, and that WebSockets and WebRTC aren't supported because Googlebot uses plain HTTP requests. A page that reads a consent cookie or saved region before showing content shows Googlebot the empty default.

## How do you test what Google actually renders?

Compare three versions of the page: the raw HTML (View Source or `curl`), the HTML Google rendered (URL Inspection in Search Console) and what a browser user sees. If important text, links or tags are missing from the first two, you have a rendering problem.

Here is a practical routine for one template at a time:

1. **Raw HTML check.** Run `curl -s https://example.com/page | grep "your key sentence"` or open View Source (not DevTools Elements, which shows the rendered DOM). If the H1, body text, canonical and internal links are there, non-rendering crawlers can read the page.
2. **Rendered HTML in Search Console.** In URL Inspection, run *Test live URL*, then *View tested page* to see the rendered HTML, a screenshot and *More info* with page resources that couldn't load and JavaScript console messages. Google points to this tool and the Rich Results Test in its [troubleshooting guide](https://developers.google.com/search/docs/crawling-indexing/javascript/fix-search-javascript).
3. **Compare signals.** Check that the title, [meta description](https://seorecheck.com/blog/meta-description-best-practices), canonical and robots tag are the same in raw and rendered HTML. Conflicting values are a common cause of [indexing problems](https://seorecheck.com/blog/fix-website-indexing-problems).
4. **Check the index.** Search for a distinctive sentence from JS-loaded content in quotes. If the page is indexed but the sentence isn't found, Google likely indexed a partial render.
5. **Disable JavaScript.** Load the page with JavaScript off in your browser. What's left is roughly what a non-rendering AI crawler gets.

Doing this by hand works for a few templates; across hundreds of URLs you need a crawler that saves both versions. A [free SEORecheck audit](https://seorecheck.com/request) loads your pages in a real browser and flags text that is visible only after JavaScript runs, alongside AI crawler access in robots.txt.

Symptoms that point to rendering, not content quality: many URLs in "Crawled – currently not indexed" on JS templates, Google showing generic titles like your app name, and indexed pages that rank for nothing in their body text. Our guides to [crawled – currently not indexed](https://seorecheck.com/blog/crawled-currently-not-indexed-fix) and [Search Console errors](https://seorecheck.com/blog/google-search-console-errors-explained) help separate the causes.

## Which rendering approach is best for SEO?

Server-side rendering or static rendering is the safest choice for pages you want to rank: the full content is in the HTML, every crawler can read it, and JavaScript then adds interactivity. Pure client-side rendering is fine for logged-in app screens that shouldn't be indexed anyway.

| Approach | Content in raw HTML? | Good for | Watch out for |
|---|---|---|---|
| Client-side rendering (CSR) | No | Dashboards, logged-in apps | Invisible to non-rendering crawlers |
| Server-side rendering (SSR) | Yes | Product, category, dynamic pages | Server load, hydration mismatches |
| Static rendering / SSG | Yes | Marketing pages, blogs, docs | Rebuilds when content changes |
| Hybrid (SSR/SSG + hydration) | Yes | Most modern sites | Keep meta tags in the server output |
| Dynamic rendering | Only for bots | Legacy stopgap | Google calls it a workaround |

Google's page on [dynamic rendering](https://developers.google.com/search/docs/crawling-indexing/javascript/dynamic-rendering) is explicit: it "was a workaround and not a long-term solution", and Google recommends server-side rendering, static rendering or hydration instead. If you still run a prerender service for bots, plan to replace it.

Most frameworks support server output: Next.js and Remix for React, Nuxt for Vue, Angular SSR, SvelteKit and Astro. Switching a CSR app to SSR is a real project, so start with the templates that earn traffic, such as product, category, service and article pages.

## How do you fix JavaScript rendering problems in the right order?

Fix the problems that hide whole pages first, then those that hide content, then the ones that only slow things down. A wrong `noindex` or uncrawlable navigation costs more than a delayed render, so order fixes by how many valuable URLs each one affects.

A sensible order:

1. **Indexing blockers:** `noindex` in raw HTML, blocked JS/CSS/API files, soft 404s.
2. **Discovery:** convert JavaScript navigation to `<a href>` links and hash routes to real paths.
3. **Content in HTML:** move headings, body copy, prices and structured data into the server response for money templates.
4. **Interaction-gated content:** replace click- and scroll-loaded content with viewport loading and paginated URLs.
5. **Hygiene:** fingerprint bundles, remove dependencies on cookies and storage, and keep rendered and raw meta tags identical.

Rendering also affects user experience: heavy bundles delay the largest content element and block input, which shows up in [Core Web Vitals](https://seorecheck.com/blog/core-web-vitals-guide) as poor LCP (over 2.5 s) or INP (over 200 ms). SSR often improves both, but measure rather than assume. After any framework upgrade, repeat the raw-vs-rendered checks as part of your [SEO regression testing](https://seorecheck.com/blog/seo-regression-testing-website-updates); rendering breaks quietly.

## Key takeaways

- Google renders JavaScript in a separate, queued step; anything that fails there never reaches the index.
- Many AI crawlers don't execute JavaScript, so content missing from the raw HTML may be invisible to AI answers.
- Use real `<a href>` links and History API routes, never click handlers or `#/` URLs.
- A `noindex` in the raw HTML can stop Google from rendering, so JavaScript can't reliably remove it.
- Error views in SPAs need a real 404 status or a `noindex` tag.
- Compare raw HTML with the rendered HTML in URL Inspection for each template.
- Prefer server-side or static rendering for pages that should rank; Google calls dynamic rendering a workaround.

To see how these problems look in a finished report, browse the [sample report](https://seorecheck.com/sample).

---

## Want to know what to fix on your site?

Get a free SEO audit preview: your score and real issues, with evidence from your pages.

- [Get a free SEO audit preview](https://seorecheck.com/request)
- [See a sample report](https://seorecheck.com/sample)
