Gatsby SEO

How to optimize a Gatsby site for search — Gatsby's four rendering paths (SSG, DSG, SSR, client-only) and what each means for crawlability, the modern Head API vs legacy react-helmet, sitemaps, canonicals, image SEO, the React-bundle CWV cost, and the Netlify-era maintenance risk.

First published: Jun 26, 2026 · Last updated: Jul 18, 2026 · Advanced
demand #1 in Static Site Generators#25 in Platform SEO#168 in Technical SEO#226 on the site
1 evidence signal on this page

Gatsby has four rendering options: SSG (the default — pages pre-rendered to static HTML at gatsby build), DSG (deferred static generation on first request), SSR (server-side rendering per request via Gatsby Functions), and client-only routes (rendered entirely in the browser). Most Gatsby sites lean on SSG, which gives crawlers fully rendered HTML on the first fetch with no rendering queue to wait on — a strong SEO baseline, far better than a pure client-side React app. But that baseline isn't universal: DSG and SSR pages generate HTML outside the build step and need their own production checks, and client-only routes shouldn't be assumed to expose route-specific content in the initial HTML at all. Whichever path serves a page, Gatsby still ships the full React runtime (~200KB+) and hydrates it client-side — a Core Web Vitals cost, not a crawlability one. The current way to manage metadata is the built-in Gatsby Head API (v4.19+), which works across all four rendering paths and replaces gatsby-plugin-react-helmet. The recurring pitfalls are double canonical tags, draft/orphan pages leaking into sitemaps, missing alt text, the production-only sitemap gotcha, DSG/SSR/client-only routes needing explicit sitemap and production-behavior checks, and a framework whose maintenance has slowed sharply since Netlify's 2023 acquisition.

TL;DR — Gatsby has four rendering optionsTurning HTML, CSS, and JavaScript into the final visual page and DOM. — SSG (the default), DSG, SSR, and client-only routes — and they don’t all put content in the raw HTML the same way. SSG pre-renders to static HTML at build time (gatsby build), so content is in the raw HTML before the first crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. request — no Web RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. Service, no rendering queue. DSG defers generation to the first request; SSR generates per request on a server; client-only routes render nothing route-specific until the browser runs the JavaScript. Whichever path serves a page, Gatsby hydrates a full React bundle (~200KB+) on the client, which is a Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. cost, not a crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. one. The current metadata approach is the built-in Gatsby Head API (v4.19+), which works across all four rendering paths and replaces gatsby-plugin-react-helmet. The recurring failure modes are double canonical tags (Head API + react-helmet both firing), draft/orphan pagesAn orphan page is a page on your site that no other page links to internally. Because crawlers discover pages by following links, an orphan page is effectively invisible to search engines unless it's in an XML sitemap or linked from an external site. leaking into sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., the production-only sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. gotcha, missing alt textAlt text is the value of the `alt` attribute on an HTML `<img>` element — a short text substitute chosen for the image's purpose and context, not a literal description of what it shows. It makes images accessible to screen-reader users and helps search engines understand images, mainly for image search. on GatsbyImage, trailing-slash inconsistency, and DSG/SSR/client-only routes that never got a production check. And the elephant in the room: since Netlify’s 2023 acquisition, Gatsby’s maintenance has slowed sharply.

Gatsby’s four rendering options — and why they matter for SEO

Google processes JavaScript pages in three phases — crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., then rendering, then indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. — and rendering happens in a separate pass from a queue using headless Chromium. Google’s own guidance is blunt about why you shouldn’t lean on that: “Server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index., and not all bots can run JavaScript.”

A Gatsby site isn’t universally build-time static HTML — Gatsby supports four distinct rendering paths, chosen per page or template Evidence for this claim gatsby build writes production output, including generated HTML, to the public directory. Scope: Gatsby production builds. Confidence: high · Verified: Gatsby CLI: build :

  • SSG (Static Site Generation) — the default. gatsby build emits fully rendered static HTML into /public for the page. GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.’s first-wave raw-HTML fetch already contains the complete content — text, links, metadata. This is the safe, low-risk path, and it’s what most Gatsby pages use.
  • DSG (Deferred Static Generation). Generation is deferred until the page’s first request rather than happening for every page at build time — useful for sites with huge numbers of low-traffic pages where a full build would be slow. The build alone does not tell you what a crawler sees; the page’s HTML doesn’t exist until something requests it, so first-request and cached behavior need their own check, not just a build log.
  • SSR (Server-Side Rendering). The page is rendered per request, using request-time data, via Gatsby Functions. Because it runs at request time, SSR pages need production checks a build-time page doesn’t: response status, caching headers, timeout behavior, and what a crawler sees on an empty or error response — none of that is visible from a successful local build.
  • Client-only routes. These render entirely in the browser and don’t get route-specific content in the initial HTML — the same profile as a plain client-side React app. Don’t assume Google (or any crawler) sees anything page-specific here until JavaScript runs; treat these as JS-dependent by design, which is fine for gated/authenticated content but wrong for anything you want indexed with content.

React hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers. (ReactDOMClient.hydrateRoot()) happens client-side on top of whichever of these produced the HTML, purely to add interactivity — that part is the same regardless of rendering path, and is a separate concern from which path generated the page (more on hydration cost below).

Contrast SSG/DSG/SSR with a pure client-side React app, which serves an empty <div id="root"> and depends on the browser (or the renderer) to build the page. Most Gatsby pages ship meaningful HTML by default — that’s the indexability win, and it’s real, but it’s a per-page property, not a framework guarantee. Rendering options and image tooling don’t guarantee Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data., indexing, or rankings on their own; verify the actual production output for whichever path a route uses.

The catch with SSG/DSG/SSR alike is a performance one, not a crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. one: Gatsby ships the full React runtime to every page and re-hydrates it. More on that, and the Astro comparison, below.

Gatsby Head API vs gatsby-plugin-react-helmet

This is the single most important “are you doing it the modern way?” question in Gatsby SEOGatsby SEO is the set of practices for getting a Gatsby site found and ranked. By default, Gatsby pre-renders HTML at build time (SSG), putting content in the raw HTML on the first fetch — but Gatsby also supports DSG, SSR, and client-only routes that don't all work that way, and it ships a full React bundle, so canonical tags, sitemaps, and Core Web Vitals still need deliberate work..

The legacy approach — gatsby-plugin-react-helmet. For years, the standard way to set <title>, meta descriptionThe meta description is an HTML head tag — `<meta name=\"description\" content=\"…\">` — that suggests a short summary of the page for the search snippet. It's not a Google ranking factor, and Google rewrites it the majority of the time, but a good one can still lift click-through., and other head tags was the react-helmet library plus this plugin. The plugin’s job was to give react-helmet SSR support — without it, your title/meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. would only appear after JS execution, not in the raw HTML, which defeats the point. It works, but it has known issues with React Hooks and concurrent rendering, plus a background-tab title bug you patch with defer={false}.

The modern approach — the Gatsby Head API (v4.19+). Gatsby now has a built-in way to add head elements: a named Head export from any page or template file. Evidence for this claim Gatsby pages and templates can export a named Head function to add head elements. Scope: Gatsby Head API. Confidence: high · Verified: Gatsby: Head API

export const Head = () => (
  <>
    <title>Page Title</title>
    <meta name="description" content="..." />
  </>
)

It receives useful props — location.pathname, params, data (from the page’s GraphQL query), and pageContext — and it deduplicates tags that share an id prop (last one wins), though running two different head-tag mechanisms at once (Head API plus a leftover react-helmet call) can still conflict even with deduplication. It works only in page files and templates, not in arbitrary components. The advantages over react-helmet: no third-party bundle, no Provider wrapper, deterministic tag order with React 18 streaming. Use the Head API for all new projects, and plan a migration for existing ones.

The Head API works the same way across all four rendering paths — SSG, DSG, SSR, and client-only routes all support a Head export. What differs is when its output lands in HTML a crawler can fetch: on SSG it’s baked in at build time; on DSG and SSR it’s generated at first-request or per-request time; on a client-only route it isn’t in the initial HTML at all. Don’t assume “I added a Head export” is equivalent to “this is in the raw HTML for every route” — check the actual production output (view-source: or curl) for whichever path each route uses, not just one representative page.

The “meta tags in DevTools but not in source” bug. A classic Gatsby SEO symptom: your title/meta tags show up in Chrome DevTools but are missing from view-source:. The cause is that DevTools shows the hydrated DOM (after JS runs), while view-source shows the raw HTML. If your tags only appear in DevTools, your SEO component is rendering client-side instead of being baked into Gatsby’s static output — usually because it’s used as a regular component rather than as (or inside) the page’s Head export. Always verify in raw HTML, not DevTools.

