JavaScript Loaded Content

No Comments
Javascript loaded content

Element Code: PE-019

TL;DR: If your main content only exists after JavaScript runs in the browser, every crawler that cannot or will not render JS sees an empty shell. Google usually renders it eventually; most other bots, including the AI crawlers, never do. Put critical content in the server HTML and treat client-side rendering as an enhancement, not a delivery mechanism.
Element code
PE-019
Category
Rendering and crawlability
Risk
Content invisible to crawlers
Affected
Google, Bing, AI crawlers
Fix effort
Medium to high

What this check actually flags

This check compares the raw HTML your server sends with the DOM after JavaScript has executed. When the meaningful stuff, body copy, product data, headings, internal links, titles, canonicals, only shows up in the rendered version, the page is flagged. The initial response is a shell: a root div, a bundle of script tags, and a promise that content will arrive once the browser does its part.

That architecture is fine for a logged-in dashboard. On a public page that needs to rank, it means every system consuming your site has to run a full browser to see anything, and most of them simply do not.

How Google actually handles JavaScript

Google can render JavaScript, and it is genuinely good at it. Googlebot renders pages with an evergreen version of Chromium, so modern JS features are not the problem. The catch is the pipeline: crawling and rendering are separate steps. Googlebot fetches your HTML first, and pages needing JS go into a render queue before the Web Rendering Service executes them. Google's Martin Splitt has said most pages get rendered within minutes, but it is still a deferred second pass that can fail on timeouts, blocked resources, or script errors, and when rendering fails, whatever only existed client-side simply does not exist.

Two hard limits people keep forgetting. First, Googlebot does not click, so content fetched only after a tap on "Load more" or a tab that pulls data on demand is never seen. Second, links that are not real anchor elements with an href, the classic div-with-onclick navigation, are not reliably followed, which quietly starves whole sections of a site of internal links.

Two paths from crawl to index Path A: content in the server HTML Bot fetches HTML Content already there Indexed Path B: content loaded by JavaScript Bot fetches shell Render queue Chromium renders Indexed only if rendering succeeds GPTBot, ClaudeBot, Perplexity and most non-Google bots stop here: shell only

Google is the best case. Everyone else is worse

Optimizing JS rendering for Google alone made sense in 2019. It does not anymore, because the crawlers that increasingly decide whether you get cited do not render at all. Research published by Vercel and MERJ in late 2024 tested the major AI crawlers and found that GPTBot, ClaudeBot and PerplexityBot fetch the raw HTML and do not execute JavaScript. If your product specs, article body or pricing only materialize client-side, you are handing AI assistants a blank page while your server-rendered competitor gets quoted. Social link previews and smaller search engines behave the same way. Bing does render JavaScript, but nobody outside Redmond will promise you the same coverage and patience Google shows.

How to detect it

  1. Disable JavaScript and reload: in Chrome DevTools, hit the command menu, type "Disable JavaScript", reload the page. Whatever vanished is your exposure. Thirty seconds, no tooling budget required.
  2. View source versus rendered DOM: compare the actual server response (view-source or curl) with the Elements panel. If the body copy is in the second and not the first, it is JS-loaded.
  3. Search Console URL Inspection: run a live test and open the rendered HTML and screenshot. This shows what Googlebot itself produced, including anything that failed to render.
  4. Screaming Frog in JavaScript rendering mode: enable rendering under Config, then use the JavaScript tab, which flags pages where word counts and links differ between raw and rendered HTML. This is how you find the problem at template scale instead of page by page.

