All fix guides
CriticalAI & Answer Engines

How to Fix Content Invisible to AI Crawlers

Your audit flagged js_dependent_content: the page's main text only appears after JavaScript runs in the browser. Many crawlers, including most AI answer engines, fetch the raw HTML and never execute that JavaScript, so they see an empty or skeletal page. The fix is to deliver your real content in the initial HTML response using server-side rendering, static generation, or prerendering.

What this means

The meaningful content of your page (headings, body copy, product details, answers) is not present in the HTML your server sends. The browser downloads a near-empty shell, then JavaScript fetches data and builds the DOM client-side. This is the default behavior of client-side-rendered single-page apps built with React, Vue, or Angular when they are not configured for server rendering.

To confirm it, look at the raw HTML rather than the rendered page. Right-click and choose "View Page Source" (this shows the initial HTML, not the live DOM), or run curl -A "Mozilla/5.0" https://yoursite.com/page from a terminal. If your article text, product name, or answer copy is missing and you only see something like <div id="root"></div> plus a bundle of script tags, the content is JavaScript-dependent.

Googlebot can render JavaScript in a second pass, so this is not always fatal for classic Google indexing. But that render step is queued, delayed, and resource-limited, and most other crawlers, including most AI answer engines, do not render JavaScript at all.

Why it matters

Two different audiences break when content is JS-dependent, and the AI one is the bigger emerging risk.

For classic Google ranking: Googlebot crawls the raw HTML first, then queues the page to render its JavaScript. That render can be delayed and is not guaranteed to run promptly on large or low-priority sites. If a page relies on client-side data fetches that fail, time out, or depend on user interaction, the rendered content may never be indexed. Internal links injected by JavaScript can also be missed, which starves the rest of your site of crawl discovery.

For AI answer engines: this is where JS-dependent content fails hardest. The crawlers behind ChatGPT (GPTBot, OAI-SearchBot), Perplexity (PerplexityBot), and Anthropic (ClaudeBot), plus most retrieval pipelines, fetch raw HTML and do not run a full browser render. If your answer only exists after JavaScript runs, these systems receive a blank page, cannot extract your content, and cannot cite you. As AI assistants increasingly sit between users and websites, being invisible to them means being left out of the answer. Severity is critical because the content is effectively unreadable to a large and growing share of automated readers.

How to fix it

  1. 1

    Confirm the content is missing from the raw HTML

    Verify the problem before changing anything. Open View Page Source (not DevTools Inspect, which shows the post-JS DOM) and search for a sentence from your visible content. Or run curl -A "Mozilla/5.0 (compatible; Googlebot/2.1)" https://yoursite.com/page and check whether your body text is in the response. In Google Search Console, use URL Inspection and click "View crawled page" to see the exact HTML Googlebot received. If the text is present in all three, you may only have a partial issue in specific components rather than a site-wide one.

  2. 2

    Switch to server-side rendering (SSR) or static generation (SSG)

    The durable fix is to render HTML on the server so content ships in the initial response. In Next.js, use the App Router (Server Components render on the server by default) or getServerSideProps / getStaticProps in the Pages Router. Nuxt ships SSR by default, so confirm you have not set ssr: false. For Angular, enable the built-in SSR option (Angular Universal). Static generation is ideal for content that does not change per request, such as blog posts, docs, and marketing pages, because every route becomes a fully formed HTML file.

  3. 3

    Use prerendering if you cannot rewrite the app

    If a full SSR migration is not feasible, add a prerendering layer that runs a headless browser, captures the fully rendered HTML, and serves that snapshot to crawlers. Build-time options like prerender-spa-plugin generate static HTML for known routes; runtime services like Prerender.io do it on demand. Serve the same rendered HTML to all clients where possible. If you serve snapshots only to bots, make sure the bot version matches what humans see exactly, or you risk cloaking penalties.

  4. 4

    Keep primary content out of interaction-gated components

    Content behind clicks, hovers, infinite scroll, or tabs that only fetch on interaction stays invisible to crawlers even after JS runs, because crawlers do not click. Render your main copy, headings, and answers into the page markup on load. Accordions and tabs are fine visually as long as the underlying text exists in the DOM (ideally the server HTML) from the start rather than being fetched only when a user opens them. Do not lazy-load the main article body.

  5. 5

    Ship real links and structured data in the server HTML

    Make sure internal links exist as real <a href> elements in the server response, not as JavaScript click handlers, so crawlers can follow them to the rest of your site. Add JSON-LD structured data (Article, Product, Organization, and similar) directly in the server HTML as well. Schema is a strong machine-readable signal for both Google rich results and AI engines that summarize your page. Do not inject schema client-side only, or non-rendering bots will miss it.

  6. 6

    Re-test and request reindexing

    After deploying, re-run the raw-HTML check with curl and View Page Source to confirm your content is now in the initial response. In Search Console URL Inspection, click "Test Live URL" to confirm Google sees the content, then request indexing. Re-run your SEO/AI-visibility audit to confirm the js_dependent_content flag clears. For AI crawlers specifically, spot-check by fetching the URL with a plain HTTP client (no browser) and verifying the answer text is present.

