Skip to content
SEO

JavaScript SEO: How Modern Websites Talk to Google

Welda Team10 min read26 June 2026

JavaScript SEO is the whole body of technical work that makes sites rendering their content with JavaScript in the browser fully crawlable, renderable, and indexable by Google. A modern site built with React, Vue, Angular, or Next.js gives users an app-like, fluid experience; but that same architecture places an invisible layer between the site and the search engine. A page that looks fully loaded on a user's screen can be nothing but an empty HTML skeleton the moment Google first looks at it.

Why should you care? Because Google ranks based on the content it can actually see. A product description that never renders, a category list that loads late, or a heading buried inside JavaScript exists for you but not for the index. And the problem is sneaky: because the site works flawlessly in the browser, the team assumes everything is fine; the symptom usually only surfaces months later, when organic traffic quietly falls short of expectations. In 2026 the picture has only gotten sharper: AI Overviews has become widespread, and AI-powered search tools generate their answers from crawlable content, and a significant share of those bots don't execute JavaScript at all. If your content doesn't arrive from the server, you become invisible not just in classic search results but in AI summaries too.

We've built this piece as a troubleshooting guide: first we'll look at how Google actually processes JavaScript, then at the risk profiles of CSR, SSR, and SSG architectures; from there we'll move from symptoms to diagnosis and cover the most common mistakes on React and Next.js sites, along with their fixes.

How Google processes JavaScript: crawling, rendering, indexing

On a classic HTML page, the process is straightforward: Googlebot downloads the page, reads the text, extracts links, indexes it. On JavaScript-heavy pages, one more stage is inserted: rendering. The flow described in Google Search Central's documentation has three steps. Googlebot first crawls the URL and takes the initial HTML the server returns. If the content isn't in that HTML, the page goes into a render queue; Google's rendering infrastructure, called the Web Rendering Service (WRS), which has run on an up-to-date version of Chromium since 2019, opens the page like a real browser, executes the JavaScript, and passes the resulting DOM on to the indexing system.

On paper, that reads as 'Google already runs JavaScript, so there's no problem.' In practice there are three risks. The first is timing: rendering doesn't happen in sync with crawling, it gets queued. Google says most pages get rendered within minutes; but that's an average, not a guarantee, and the delay can stretch out during busy periods or on large sites. The second is cost: running JavaScript demands far more processing power than reading plain HTML. Google doesn't allocate unlimited resources to any single site; on a site with tens of thousands of URLs, that can mean some pages get rendered late or never get crawl priority at all. The third is fragility: if a JavaScript error occurs during rendering, a critical API request times out, or a needed resource gets blocked, Google indexes the incomplete version of the page, and it won't notify you separately.

There's also a frequently overlooked, current fact: even though Google can render, most answer-generating AI crawlers settle for the initial HTML. A site that doesn't send content from the server is, to a large extent, empty in the eyes of these systems. At a time when search behavior is expanding toward AI tools, that's a visibility loss too significant to ignore; we cover the strategic dimension of this in depth in our SEO in AI search piece. Looking at this picture, the core principle emerges on its own: content you want indexed shouldn't be left at the mercy of JavaScript, it needs to exist in the initial HTML.

CSR, SSR, SSG: same content, three different delivery methods

Almost every JavaScript SEO problem traces back to the same question: where is the HTML actually generated? The answer is one of three main architectures, and each carries a different risk profile.

Client-side rendering (CSR)

The default behavior of plain React or Vue apps. The server sends a nearly empty HTML shell along with a large JavaScript bundle; content only takes shape after code runs in the browser, usually after fetching data from an API. There's no problem for the user, but it's the riskiest scenario for a search engine: the initial HTML has no heading, no text, no link. Indexing depends entirely on the render step completing without a hitch; for bots that don't execute JavaScript, the page effectively doesn't exist.

Server-side rendering (SSR)

HTML is generated on the server on every request; both the browser and the bot receive a page already full of content. This is the core promise of frameworks like Next.js and Nuxt, and it's the safest approach for SEO: content is ready in the initial HTML without waiting on Google's render step. The cost is server load on every request and a response time that can stretch out if not set up correctly. It's also worth knowing that SSR doesn't finish the whole job: the page becomes interactive in the browser through a process called 'hydration,' and heavy JavaScript bundles drag down user experience metrics right at that stage.