How to fix it, step by step

  1. Inventory the damage. List what is JS-only: main copy, titles, meta robots, canonicals, structured data, internal links, product data. Meta signals living only in the rendered DOM are a special kind of footgun, since a client-side canonical can flip after the HTML one was already processed.
  2. Pick a rendering strategy per template. Static generation for stable marketing and blog pages, server-side rendering for pages that change per request, and keep pure client-side rendering for authenticated views that should not be indexed anyway.
  3. Use the framework's server mode. Next.js, Nuxt and SvelteKit all ship server rendering with client hydration, so you keep the interactive feel while the first HTML response carries the full content.
  4. Make navigation real. Every crawlable destination gets a genuine anchor with an href. Router libraries support this; teams just forget to use it.
  5. Do not block the machinery. If some content must stay client-rendered, never block the JS, CSS or API endpoints it needs in robots.txt, or Google's renderer produces the same blank shell as everyone else.
  6. Retest. URL Inspection on the fixed templates, a fresh Screaming Frog rendering crawl, and a diff of raw HTML before and after. The win condition: content visible with JavaScript off.
StrategyContent in first HTML responseCrawler safetyBest for
Static generation (SSG)YesSafestBlogs, docs, marketing pages
Server-side rendering (SSR)YesSafeFrequently changing or personalized pages
SSR plus hydration (hybrid)YesSafeInteractive product experiences
Client-side rendering (CSR)NoRiskyLogged-in app views only
Prerendering for bots (dynamic rendering)Bots onlyWorkaroundLegacy SPAs you cannot rebuild yet

On that last row: Google's own documentation now describes dynamic rendering as a workaround rather than a recommended long-term solution. It buys time for an old single-page app; it is not an architecture to build toward in 2026.

What good looks like

Load any public page with JavaScript disabled and the headline, body content, and navigation are all there. Titles, canonicals and structured data live in the server response, not in a script's side effects. The Screaming Frog JavaScript report shows near-zero difference between raw and rendered word counts on indexable templates. JS still runs, the site still feels like an app; it just stops being the only place your content exists.

DO

  • Server-render primary content, titles, canonicals and structured data
  • Use real anchor tags with href for every crawlable link
  • Test templates with JavaScript disabled after each release
  • Check the rendered HTML in URL Inspection, not just the browser
  • Treat client-side JS as an enhancement layer
DON'T

  • Don't fetch body copy from a client-side API on public pages
  • Don't hide content behind clicks that trigger a network request
  • Don't block JS, CSS or API routes in robots.txt on rendered pages
  • Don't treat dynamic rendering as a permanent architecture
  • Don't assume Google rendering it means every bot sees it

FAQ

Can Google index JavaScript content at all?
Yes, and usually well. Googlebot renders with an up-to-date Chromium and most pages clear the render queue quickly. The issue is reliability and everyone else: rendering is a deferred second pass that can fail, and the non-Google crawlers mostly never render. Server-side content removes the entire class of risk.
Do AI crawlers like GPTBot run JavaScript?
No. Testing by Vercel and MERJ in late 2024 found GPTBot, ClaudeBot and PerplexityBot download HTML without executing scripts. If AI visibility matters to you, and it should by now, JS-only content is invisible to exactly the systems people are asking for recommendations.
Is content in hidden tabs or accordions a problem?
Not if the content is in the HTML and merely hidden with CSS until clicked; that gets indexed fine. The problem is tabs that fire a network request on click to fetch their content. Same UI, completely different crawlability. Check which one your component actually does.
We prerender for bots with a service. Good enough?
It works, and Google explicitly calls it a workaround, not a recommendation. You are maintaining two versions of reality, cloaking-adjacent by design, and paying for the privilege. Fine as a bridge for a legacy SPA; plan the migration to server rendering anyway.
How do I see exactly what Googlebot saw?
Search Console URL Inspection, live test, then open the screenshot and the rendered HTML. Search for a sentence of your main content in that HTML. If it is missing there, it is missing from the index's point of view, whatever your browser shows you.

Suspect your framework is hiding content from crawlers?

Rendering problems are invisible in a browser and brutal in the index. My advanced SEO audit includes a raw-versus-rendered comparison across your templates, so you know exactly what every crawler can and cannot see.

Get the Advanced SEO Audit

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog