Single Page Apps serve <div id="root"></div> to AI crawlers. No content, no citations. We migrated HomeCalc.ca from SPA to SSG in one commit and watched Bing Copilot citations jump from ~20/day to ~200/day within 48 hours.
I found this on my own product (HomeCalc.ca) before any tool flagged it. The AI Visibility Audit I run for clients catches structural issues like this — the kind a dashboard will never tell you about — and ships a prioritized 7-day fix plan. See the AI Visibility Audit →
When a user visits your React SPA, their browser downloads a JavaScript bundle, executes it, and renders the page. They see your content, your calculators, your FAQ sections — everything works. But that’s not what AI crawlers see.
AI crawlers — Bing’s indexer (which feeds Copilot), Perplexity’s crawler, ChatGPT’s browse mode — request your URL and read the raw HTML response. They don’t execute JavaScript. For a standard React SPA built with Create React App or Vite, the HTML they receive looks like this:
<!DOCTYPE html>
<html>
<head>
<title>HomeCalc - Mortgage Calculator</title>
</head>
<body>
<div id="root"></div>
<script src="/assets/index-4a8f2b.js"></script>
</body>
</html>That’s it. An empty div. No headings, no paragraphs, no calculator results, no FAQ answers, no structured data in the body. Your 68 pages of content? Invisible. Your schema markup that JS injects? Never rendered.
Google is the exception — Googlebot has a full rendering pipeline (Web Rendering Service) that executes JavaScript. But even Google queues JS rendering, which means your content is indexed with a delay. Every other major AI crawler? They get the empty div and move on.
HomeCalc.ca is a Canadian mortgage calculator site with 68 routes — land transfer tax calculators, mortgage payment tools, CMHC insurance calculators, and more. Each page has substantial content: calculations, explanations, FAQ sections, and structured data.
Before May 22, 2026, HomeCalc was a plain SPA built with React + Vite. The site worked perfectly in browsers. Users could calculate mortgage payments, compare scenarios, see results — everything rendered client-side after the JavaScript bundle loaded.
But Bing’s crawler saw 68 pages of <div id="root"></div>. Copilot had almost nothing to cite. Perplexity had nothing to index. The site existed for humans and was invisible to machines.
The numbers told the story:
Bing impressions: 0–10 per day baseline
Pages cited by AI: 4 out of 68
Content visible to crawlers: None (empty body)
On May 22, 2026, we pushed commit 47c5c55 — a migration from plain Vite SPA to SSG (Static Site Generation) using vite-react-ssg.
What changed: instead of shipping an empty HTML shell with a JS bundle, the build process now pre-renders every route at build time. Each of the 68 pages gets its own complete HTML file — with headings, paragraphs, calculator descriptions, FAQ answers, structured data, everything — before a single line of JavaScript runs.
The user experience didn’t change at all. React still hydrates and makes the page interactive. Calculators still work. But now the HTML that crawlers receive contains the full content.
What the HTML looks like after SSG
<!DOCTYPE html>
<html>
<head>
<title>Ontario Land Transfer Tax Calculator</title>
<script type="application/ld+json">
{ "@type": "FAQPage", ... }
</script>
</head>
<body>
<div id="root">
<h1>Ontario Land Transfer Tax Calculator</h1>
<p>Calculate your land transfer tax for any
Ontario property purchase...</p>
<div class="calculator">...</div>
<section class="faq">
<h2>How is Ontario land transfer tax calculated?</h2>
<p>Ontario land transfer tax uses a graduated
rate structure based on the purchase price...</p>
</section>
</div>
<script src="/assets/index-4a8f2b.js"></script>
</body>
</html>Same page, same URL, same user experience. But now Bing, Copilot, Perplexity, and every other crawler sees the actual content on first request.
The commit shipped May 22 at 14:34 EDT. Bing re-crawled the site. The propagation lag from Bing’s index to Copilot’s citation engine was approximately 48–60 hours. By May 24, the numbers shifted:
10× citation growth in 48 hours — not from new content, not from backlinks, not from any marketing effort. The same 68 pages, the same content, the same domain authority. The only difference: the HTML now contained the content instead of an empty div.
The number of distinct pages being cited by AI went from 4 to 16+ — a 4× expansion of the “citation surface area.” Pages that had existed for months were suddenly discoverable because they were finally readable.
This isn’t a theoretical risk. According to the 2026 State of JS survey, React + Vite is the most popular frontend stack for new projects. Vite’s default React template produces a pure SPA. Create React App (still widely used in production) produces a pure SPA. If you followed the default setup path for either tool, your site is an SPA right now.
Next.js, Remix, and Gatsby default to SSR or SSG — but only if you use them. A significant portion of React sites in production are still plain SPAs, especially tools, calculators, dashboards, and internal products that were later made public.
The insidious part: everything works in your browser. Your users see the content. Your QA passes. Google eventually renders and indexes it (with delays). The only thing broken is AI visibility — and if you’re not specifically measuring AI citations, you have no signal that 80% of AI crawlers can’t see your site.
We wrote about a related bug where FAQ accordion components hide content from the DOM. That bug affects SSG/SSR sites — the accordion strips content after the server renders it. The SPA problem is worse: there’s no content to strip because the server never rendered it in the first place.
Both the SPA problem and the accordion bug are instances of the same principle:
Everything you want Google and AI to see must be in the HTML your server returns on first request — before any JavaScript executes.
If the content depends on client-side rendering, it’s invisible to most AI systems. If the content depends on user interaction (clicking an accordion), it’s invisible at crawl time. If the content depends on API calls that happen after page load, it’s invisible.
The fix is always the same: inline the content in the server-rendered HTML.
Accordion forceMount fix: FAQ answers were empty. Inline the answers in HTML.
API-dependent content: Data loads after JS. Fetch at build time and inline in HTML.
Step 1: Check what crawlers see
curl -s https://your-domain.com/ > page.htmlOpen page.html in a text editor. If the <body> contains only a root div and script tags — no headings, no paragraphs, no content — you have an SPA problem.
Step 2: Pick your migration path
React + Vite (our case): Use vite-react-ssg or vite-plugin-ssr. Minimal code changes — mostly configuration. Our migration was a single commit.
Create React App: Migrate to Next.js (SSG/SSR by default) or add react-snap for prerendering. Next.js migration is more work upfront but gives you the full SSG/SSR toolkit.
Next.js / Remix / Astro: You probably already have SSG or SSR. Verify by running the curl test above. If your pages render full HTML, you’re fine.
Vue / Svelte / Angular:Same principle applies. Nuxt (Vue), SvelteKit (Svelte), and Angular Universal all provide SSG/SSR. The framework doesn’t matter — what matters is that the HTML contains content before JS runs.
Step 3: Verify after deploy
After deploying your SSG/SSR migration, run the curl test again. The HTML should now contain your actual page content. Submit the updated pages in Google Search Console and Bing Webmaster Tools for re-crawling. Expect AI citation improvements within 48–72 hours as crawlers re-index the new HTML.
Is your site invisible to AI crawlers?
The audit checks what ChatGPT, Perplexity, Copilot, and Google AI Overviews actually see when they crawl your site — including rendering issues, schema mismatches, and content gaps competitors are exploiting.
Book an AI Visibility Audit →After this experience, we established a rule for every new venture:
Day 0 of any new project: ship SSG or SSR. Never plain SPA.
The cost is a few hours of configuration at project start. The downside of skipping it is 3–6 months of invisible content before someone notices that AI crawlers can’t read the site. By then, you’ve lost months of potential citations — citations your competitors were accumulating while your pages served empty HTML.
If you’re building a dental clinic site, a real estate tool, a SaaS landing page, a calculator, a directory — anything that should be found by AI — the first commit should set up SSG or SSR. Everything else can iterate. This can’t.
Can AI crawlers render JavaScript like Google does?
No. Google has a full rendering pipeline (Googlebot + WRS) that executes JavaScript, though with delays. AI crawlers — Bing/Copilot, ChatGPT's browse mode, Perplexity — have limited or no JS execution. They rely on the raw HTML your server returns. If that HTML is an empty <div id="root"></div>, they see nothing.
What's the difference between SSG and SSR for AI visibility?
Both produce full HTML on first request, so both solve the empty-body problem. SSG (Static Site Generation) pre-builds HTML at build time — fastest response, best for pages that don't change per-request. SSR (Server-Side Rendering) generates HTML on each request — better for personalized or real-time content. For AI visibility, either works. The critical thing is that the HTML contains your content before any JavaScript runs.
Does this affect Google rankings too, or just AI citations?
Google can render JavaScript, so SPAs aren't invisible to Google the way they are to AI crawlers. However, Google's rendering queue introduces delays — your content may take days or weeks to be fully indexed. SSG/SSR pages are indexed faster and more reliably. For AI Overviews specifically, Google pulls from its rendered index, so the delay matters less — but the speed advantage of SSG/SSR still helps with freshness signals.
How long does the SPA to SSG migration take?
For a React + Vite project, we used vite-react-ssg and the migration took under a day. For Next.js, SSG is the default — you may already have it. For Create React App, you'll need to migrate to Next.js, Remix, or add a prerendering step. The actual code changes are small; the complexity is in routing and data fetching patterns.
Should I use SSG for every new project from now on?
Yes. Our rule after this discovery: Day 0 of any new venture, ship SSG or SSR. Never plain SPA. The cost is a few hours of setup. The downside of not doing it is 3–6 months of invisible content before you realize AI crawlers can't see your site. That's months of lost citations you can never recover.
For the full HomeCalc story — from near-zero to 7,400+ AI citations in 3 months — read the case study. For the related accordion bug that hides FAQ content from the DOM, see The Silent SEO Bug Hiding in Your React FAQ Accordion.
Hami Tahm is an AI visibility consultant based in Toronto.