← all articles

JavaScript rendering and the half Googlebot never sees

What rendering actually means for a crawler

When Googlebot requests a page, it gets raw HTML first. If your site is built on a JavaScript framework and that HTML is mostly a <div id="root"></div> with a bundle of scripts underneath, that’s what shows up in “view source.” Everything you actually see in the browser, the headings, the product grid, the internal links, gets built afterward when the browser executes JavaScript and constructs the DOM.

Googlebot doesn’t stop at the raw HTML. It queues the page for rendering, runs it through a headless version of Chromium, and only then does it see the DOM as a user would. But that second step doesn’t happen at the same moment as the first. There’s a gap, and that gap is where a lot of sites lose content, links, and crawl budget without anyone noticing until rankings are already flat.

Two passes, not one

This is the part people skip past because it sounds like plumbing, but it’s the whole story. Crawling and rendering are two separate jobs on two separate queues. The crawler fetches HTML, parses whatever links and text exist in that raw response, and moves on. Pages that need JavaScript to reveal their content or their internal links get flagged for a second pass. That second pass waits in line behind every other page Google has decided is worth spending render resources on.

For a small site or a page Google already trusts, that wait can be short. For a new site, a low-authority section, or a page buried deep in the architecture, it can sit for a long time, and there’s no published SLA for how long. I don’t know Google’s internal prioritization logic and I’m not going to pretend I do. What I can tell you from running sites is that the delay is real, it’s inconsistent, and it means the version of your page that gets indexed first is often the empty shell, not the finished one.

Where the gap costs you

The obvious cost is content. If your hero copy, your product descriptions, or your article body only render client-side, the first index of that URL may contain almost nothing. Google does update the index once rendering completes, but you’re now dependent on that second pass happening promptly and correctly, on every template, on every page, forever, as your CMS or framework changes.

The less obvious cost is links. Googlebot discovers new URLs primarily by following href attributes in HTML. If your internal links only get built by JavaScript after the DOM loads, and rendering is delayed or deprioritized for that section of the site, you’re not just delaying content, you’re delaying discovery of every page those links point to. A slow render queue on your category pages can throttle how fast your product pages get found at all. This compounds on large sites where the crawler has to make constant decisions about what’s worth fetching next.

The javascript patterns that quietly kill crawlability

A few patterns show up over and over on sites I’ve had to fix, my own included.

Links that aren’t links. A <div onclick="navigate()"> or a button wired to a JS router push might work perfectly for a user clicking with a mouse, but it’s not a link a crawler can follow without executing your code first. Anything meant to be crawled needs a real <a href="...">, even if you also attach a click handler for the fast client-side transition.

Content gated behind interaction. Tabs, accordions, and “load more” buttons that fetch content only on click mean that content doesn’t exist in the DOM until a user (or Chromium) triggers the action. If the render pass doesn’t simulate that interaction, and it usually doesn’t, that content stays invisible.

Infinite scroll with no paginated fallback. If page two of your listings only appears after a scroll event fires a fetch call, there’s no URL for that content to live at. Give scrolling sites real paginated URLs underneath the infinite scroll behavior, not just for crawlers but for anyone sharing a link.

Meta tags injected by JavaScript. Canonical tags, hreflang, and robots meta tags that get written into the head via JS are a bet that rendering happens reliably and fast. If it doesn’t, Google may act on the raw HTML’s absence of those tags, or on stale ones left over from a previous state, before your script ever runs. These tags are cheap to render server-side. There’s no good reason to gamble on them.

JavaScript redirects. A client-side window.location redirect requires a full render before Google even learns the redirect exists. A server-side 301 is instant and unambiguous. If you’re using a JS redirect for anything that matters for SEO, you’re adding a dependency you don’t need.

How I check a site before I touch a single line of code

I don’t guess at this. I pull up the page in a browser, open devtools, and disable JavaScript entirely, then reload. Whatever’s left on screen is roughly what a crawler sees before rendering catches up. If the nav is gone, the body copy is gone, and the internal links are gone, that tells me exactly where the risk sits.

Then I compare that to the rendered HTML through Search Console’s URL inspection tool, which shows what Google’s renderer actually produced for that URL. If the two are wildly different, and especially if links present in the rendered version are absent from the raw HTML, that’s the gap I described above, sitting on that exact page.

I also check whether robots.txt is blocking any JS, CSS, or API endpoints the page depends on to render. This sounds basic but I’ve found it on client sites more than once: someone blocked a /api/ or /static/js/ path years ago for an unrelated reason, and the render pass has been failing quietly ever since because the renderer couldn’t fetch the resources it needed.

What actually fixes it

Server-side rendering or static generation is the durable fix. If the HTML that hits the wire already contains your content and your links, you’ve removed the dependency on a second render pass entirely. Frameworks like Next.js, Nuxt, and Astro exist largely to solve this problem, and if you’re starting a new build, picking one of them over a pure client-side setup saves you this entire conversation later.

For existing sites that can’t be rebuilt overnight, hybrid rendering, where the initial page load is server-rendered and subsequent navigation is handled client-side, gets you most of the benefit without a full rewrite. The key requirement is that the first response for any URL a user or a bot might land on directly contains the real content and real links, not a loading skeleton.

What I stopped bothering with

Dynamic rendering, serving a pre-rendered snapshot to bots while serving the JS app to users, used to be a common stopgap. I ran it on a couple of sites years ago. I’ve stopped recommending it. Google’s own guidance moved away from suggesting it as a long-term solution, maintaining a second rendering pipeline just for bots is extra infrastructure that breaks quietly, and cloaking-adjacent setups make me nervous even when the intent is defensible. If a site needs its content crawlable, I’d rather fix the rendering path everyone gets than maintain a bot-only side door.

I also don’t chase this as a one-time audit. Templates change, a developer adds a new interactive component, a marketing team bolts on a JS-driven filter widget, and the gap reopens somewhere new. Checking the raw HTML against the rendered HTML is something I do routinely on my own sites, not something I do once and file away.

None of this comes with a timeline. Fixing a rendering gap doesn’t tell you when Google will re-crawl, re-render, and re-index the affected pages, and I wouldn’t trust anyone who claims otherwise. What it does is remove the guesswork from whether your content and links exist for a crawler at all, which is the part actually inside your control.

If you want more of this kind of practical, no-nonsense technical SEO breakdown, come find us at The SEO Desk.

for SEOs
Tracking rankings or scraping SERPs at scale?

Rank checkers and SERP crawlers get blocked and geo-skewed fast on datacenter IPs. Singapore Mobile Proxy runs real 4G/5G mobile IPs that search engines still trust, so your position data stays clean.

see plans →
read on
More from The SEO Desk

Technical SEO, link building, content and SERP strategy, and tool reviews for people who ship growth.

browse all articles →