Static generation (SSG) and incremental regeneration (ISR)

Pages are generated as HTML at build time and served from a CDN. For blogs, documentation, corporate pages, and landing pages that rarely change, this is both the fastest and safest option; there's nothing left to render, and server cost is nearly zero. For large sites with frequently changing content, Next.js's ISR (Incremental Static Regeneration) approach refreshes static pages in the background at set intervals, resolving the tension between freshness and speed.

The practical rule is this: every page you expect organic traffic on, home, category, product, blog, should be served with SSR or SSG. CSR is entirely legitimate for areas that don't need to be indexed, like a login-gated dashboard, a cart, or an account screen. The problem isn't the architectures themselves, it's applying one architecture everywhere without discrimination. Worth noting along the way: the 'dynamic rendering' approach Google referenced for years as a stopgap (serving a separate version to bots and to users) is no longer recommended as a long-term solution; the current advice is server-side rendering or static generation.

From symptom to diagnosis: which problem is yours?

Troubleshooting starts with reading the symptom correctly. Use the list below as a matching table:

  • If a site: search shows all pages listed with the same title, your meta tags are most likely being written only on the client.
  • If your homepage is indexed but category and detail pages aren't, your internal links may not be producing real href attributes; Google can't discover the pages.
  • If the 'Crawled – currently not indexed' row is piling up in Search Console, the post-render content is being judged too weak, or the render cost may be exceeding the page's perceived value.
  • If a page is indexed but the snippet shows missing or unrelated text, part of the content isn't rendering.
  • If your images never show up in Google Images, your lazy-loading setup is using a method the bot can't see through.
  • If nonexistent URLs get flagged as 'soft 404' in Search Console, your app is returning a 200 status code for every address.

Each of these symptoms points to one of the seven mistakes below.

Seven common mistakes on React and Next.js sites, and their fixes

1. Content that only renders on the client

The most common and most costly mistake. Data gets fetched inside useEffect, a component loads via dynamic import with ssr: false, or content depends on client-side state; the end result is that the main text is missing from the initial HTML. As a worked scenario: a 5,000-product e-commerce site fetches product descriptions from a client-side API call. On every render attempt where that API responds slowly or returns an error, Google sees that product page as empty; within a few months, a gap measured in the thousands can open up between the number of pages indexed and the number of pages the site actually has. The fix: in Next.js App Router, components render on the server by default, move your data fetching into server components. 'use client' and ssr: false should be reserved for pieces that are genuinely interactive and don't need to be indexed. A simple test: when you view page source, you should be able to read the main content text.

2. Links that don't produce an href

Googlebot only follows link elements carrying an href attribute. Calling router.push from an onClick handler attached to a div is a link for the user, but a dead end for the bot; Google doesn't click buttons or fill out forms. Similarly, hash-based routing (addresses like site.com/#/products) doesn't create a separate page in Google's eyes; anything after the hash symbol is ignored for indexing purposes. The fix: Next.js's Link component naturally produces an href, use it; even if you need custom click behavior, a valid href must always be present, and any redirect logic should work through the history API over real URLs.

3. Meta tags and canonical written on the client

If title, description, canonical, and robots directives are only added in the browser via tools like react-helmet, Google only sees them after rendering; bots that don't run JavaScript never see them at all. There's an even more critical nuance here: according to Google's documentation, a page carrying noindex in its initial HTML never even makes it into the render queue. In other words, the 'we'll remove noindex with JavaScript' approach doesn't work; the page gets eliminated before JavaScript ever runs. The fix: send all meta tags from the server, in Next.js the Metadata API handles this per page, server-side.

4. Blocking JavaScript and CSS files with robots.txt

A habit inherited from an older generation of sites causes serious damage on modern ones: if directories like /assets, /static, or /_next are blocked via robots.txt, the WRS can't render the page and sees the content as incomplete or broken. Google Search Central's warning is explicit: resources needed for rendering must be crawlable. One additional detail: the WRS caches JavaScript files aggressively; using a content hash in filenames is the safest way to make version changes visible, and modern build tools already do this by default. The fix: remove JS/CSS blocks from robots.txt and use Search Console's URL inspection tool to confirm no blocked resources remain.

