AEO Guide — React
AEO for React
Pure client-side React apps have an AEO problem: crawlers often see an empty <div id="root"> instead of your content. This guide covers both pre-rendered React (Vite SSG, Remix, Gatsby) and workarounds for CSR-only apps.
What is AEO for React? AEO for React requires server-side rendering or static generation so AI crawlers see your content in the initial HTML. Use frameworks like Next.js, Remix, or Gatsby, or add pre-rendering to Vite with vite-plugin-ssr. Then add JSON-LD via react-helmet-async or direct script tags, serve llms.txt from /public, and use semantic HTML elements.
The 5 AEO fixes for React
Step 1
Check if your React app renders HTML to crawlers
Run `curl -sL https://yoursite.com | grep -o "<h1"` — if you don't see <h1>, your content is client-rendered and AI crawlers can't see it. Same test for your key content. If empty, move to step 2.
Step 2
Add pre-rendering (SSG) to your Vite/CRA app
Install vite-plugin-ssr or switch to a framework with built-in SSG (Next.js, Remix, Astro). For Create React App, use react-snap or migrate to Vite + vite-plugin-ssg.
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import ssr from 'vite-plugin-ssr/plugin'
export default defineConfig({
plugins: [react(), ssr({ prerender: true })],
})Step 3
Inject JSON-LD with react-helmet-async
Use HelmetProvider + Helmet to add JSON-LD script tags that render into the static HTML during pre-rendering.
import { Helmet } from 'react-helmet-async'
export function FAQSection({ faqs }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map(f => ({
'@type': 'Question',
name: f.q,
acceptedAnswer: { '@type': 'Answer', text: f.a },
})),
}
return (
<>
<Helmet>
<script type="application/ld+json">
{JSON.stringify(jsonLd)}
</script>
</Helmet>
{/* FAQ UI */}
</>
)
}Step 4
Use semantic HTML in components
Replace <div> wrappers with <main>, <article>, <section>, <header>, <footer>. This is pure HTML — no library needed. React JSX supports all HTML5 semantic tags directly.
Step 5
Drop llms.txt in the public folder
Create public/llms.txt (or static/ in some setups). Vite, CRA, Remix, and Gatsby all serve this at the site root. Verify at yoursite.com/llms.txt after deploy.
Why React needs AEO
- Pure CSR React apps are invisible to most AI crawlers — they see an empty div
- Google crawlers render JS, but ChatGPT, Perplexity, and Claude often don't
- SSG / SSR solves this with zero runtime cost — same static hosting
- react-helmet-async renders into pre-rendered HTML so JSON-LD is visible to crawlers
- Semantic HTML (<main>, <article>) works in React out of the box
React AEO FAQ
Can pure client-side React apps do AEO?
Not well. Most AI crawlers don't execute JavaScript. You need server-side rendering, static generation, or pre-rendering for your content to be visible to ChatGPT, Perplexity, and Claude.
Is Next.js or Remix better for AEO?
Both work. Next.js has the Metadata API and App Router; Remix has nested routes and meta exports. For AEO specifically, either framework's SSG/SSR output is equivalent — structured data in static HTML.
Does react-helmet or react-helmet-async support JSON-LD?
Yes. Use <script type="application/ld+json">{JSON.stringify(data)}</script> inside a Helmet component. It renders into the HTML head during SSR/SSG.
How do I test if AI crawlers can see my React content?
curl -sL yoursite.com and check if your H1, paragraphs, and schema appear. If the response is mostly an empty <div id="root">, crawlers can't see your content — add SSG or SSR.
Check your React site's AEO score
Free scan. See which AEO checks your React site passes and fails in seconds.