TIP Catch Gatsby metadata that exists only after hydration

The browser DOM can hide a broken production artifact. This compares initial HTML with rendered output and flags titles, descriptions, canonicals, and content that appear only after JavaScript runs.

Test a production route with my free Render Gap Analyzer Free

  1. Run a production build and test a representative page or template—not gatsby develop.
  2. Trace any initial-vs-rendered metadata gap back to the Head export or legacy helmet setup.
  3. Rebuild, retest the raw output, and remove duplicate head-management mechanisms.
If the title exists only after rendering, Gatsby’s static artifact is not carrying the Head output you expected.

The analyzer reports that the title only appears after rendering and says placing it in the initial HTML is more reliable.

Wiring up an SEO component (the GraphQL data layer)

Gatsby’s data layer is GraphQL, and it’s how you feed metadata into your pages.

  • useStaticQuery pulls global defaults from siteMetadata (title, description, siteUrl) defined in gatsby-config.js.
  • Page-level GraphQL queries pass a data prop straight to the Head export — no extra wiring needed.
  • The standard pattern is prop || siteMetadata fallback: use the per-page value if it exists, otherwise the site default.

A Head export that takes page data looks like:

export const Head = ({ data }) => (
  <>
    <title>{data.post.title}</title>
    <meta name="description" content={data.post.excerpt} />
  </>
)

Sitemaps: gatsby-plugin-sitemap (and its traps)

Install gatsby-plugin-sitemap and configure it in gatsby-config.js. A few things trip people up:

  • It generates sitemap-index.xml, not /sitemap.xml. Submit the index URL in Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. — don’t submit /sitemap.xml and expect it to resolve.
  • It only runs in production builds. It does nothing in gatsby develop. To test it, run gatsby build && gatsby serve. People file “my sitemap is missing” reports that are really just “I never ran a production build.”
  • createLinkInHead: true by default adds the sitemap reference to the HTML head automatically.
  • It always excludes /dev-404-page, /404, and /offline-plugin-app-shell-fallback.
  • <priority> and <changefreq> are ignored by Google — the plugin docs say so directly. Focus on an accurate <lastmod> instead.
  • entryLimit defaults to 45,000 URLs per file.

Excluding drafts is your job. Gatsby builds everything it finds, so draft content sails straight into the sitemap unless you filter it. Do that in gatsby-node.js with a GraphQL filter (e.g. excluding entries without a publish date), not by hiding it in a React component — by then it’s already built and listed.

DSG, SSR, and client-only routes need an explicit sitemap decision. gatsby-plugin-sitemap reflects what it can see at build time. An SSG page is straightforward — it exists as a static file, so it’s naturally sitemap-eligible. A DSG page’s HTML doesn’t exist yet at build time (it generates on first request), an SSR page never has fixed HTML at all, and a client-only route has no route-specific content to index in the first place. Don’t assume any of these are in the sitemap (or should be) just because the route exists — decide, page by page, whether it belongs, and verify the generated sitemap-index.xml actually reflects that decision rather than a build-time guess.

robots.txt: gatsby-plugin-robots-txt

gatsby-plugin-robots-txt generates robots.txt at build time. The useful detail for SEO is environment awareness: it reads process.env.GATSBY_ACTIVE_ENV then process.env.NODE_ENV, so you can serve different rules per environment. The classic use is blocking crawlers on Netlify preview/branch deploys so your staging URLs don’t get accidentally indexed, while leaving production open.

Canonical URLs (and the double-canonical bug)

Two viable approaches:

  1. gatsby-plugin-canonical-urls adds a <link rel="canonical"> to every page. Set stripQueryString: true so /blog?tag=foo and /blog don’t get treated as separate canonicalized pages — recommended for most sites.
  2. The Head API, setting canonicals yourself from location.pathname:
export const Head = ({ location }) => (
  <link rel="canonical" href={`https://example.com${location.pathname}`} />
)

The double canonical bug. This is a known, easy-to-hit issue: if you use gatsby-plugin-canonical-urls and a react-helmet canonical tagA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content. at the same time, you emit two <link rel="canonical"> tags. Pick one mechanism. (If you’re on react-helmet, gatsby-plugin-react-helmet-canonical-urls is the helmet-aware option; on the Head API, set the canonical there and drop the plugin.)