Example

// app/blog/[slug]/page.jsx  (Next.js App Router — Server Component by default)

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  return { title: post.title, description: post.excerpt };
}

export default async function BlogPost({ params }) {
  // This runs on the server. The HTML sent to the crawler already
  // contains the heading and body, so no client-side fetch is needed.
  const post = await getPost(params.slug);

  return (
    <article>
      <h1>{post.title}</h1>
      {/* JSON-LD in the server response — readable by Google and AI engines */}
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          __html: JSON.stringify({
            "@context": "https://schema.org",
            "@type": "Article",
            headline: post.title,
            author: { "@type": "Person", name: post.author },
            datePublished: post.publishedAt,
          }),
        }}
      />
      <div dangerouslySetInnerHTML={{ __html: post.bodyHtml }} />
      {/* Real anchor tag so crawlers can follow it */}
      <a href={`/blog/${post.nextSlug}`}>Next article</a>
    </article>
  );
}

Next.js App Router: content rendered on the server so it ships in the initial HTML. Fetching happens server-side, so crawlers and AI bots receive fully formed markup with no JavaScript required.

Platform-specific steps

WordPress

Standard WordPress themes render content server-side in PHP, so most WordPress sites are unaffected. This issue shows up in headless WordPress, where a client-side React or Vue front end pulls from the REST or GraphQL API. Fix it by rendering that front end with Next.js (SSR/SSG) or Nuxt instead of a pure client-side app. If a page builder lazy-loads sections via JavaScript, confirm the main content is not gated behind interaction or delayed fetches.

Shopify

Classic Liquid themes are server-rendered, so product and collection copy ships in the HTML. Risk appears with custom headless storefronts (Hydrogen) or heavy app-injected content. Hydrogen supports SSR out of the box, so avoid disabling it. For apps that inject reviews, descriptions, or specs client-side, confirm that text also exists in the raw HTML, not only after the app's script runs.

Wix / Squarespace

Both platforms server-render page content by default, so core text is usually visible to crawlers. Problems arise mainly with custom code blocks or third-party embeds that build content with JavaScript. Keep primary copy in native page elements rather than custom JS widgets, and verify any embedded content appears in View Page Source.

React / Vue / Angular SPA (raw)

This is the most common source of the issue. A Create React App or Vite SPA with only <div id="root"></div> in index.html ships zero content to crawlers. Migrate to a server-rendering framework: Next.js for React, Nuxt for Vue, or Angular's SSR support for Angular. If a rewrite is not possible, add build-time prerendering (prerender-spa-plugin) or a runtime prerender service (Prerender.io) to serve static rendered HTML for your key routes.

Free tool
Check this with the Bot-Eye View

Frequently asked

Doesn't Google render JavaScript now, so this doesn't matter?

Google can render JavaScript, but it does so in a delayed second pass that is queued, resource-limited, not guaranteed on every page, and prone to failure if client-side data fetches time out. More importantly, the AI crawlers behind ChatGPT, Perplexity, and Claude generally do not run a full browser render at all. They read raw HTML. So even where Google eventually sees your content, AI crawlers may never see it. Server-rendering solves both problems at once.

How do I check if my content is invisible to AI crawlers specifically?

Fetch your page with a plain HTTP client that does not execute JavaScript, which mimics how most AI crawlers behave. Run curl -A "Mozilla/5.0" https://yoursite.com/page and read the response, or use any "view raw HTML" tool. If your headings, body copy, and answers are absent and you only see an empty root div plus script tags, AI crawlers see the same blank page. The raw HTML is the ground truth for what non-rendering bots can read.

Is a React or Vue SPA always bad for SEO?

Not inherently, but a pure client-side SPA with no server rendering is the most common cause of this issue. The fix is not to abandon your framework; it is to enable its server-rendering mode. Next.js, Nuxt, and Angular's SSR support let you keep your existing codebase while shipping real HTML to crawlers. If you cannot migrate, add a prerendering layer to serve static snapshots of your key routes.

What is the difference between SSR, SSG, and prerendering?

SSR (server-side rendering) builds the HTML on the server for each request, which suits personalized or frequently changing pages. SSG (static site generation) builds HTML at deploy time into static files, which is fastest and ideal for content that is the same for everyone, like blog posts and docs. Prerendering is a bolt-on where a headless browser captures rendered HTML and serves that snapshot, useful when you cannot rewrite an existing SPA. All three achieve the same goal: real content in the initial HTML response.

Will fixing this get my content cited by ChatGPT or in AI Overviews?

It is a prerequisite, not a guarantee. If AI crawlers cannot read your content, you cannot be cited, so making content visible in raw HTML removes the hard blocker. Getting cited also depends on content quality, giving direct answers to questions, clear structure, and machine-readable signals like JSON-LD. But none of that matters if the crawler receives a blank page first, which is why clearing this critical issue comes before other AI-visibility work.

Does your site have this issue?

Run a free, AI-powered audit and we’ll flag this and 150+ other checks in about a minute. No signup.

No signup needed. Results in under 60 seconds.

Related fixes