We use cookies. Privacy Policy

    PageGlass - JavaScript SEO Rendering for React & Vue Sites

    Gatsby SEO: when the static build isn't enough

    Gatsby builds static HTML at compile time, which is great for blog posts. The trouble starts on routes that fetch data at runtime - product detail pages, search results, anything with Apollo Client - because crawlers see the empty build output, not the resolved page.

    This is a known problem, and the fix is simpler than you think.

    100+ bots supportedPre-rendered by PageGlassFive-minute setupBuilt on Cloudflare's edge
    Paste your Gatsby site's URL above to see what Googlebot gets from the static build before any client-side data arrives.

    Don't want an external tool? We understand.

    Migrating off Gatsby to Next.js or moving every dynamic data source into the build-time GraphQL layer fixes the underlying issue properly. PageGlass renders the dynamic routes that don't fit the static-build model and serves the result to bots with no code change.

    Fix this in three steps

    1. Run a free Gatsby scan. Confirm the bot visibility gap caused by Gatsby client-side data fetching - the scan takes ten seconds and needs no signup. You get exactly what Googlebot, Bingbot, and the AI crawlers see when they hit your URLs today, side by side with what your users see.
    2. Add one CNAME record. Point your Gatsby site's domain through PageGlass in your DNS provider. The change takes thirty seconds and is fully reversible. Zero code changes, no deploy, no impact on the bundle your real users download.
    3. Gatsby content is now indexable. Bot traffic now receives fully-rendered HTML for every URL on your Gatsby site, while human visitors keep getting the exact same dynamic experience as before. Come back to PageGlass and run the scan again to confirm the fix.

    Why Gatsby's "static" promise has cracks

    Gatsby's pitch is that every page is pre-rendered to HTML at build time, which makes the framework look perfectly SEO-friendly. That's true for the routes whose data lives entirely in the build-time GraphQL layer - Markdown content, headless CMS feeds, contentful entries, and so on.

    The cracks appear when teams use Gatsby as the frontend for an external API. Apollo Client, runtime fetch calls, and user-driven search pages all bypass the GraphQL build pipeline. The HTML in public/ for those routes is just the layout shell. Googlebot reads that shell on first crawl, finds no real content, and either defers indexing or moves on entirely.

    Common Gatsby fixes that miss the point

    • Adding more pages to gatsby-node.js. Helps if those pages can be generated from build-time data. If your pages need runtime inputs, this just creates empty shells faster.
    • Using react-helmet inside an Apollo-driven component. The Helmet tags update after the runtime fetch resolves, which is too late for crawlers reading the initial HTML.
    • Relying on Google's web rendering service to fill the gap. WRS sometimes runs JavaScript and updates the index later, sometimes days later, sometimes not at all. Other crawlers (Bingbot, GPTBot, ClaudeBot, the social card fetchers) don't run JavaScript at all. Designing around WRS is designing for the most generous crawler.

    What actually works

    Three paths: (1) move every data source into the build-time GraphQL layer using a source plugin, which works for stable data and is the official Gatsby answer; (2) adopt Deferred Static Generation for routes that genuinely change, accepting the cold-start cost; or (3) front Gatsby with PageGlass, which detects bot user-agents at the edge, runs any runtime fetches in a headless browser, and serves the resolved HTML to crawlers - while human visitors keep the same dynamic experience.

    Related resources

    Frequently asked questions