Trailing slashes. Gatsby pages can be reachable with and without a trailing slash, and Gatsby’s <Link> component uses client-side History API routing — which bypasses server-side 301 redirectsA 301 redirect is the HTTP status code for a permanent move: it tells browsers and search engines a URL has moved for good, and it's the strongest signal for consolidating a page's ranking signals onto the new URL. Google says permanent redirects don't cause a loss in PageRank. you’d normally use to normalize trailing slashes. Decide on one form, enforce it at the host/CDN level, and keep canonicals consistent with it.

Image SEO: gatsby-plugin-image

gatsby-plugin-image is genuinely one of Gatsby’s strengths. Two components:

  • StaticImage — for images whose path is known and hardcoded at build time.
  • GatsbyImage — for dynamic images coming from GraphQL.

What it does automatically: multiple sizes, WebP/AVIF formats, lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript., and breakpoints (750/1080/1366/1920px). It also generates placeholders (blurred, dominant color, or traced SVG) that reserve space and prevent Cumulative Layout Shift — a Core Web VitalsWeb Vitals is Google's initiative (launched May 2020) for unified page-experience quality signals. Core Web Vitals — LCP, INP, and CLS — are the subset used in ranking; the rest (TTFB, FCP, TBT, Speed Index) are diagnostic, not ranking factors. metric. Because dimensions are set, you avoid CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good., and modern formats plus lazy loading help LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good..

The one thing it does not do is write alt textAlt text is the value of the `alt` attribute on an HTML `<img>` element — a short text substitute chosen for the image's purpose and context, not a literal description of what it shows. It makes images accessible to screen-reader users and helps search engines understand images, mainly for image search.. That’s on you, every time — missing alt text on GatsbyImage is one of the most common Gatsby SEO oversights. (Migrating from the old gatsby-image package? There’s a codemod: npx gatsby-codemods gatsby-plugin-image.)

Structured data (JSON-LD)

Google’s preferred structured-data format is JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal., and the clean way to add it in modern Gatsby is via the Head API with a script tag:

export const Head = ({ data }) => (
  <script type="application/ld+json">
    {JSON.stringify({
      "@context": "https://schema.org",
      "@type": "Article",
      "headline": data.post.title,
    })}
  </script>
)

gatsby-plugin-next-seo offers pre-built JSON-LD components if you’d rather not hand-roll them. One frequent confusion to clear up: gatsby-plugin-manifest is not a structured-data plugin — it generates the PWA web app manifest (icons, theme color), nothing to do with schema.

The React bundle and Core Web Vitals

Here’s Gatsby’s real weakness relative to the zero-JS generators.

  • Full hydration (the Gatsby 1–4 default) hydrates the entire React tree and ships a 200KB+ React runtime to every page. The HTML is pre-rendered, so this doesn’t hurt crawlability — but it absolutely affects load speed and CWV.
  • Partial hydration (Gatsby 5, experimental) hydrates only components marked "use client" and leaves the rest as static HTML, cutting the JS shipped and directly improving TTI and CWV. The limitations are real: production builds only, still beta, and incompatible with emotion, styled-components, and gatsby-plugin-offline.

The takeaway: Gatsby’s JS payload is a performance problem, not an indexability one. Googlebot still renders JS to assess page-experience signals, so the bundle can cost you on CWV even though your content indexes fine.

Gatsby vs Astro for SEO

If you’re choosing a static framework today, this is the comparison that matters most for SEO.

DimensionGatsbyAstro
JS shipped to browser200KB+ (full React runtime)~5KB (interactive islands only)
Rendering modelSSG → SPA (full hydration)SSG → MPA (zero hydration by default)
Build speed (40 pages)2–3 minutesUnder 10 seconds
SEO plugin ecosystemMature (gatsby-plugin-*)Growing
Crawl-budget impactHigher (more JS for Google to render)Lower
Framework futureUncertain (Netlify ownership, slowed activity)Active, growing

Both pre-render indexable HTML — that’s a wash. The difference is the JS tax: Astro’s islands ship a fraction of the JavaScript, which a Vaihe comparison frames as “Reduced JavaScript execution conserves crawl budgetThe number of URLs an engine will crawl in a timeframe. and accelerates page scanning.” (One historical caveat on the other side: Astro’s image handling lacked automatic width/height at the time of that comparison, which produced LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. warnings — check current Astro docs, as it may be resolved.)

For context on how the whole field compares, see the static site generatorsA build tool that pre-renders every page into static HTML files at deploy time, so the server delivers complete HTML without executing code per request — eliminating JavaScript rendering delays for search engine crawlers. hub.