5. Soft 404: a nonexistent page returning 200

In CSR apps, the server returns the same app shell with a 200 status code for every URL; a 'Product not found' message gets generated on the client. Google flags these pages, which return status 200 but carry error content, as soft 404. As the count grows, crawl budget gets spent on pages that don't matter, and it drags down the site's overall quality perception. The fix: resolve error states on the server. In Next.js, calling notFound() returns a real 404; use 410 for content permanently removed, and 301 for content that's moved.

6. Content hidden behind an interaction

Googlebot doesn't click, doesn't scroll, doesn't fill out forms; it renders the page with a tall viewport and sees whatever's in the DOM at that moment. Products that appear via a 'load more' button, tab content only added to the DOM on click, and lists fed by infinite scroll are all content the bot can't reach. The fix: back infinite scroll with paginated URLs; give each slice its own address and previous/next links. For tabs and accordions, you can put the content in the DOM from the start and hide it visually with CSS: content present in the rendered DOM gets indexed even if it's visually hidden.

7. Hydration weight collapsing Core Web Vitals

Moving to SSR fixes the rendering problem but doesn't fix sending megabytes of JavaScript. Bloated bundles delay LCP, long tasks during hydration break INP; and Core Web Vitals is both Google's page experience signal and a direct driver of conversion rate. A rough calculation: assuming around 1.5 MB downloads per second on a 4G connection, a 900 KB JavaScript bundle alone takes over half a second just to arrive; add parsing and execution time on top, and interaction delay on a mid-range phone can easily reach 1-2 seconds. The fix: code splitting, pruning unused dependencies, and leaving components that don't need interactivity as server components. For measurement and improvement steps, see our Core Web Vitals guide.

Five-step diagnosis: look at your site through Google's eyes

You don't need expensive tools to find out whether these mistakes exist on your site; the five steps below surface most of the problems:

  1. Run a URL inspection: open the URL Inspection tool in Search Console and use 'View crawled page' to look at the HTML and screenshot Google actually rendered. If the main content isn't there, the problem is confirmed. We cover the tool in detail in our Search Console guide.
  2. Check the initial HTML: use 'view source' on the page and search for a sentence from your main text. If it's not in the source, the content is being generated on the client.
  3. Turn JavaScript off: disable JavaScript in your browser settings and browse the site. What you see is the closest approximation to what bots that don't run JavaScript see.
  4. Run a site: search: use site:yourdomain.com on Google and check whether the titles and descriptions of indexed pages are actually page-specific.
  5. Read the page indexing report: in Search Console's page indexing report, look at which URL patterns the 'Crawled – currently not indexed' and 'Discovered – currently not indexed' groups are piling up in; the pattern tells you exactly where the error lives.

These tests confirm the problem exists; finding the root cause and prioritizing it needs a systematic audit. Our technical SEO checklist lays out the broader framework that covers rendering issues alongside crawl budget, site architecture, and status codes.

Conclusion: getting on Google's good side is a translation job

The relationship between modern JavaScript frameworks and search engines isn't a mismatch, it's a translation problem. Google can process JavaScript; but it does so with delay, at a cost, and conditionally. Most AI crawlers don't process it at all. The rule is clear because of this: the content, meta tags, and links of every page you expect traffic on must exist in the initial HTML. Confining CSR to interactive areas, serving critical pages with SSR or SSG, and running regular render audits are the three terms of this contract.

The good news: once diagnosed correctly, JavaScript SEO problems are usually resolved with a limited number of architectural decisions, and the fix shows sitewide impact. The hard part is noticing that a problem exists on a site that looks flawless in the browser; that takes knowing how to look at it through Google's eyes.

At Welda, our SEO team combines that perspective with a developer's viewpoint: we audit rendering on React and Next.js projects, justify with data which pages should be served with SSR versus SSG, and translate the findings into technical tasks your development team can act on directly. We tie this work to a measurable roadmap as part of our SEO services. If you're curious how your site actually looks to Google, get in touch; let's lay out the current state with concrete findings.

Experience Welda in your own business.

Related posts