Content readable without JavaScript
Your page's main content - the paragraphs, headings, tables, and prices a visitor came for - must be present in the HTML your server returns on the first request. Enhancement by is fine. Content that only appears after JavaScript runs is invisible to most AI crawlers, and therefore invisible to the assistants that cite from them.
Throughout this page, suppose Fernwood rebuilt its marketing site as a single-page app. In a browser it looks complete. View-source shows a nearly empty <div id="root"></div>. That empty shell is what GPTBot, ClaudeBot, PerplexityBot, and similar crawlers receive.
Why it works
Traditional search engines largely solved this: Google renders JavaScript before indexing. Answer engines have not. The crawlers that feed ChatGPT, Claude, Perplexity, and similar systems typically fetch the raw HTML response and stop - they do not wait for your framework to hydrate, do not execute your bundle, and do not follow client-side routes. Silktide's own crawl comparison (rendered page vs. raw HTML) is built on exactly that behavior; see Content without JavaScript.
The failure mode is silent and total:
- A page that ranks well in Google can be completely absent from AI answers, because the assistants never received the text.
- Every other AEO investment on that page - structured data, machine-readable dates, answer-first writing - is worthless if the crawler never sees the content those signals describe.
- Human visitors on failed or blocked scripts see the same empty shell, and first contentful paint suffers even when scripts eventually succeed.
This is a site architecture problem, not a page-editing problem. Fixing one URL by hand does not fix the template that produces the next hundred.
How to check what a crawler sees
Before changing anything, confirm the problem. Three ways, strongest first:
- Silktide's check. Content without JavaScript compares the meaningful body text of the rendered page against the raw HTML captured at crawl time. It flags pages where the raw text is both under ~10% of the rendered text and tiny in absolute terms - a genuine empty shell, not a page that merely enhances itself.
- View source, not DevTools Elements. In the browser, "View Page Source" shows what the server sent. The Elements panel shows the DOM after JavaScript ran. If your article text is in Elements but absent from View Source, crawlers that skip JS will not see it.
- Fetch without a browser. From a terminal:
curl -sL https://fernwood.example/pricing | head. Or use a text-only browser. If the pricing table is missing from that output, it is missing from the crawler too.
Also confirm the crawler is allowed in at all - a perfect HTML response is useless if robots.txt blocks the AI crawler, or a firewall blocks it in practice (AI crawlers blocked in practice).
How to fix it
Pick the approach that fits your stack. All three produce the same outcome: the first HTML response contains the content.
1. Server-side rendering (SSR)
The server renders each page to HTML on request; JavaScript then hydrates for interactivity. This is the default path for frameworks that already support it:
- Next.js - use the App Router with Server Components, or
getServerSideProps/getStaticPropsin the Pages Router. Do not ship a client-only root that fetches content after mount. - Nuxt - universal / SSR mode (the default), not
ssr: false. - Remix, SvelteKit, Astro (SSR mode), and equivalents - same idea: the document response includes the body text.
The rule of thumb: if a useEffect / onMounted fetch is what puts the article on the page, move that data fetch to the server.
2. Static site generation (SSG)
Pre-build pages as plain HTML at publish time. Ideal for content that does not change per visitor - blog posts, docs, marketing pages, pricing. Astro, Eleventy, Hugo, Next.js output: 'export', and Nuxt generate all produce files a crawler can read with no JavaScript at all.
SSG is usually the cheapest win for marketing and content sites: no per-request render cost, and the HTML on disk is exactly what the crawler gets.
3. Pre-rendering as a bridge
If you cannot change frameworks yet, a pre-rendering service or build step can serve a rendered HTML snapshot to crawlers (and often to first-time visitors) while the SPA continues to run for interactive sessions. Treat this as a bridge, not a destination: snapshot freshness, cache invalidation, and authenticated routes all become their own maintenance burden. Prefer fixing the render mode when you can.
Google's own guidance on JavaScript SEO and web.dev's Rendering on the Web cover the same spectrum - SSR, SSG, and progressive enhancement - from the search-engine side of the problem.
What must be in the first HTML
Not every pixel. The content a citation would quote:
- The article or page body - headings, paragraphs, lists, tables.
- Prices, limits, and other facts you want assistants to repeat.
- Structured data in a
<script type="application/ld+json">block in the initial HTML - JSON-LD injected only after hydration is as invisible as the prose. - Canonical URL, title, and meta description in
<head>.
JavaScript can still own menus, personalization, charts that enhance an already-present table, and progressive features. Silktide's check is deliberately lenient about enhancement: pages that serve their main content as HTML and layer behavior on top pass.
Common failure patterns
- Client-only SPAs - Create React App, Vite SPAs, and similar setups that ship an empty shell and fetch routes in the browser. The fix is SSR/SSG, not more client code.
- Content behind "Load more" or tabs that never appear in HTML. If the only way to reach section three is a click that fetches it, crawlers never reach section three. Prefer real URLs or include the content in the initial response.
- "It works in Google, so we're fine." Googlebot rendering is not a substitute for AI-crawler readability. Passing Google and failing GPTBot is a common, invisible split.
- Blocking the crawler and blaming JavaScript. Always check AI crawler access and effective reachability alongside this technique.
How Silktide helps
- Content without JavaScript flags indexable pages whose raw HTML is an empty shell relative to the rendered page.
- AI crawler access and AI crawlers blocked in practice cover the related failure: the crawler never receives the HTML at all.
If Silktide cannot read your content without JavaScript, neither can the assistants you want citing you.
Related
- Content without JavaScript - the Silktide check
- AI crawler access policy - allow the crawler in before worrying about what HTML it receives
- AI crawler access
- Page speed and Core Web Vitals - client-only rendering often hurts both crawler readability and LCP
- llms.txt - optional curated index (useless if linked pages are empty shells)
- Structured data markup - also worthless if it only appears after hydration
- Answer-first page structure - once the crawler can see the page, this is how to write it
- Understand the JavaScript SEO basics (Google Search Central)
- Rendering on the Web (web.dev)