The honest part: Gatsby’s maintenance trajectory

I won’t sugarcoat this, and I won’t catastrophize it either.

Netlify acquired Gatsby Inc. in February 2023. Gatsby Cloud was sunset and customers were moved to Netlify; Netlify stated the acquisition would “not impact Gatsby JS.” Since then, activity has slowed markedly. A widely-read community GitHub discussion (#39062) argues Gatsby is effectively abandoned — minimal commits, no React 19 support, a 2024 roadmap that wasn’t delivered, and the telemetry service shut down. Maintainers have framed the current state as security fixes, limited dependency updates, and low-hanging-fruit bug fixes.

What that means for SEO teams. For an existing Gatsby site, none of this is an emergency — it builds, it indexes, it works. The risk is ecosystem decay over time: SEO depends on plugins (gatsby-plugin-sitemap, image, canonical-urls), and aging plugins (e.g. gatsby-source-shopify facing API deprecation) can eventually break in ways that quietly degrade indexing. For a new project, weigh that seriously — the frameworks people are migrating to are Astro and Next.js.

Production checklist: verify every rendering path

A local gatsby develop session or even a clean gatsby build log doesn’t prove what a crawler actually receives. Because SSG, DSG, SSR, and client-only routes each generate HTML differently, check production behavior per path rather than assuming one representative page covers all of them:

  • Raw HTML content. For each rendering path in use, fetch a real production URL with curl -s <url> or view-source: — not DevTools — and confirm the content, title, and meta tags a crawler would see are actually there.
  • Metadata (Head export output). Confirm the Head export’s tags land in that raw HTML for the path in question. This is where DSG/SSR differ most from SSG: the tags exist in your source either way, but only a production fetch proves they made it into the response.
  • HTTP status. Check the response status code on production, especially for SSR and DSG routes — a page that renders fine locally can 500 in production on first request or under load in ways a build never surfaces.
  • Caching behavior. SSG output is a static file with predictable caching. DSG caches after the first request — confirm the second request is fast and correct, not just the first. SSR responses depend on your caching headers and hosting layer; verify stale or per-request content isn’t served to the wrong visitor.
  • Failure and empty-state behavior. For SSR and DSG pages backed by request-time or first-request data, check what a crawler sees if that data fetch fails or returns empty — an unhandled error state is not the same page you tested locally with good data.
  • Sitemap generation and exclusions. Re-confirm this only happens on a production build (gatsby build && gatsby serve, never gatsby develop), and that the exclusions you expect — drafts, client-only routes, anything you decided shouldn’t be listed — are actually absent from the generated sitemap-index.xml, not just absent from your intent.

None of this is optional per rendering path — a working gatsby build proves SSG output, not DSG, SSR, or client-only behavior.

Common Gatsby SEO mistakes

  1. Still using gatsby-plugin-react-helmet — legacy; migrate to the Head API.
  2. Meta tags in DevTools but not in page source — the SEO component is rendering client-side; check view-source:, not DevTools.
  3. Draft content in sitemaps — filter drafts in gatsby-node.js with GraphQL, not in a React component.
  4. Orphan pagesAn orphan page is a page on your site that no other page links to internally. Because crawlers discover pages by following links, an orphan page is effectively invisible to search engines unless it's in an XML sitemap or linked from an external site. from src/pages — Gatsby auto-routes everything there; stale files build and land in the sitemap.
  5. Double canonical tagsgatsby-plugin-canonical-urls + react-helmet both firing.
  6. Trailing-slash inconsistency<Link> client-routing bypasses server-side trailing-slash redirectsA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't..
  7. Not stripping query strings from canonicals — set stripQueryString: true.
  8. Alt text omitted on GatsbyImage — it isn’t auto-generated.
  9. Submitting /sitemap.xml — the real file is /sitemap-index.xml.
  10. Testing the sitemap in gatsby develop — it only generates on gatsby build.
  11. NoindexNoindex is a directive that tells search engines to keep a page out of their index, so it won't appear in search results. It works only on pages a crawler can actually fetch — a page blocked in robots.txt can never be noindexed. toggled by React state — Google may have already processed the raw HTML; and when it sees noindex in raw HTML it may skip rendering entirely. Keep noindex decisions in static HTML or server headers.

For the JavaScript-rendering fundamentals behind all of this, see the parent JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. hub.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.