BlogFindings
Client side rendering: JavaScript supplied 7.6 percent of the prose, and all of it on 11 of 271 pages
Lantad loaded the home page of 392 hostnames twice on 20 September 2026, from the same browser at the same moment, changing one thing between the two loads: whether JavaScript was allowed to run. On the 271 pages that answered HTTP 200 both times, the unrendered document held 173,138 words and the rendered one held 187,422. The average is undramatic and the distribution is not: 100 pages were word for word identical, and 11 returned nothing readable at all until the bundle ran.
On 20 September 2026 we loaded the home page of all 392 hostnames in this repository's platform corpus twice, from one headless browser, seconds apart, over the same connection, with the same user agent, and changed exactly one variable between the two loads: whether JavaScript was permitted to execute. Everything else was held constant, including the extraction, so the difference between the two word counts is JavaScript's contribution and nothing else. That is a narrower measurement than prose parity as the scanner scores it, and it is deliberately narrower, because it answers one question cleanly instead of four questions approximately. It says nothing about what any particular crawler does with the result, which is a separate matter this blog has put to the vendors' own documentation and found mostly unanswered.
In short
- Client side rendering left 11 of the 271 home pages Lantad loaded on 20 September 2026 with zero readable words until JavaScript ran, and every one of the 11 returned real prose once it did.
- Across those 271 pages the unrendered document carried 173,138 words and the rendered one 187,422, so JavaScript supplied 7.6 percent of the prose in total, measured on 20 September 2026.
- The total hides the risk. 100 of the 271 pages returned an identical word count with JavaScript switched off, while 20 pages kept half or more of their prose behind it.
- Of the ten platform strata in this repository's committed corpus, single page app startups depended on JavaScript most, which supplied 18.3 percent of the prose across their 39 usable sites, against 0.6 percent across 25 Webflow sites.
- Structured data barely moved: 167 of the 271 pages carried a JSON-LD block before JavaScript ran and 168 after, so on nearly every site that published any, the markup was already in the document the server sent.
| Share of the rendered prose that needed JavaScript | Home pages | What a client that runs nothing received |
|---|---|---|
| None: the two word counts matched exactly | 100 | Every word the rendered page held |
| Under 10 percent | 76 | Substantially the whole page |
| 10 to 50 percent | 39 | The page, short a section or a widget |
| 50 to 90 percent | 6 | A fragment of the page |
| 90 percent or more | 14 | A shell, and on 11 of them nothing at all |
| Fewer words after rendering | 36 | More text than the rendered page held |
One variable, changed twice on the same page
The corpus is the 392 hostnames in worker/seeds/corpus-seeds-platform.json, a committed sampling frame stratified by the platform a site is built on rather than by industry, which is the stratification that exists precisely because the build tool is what decides whether text reaches a client that runs nothing. It is an editorial frame of small and mid sized sites, not a random draw from the web, so it describes itself and no wider population.
Each home page was requested at https://host/ twice by headless Chromium 141.0.7390.37 driven by playwright-core 1.63.0, once in a browser context with JavaScript disabled and once with it enabled, from one network location, identifying as LantadBot/1.0 (+https://lantad.co/bot) on both loads. Navigation timed out at thirty seconds, and after the load event each page was given a further 2.5 seconds to settle before anything was read. Text was taken as document.body.innerText on both sides, so the same rule decided what counted as a word in both captures. Holding the user agent constant matters more than choosing a realistic one: the point was to isolate JavaScript, and a page that serves a crawler something different from a browser would have contaminated the comparison with a second variable. What a site does when it sees a crawler token is measured separately, by the scanner's own crawler view.
The sample lost more hosts than we would like, and it lost them unevenly. 34 hostnames timed out with JavaScript off, 100 timed out with it on, and 25 failed both ways, which is what a thirty second budget does to pages whose load event waits on third party scripts. 283 returned on both loads and 271 answered HTTP 200 on both, and that 271 is the denominator for every figure below. The Shopify stratum effectively disappeared, returning one usable pair out of 34, so nothing here describes Shopify storefronts and the Shopify guide remains the place that does. Media and local sites returned 17 of 32 and SaaS marketing sites 18 of 39. The failures are not random with respect to the thing being measured, since the pages most dependent on scripts are the likeliest to miss a thirty second load event, which means the figures below understate JavaScript's contribution rather than overstating it. How this scanner handles the same problem in production is set out in the methodology.
Flow: 392 corpus hostnames to Load, JavaScript off; 392 corpus hostnames to Load, JavaScript on; Load, JavaScript off to Read text, links, JSON-LD; Load, JavaScript on to Read text, links, JSON-LD; Read text, links, JSON-LD to 271 usable pairs.
How much of the prose actually needed JavaScript?
In total, very little. The 271 unrendered documents held 173,138 words between them and the 271 rendered ones held 187,422, a difference of 14,284 words, which is 7.6 percent of the rendered total. The median page moved from 478 words to 522. If the question is what share of this corpus's text is unreachable without a browser, the answer is under a tenth of it, and that answer is inconvenient for anyone selling rendering as the main problem in AI visibility. It is worth stating plainly rather than burying, because a measurement that only ever confirms the pitch is not a measurement.
The shape of the distribution is a different finding from the size of the average, and it is the one that matters to any individual site. 100 of the 271 pages returned exactly the same word count both ways, which means the server had already sent every word the browser would end up showing. A further 76 gained under a tenth of their text, which is the ordinary residue of a cookie notice, a chat widget or a lazily mounted testimonial. That is 176 of 271 pages for which rendering is a rounding error.
Then the tail. 39 pages gained between a tenth and a half of their words, 6 gained between half and nine tenths, and 14 gained more than nine tenths. Twenty pages, 7.4 percent of the sample, published less than half of their own prose in the document the server sent. On 11 of those the unrendered page held no readable words whatsoever. Sixteen of the twenty had no h1 element before JavaScript ran, so the page offered no heading either. This is the same pattern we found inside a single page's markup when text in a hydration payload scored the same as no text at all, and the same one behind 17 of 380 home pages sending a crawler zero words in an earlier sweep of the industry corpus. Two different frames, two different methods, the same small group of sites that publish nothing until a bundle runs.
Payload tells the same story from the other end. The 271 unrendered documents came to 77.9 million characters and the rendered ones to 112.7 million, so the DOM roughly doubled in size while the readable text grew by a fourteenth, and the density fell from 2.2 words per thousand characters to 1.7. Shipping more to say the same amount is a habit with its own measurement here, in the 28 Next.js pages that sent fifteen times more payload than prose.
JavaScript off
- 173,138 words of readable text
- Median page: 478 words
- 77.9 million DOM characters
- 2.2 words per 1,000 characters
- 11 pages with no readable words
- 57 pages with no h1 element
JavaScript on
- 187,422 words of readable text
- Median page: 522 words
- 112.7 million DOM characters
- 1.7 words per 1,000 characters
- 0 pages with no readable words
- 39 pages with no h1 element
What does client side rendering cost you with an AI crawler?
The honest answer is that it depends entirely on the client, and that only two of the operators behind the crawler tokens this scanner evaluates have written down what theirs does. That is not a gap this measurement can fill, so here is what the two say, read at source on the day of the sweep.
Google's JavaScript basics documentation, carrying Last updated 2026-03-04 UTC, describes three phases and is explicit that the second is deferred. It states that Googlebot queues all pages with a 200 HTTP status code for rendering unless a robots meta tag or header says not to index the page, that the page may stay on this queue for a few seconds but it can take longer than that, and that once Google's resources allow, a headless Chromium renders the page and executes the JavaScript. Rendering happens, and it happens later, on a queue whose length Google does not publish. Common Crawl's FAQ is the opposite and shorter: currently, JavaScript is not executed and Cookies are not used. An archive that feeds a great many training corpora reads the document the server sent and nothing else.
The other seven operators in this scanner's registry published no position at all when we read their pages on 5 September 2026, which is the whole subject of the two of nine that say either way. Silence is not a promise to render and it is not a refusal, so a site that publishes its text only after a bundle has, for seven of nine vendors, no documented basis for expecting that text to be read. For a page you actually want quoted in an answer, the guidance on getting cited by ChatGPT starts from the document the server sends for exactly this reason.
None of that makes a framework a mistake. Both of the frameworks most often blamed here can send the words in the first response, and the fix is a configuration rather than a rewrite: the notes for React and for Next.js cover which rendering mode puts prose in the document and what each one costs. The 100 pages in this sample whose word counts matched exactly are proof that ordinary sites on ordinary stacks already do it.
| Client | Published position on executing JavaScript | Where it is written |
|---|---|---|
| Googlebot | Renders, on a deferred queue | JavaScript basics, Last updated 2026-03-04 UTC |
| CCBot | Does not execute JavaScript | Common Crawl FAQ, read 20 September 2026 |
| The other seven operators | No published position | Nine vendor pages read 5 September 2026 |
The average hides the platform, and the platform hides the site
Grouping the 271 pairs by the stratum each hostname sits in produces a spread far wider than the 7.6 percent total suggests. Single page app startups gave up the most to JavaScript, which supplied 18.3 percent of their prose across 39 usable sites. Media and local sites followed at 12.5 percent across 17, then WordPress and Framer at 9.5 percent each, SaaS marketing at 8.8 percent and the Wix and Squarespace group at 7.6 percent. At the bottom, static documentation sites needed JavaScript for 1.2 percent of their words and Webflow sites for 0.6 percent, which is close enough to nothing that it is the absence of a finding.
The Framer number deserves a note, because 9.5 percent sounds worse than the platform behaves. One site in the stratum accounts for most of it, and Framer's output is otherwise ordinary server rendered HTML, which is consistent with what we found when 35 of 36 Framer sites served markdown to a plain request. Platform averages are made of sites, and a stratum of two dozen can be moved a long way by one of them. The per stack notes for Framer and for Lovable exist because the right action is per build, not per brand.
The clearest case against reading the averages at all is the no-code stratum. Across its 35 usable sites JavaScript supplied 0.1 percent of the prose, which reads as a clean bill of health and is not one. Six of those 35 sites returned zero readable words without JavaScript, and seven of them kept half or more of their prose behind it, the highest count of any stratum in the corpus. The aggregate is near zero because a handful of text heavy sites in the same group server render several thousand words each and swamp the sum. A site owner reading the stratum average would conclude the platform is safe; a site owner in the affected six would find their home page publishing a title and nothing else. Every figure in this post is a distribution before it is an average, and this stratum is the one that proves why that distinction is not pedantry.
The markup and the links barely moved, and sometimes rendering subtracted
If JavaScript is where the text is, one might expect it to be where the machine readable markup is too. It is not. 167 of the 271 pages carried at least one JSON-LD block in the unrendered document and 168 carried one after rendering, a difference of a single site. Two pages gained their only block from JavaScript and one lost its only block to it. Nine pages carried more blocks after rendering than before, and the types that appeared only after the bundle ran were the commerce and reputation ones: AggregateRating on five pages, then Product, Rating, Review, LocalBusiness, Person and Organization on three each. Those are the shapes a review or booking widget injects. The base structured data was already in the document nearly everywhere it existed at all, which is consistent with the finding that 141 of 382 home pages carried none in the raw HTML: where markup is missing, it is usually missing outright rather than hiding behind a script.
Same host links moved almost as little. The unrendered pages offered 5,810 distinct same host links and the rendered ones 5,923, a gain of 113 across 271 pages. Twenty pages gained at least one link and fourteen lost at least one. The concentration is the same as it was for prose: 16 pages offered no same host link at all without JavaScript, and 11 of those 16 gained links once it ran, one of them going from zero to 33. For the other 255 pages the crawl graph was already complete in the first response, which matches what happened when rendering added no new crawl paths to five captured pages and dropped nine locale links in the process.
Rendering is also not monotonic, which is the result we did not expect. 36 of the 271 pages held fewer readable words after JavaScript ran than before it. Most of those losses are trivial, with a median of 4 words, and are the ordinary effect of a script collapsing an accordion or replacing a fallback. Seven pages lost 100 words or more, the largest shedding 2,183 of its 2,364 words when the bundle replaced the server rendered body with a smaller one. That failure mode has a counterpart in the markup: a page can announce headings a machine cannot use, which is what happened when an h1 inside a header element counted as no h1 at all, and it has another in the fallback that is supposed to cover exactly this case, since fourteen noscript elements on five pages held no text between them.
| Signal | JavaScript off | JavaScript on | Change |
|---|---|---|---|
| Pages carrying at least one JSON-LD block | 167 | 168 | +1 |
| Distinct same host links, all pages | 5,810 | 5,923 | +113 |
| Pages offering no same host link | 16 | 5 | -11 |
| Pages with no h1 element | 57 | 39 | -18 |
| Readable words, all pages | 173,138 | 187,422 | +14,284 |
| Pages that lost words to rendering | 0 | 36 | 5,803 words lost |
What this measurement does not say
It does not say what any named AI crawler saw, because no AI crawler was involved. A headless Chromium with a switch flipped is a model of a client that runs nothing, not a simulation of GPTBot, ClaudeBot or PerplexityBot, and the section above on what the vendors publish is the closest this post comes to that question. Anyone reading a number here as a statement about a specific bot is reading it wrong.
It does not describe the web. The corpus is an editorial frame of 392 hostnames chosen to spread across build tools, and after timeouts it describes 271 of them. The Shopify stratum is gone, the media and local stratum lost nearly half its sites, and those losses are biased towards heavy pages, so the real dependence on JavaScript in this frame is higher than 7.6 percent by an amount this method cannot recover.
It is also not identical to what a non-rendering crawler parses. A browser with JavaScript disabled still applies CSS, so innerText omits text that is hidden by a stylesheet, while a crawler reading raw bytes would find it. We checked the eleven zero-word pages against a plain HTTP GET with no browser at all, and the raw documents agreed: one of them shipped 3,787 bytes whose only readable words were the site's name and its two service lines, another 31,247 bytes carrying nine words. On those pages the two methods reach the same verdict, which is the verdict that matters, though the general caution stands for the rest of the sample. The same care applies to the extraction boundary, which is its own source of loss: deleting one main element cost 1,665 of 13,615 words on a page nobody had touched otherwise.
What it does say is narrow and worth having. Most of this corpus publishes its text in the first response, so for most site owners rendering is not the thing standing between them and being quoted. A small and identifiable minority publishes nothing at all in the first response, and for them it is the only thing that matters, because every other signal that AI visibility is made of is computed from text that has to exist first. The work is to find out which group you are in, and the answer takes one request.
-
Named AI crawlersNot measured No crawler was used. Only a browser with one switch changed, so no figure here describes GPTBot, ClaudeBot or any other bot. -
The web at largeNot measured An editorial frame of 392 hostnames stratified by build tool, reporting on the 271 that answered both loads. -
Timeout biasKnown, unrecovered 100 hosts missed a thirty second load event with JavaScript on. Heavy pages fail first, so 7.6 percent is a floor. -
CSS hidden textKnown limit innerText omits text a stylesheet hides. A raw byte parser would see it. Checked on the eleven zero-word pages, which agreed. -
Prose differenceMeasured 14,284 words across 271 pages, 7.6 percent of the rendered total, one variable changed between the two loads. -
Per site verdictMeasured Twenty pages published under half their prose in the first response, and eleven published none of it.
Lantad
Published .
Client side rendering is the arrangement where the server sends a small document and the words arrive afterwards, assembled in the browser. Whether that costs a site anything with an answer engine is usually argued rather than measured, and the argument runs in both directions: one side says every serious crawler runs a browser now, the other says none of them do. Both claims are about the crawlers. This post is about the pages, and it asks a question that can be settled with an experiment rather than an opinion. How much of a real site's text is actually behind the bundle?
Common questions
Does client side rendering stop AI crawlers reading my site?
It depends on the crawler, and only two of the nine operators behind the fifteen tokens this scanner evaluates publish a position. Google's JavaScript basics documentation, Last updated 2026-03-04 UTC, says Googlebot queues every page with a 200 status for rendering by a headless Chromium, and that the page may stay on that queue longer than a few seconds. Common Crawl's FAQ says JavaScript is not executed. The other seven said nothing when their pages were read on 5 September 2026.
How much of a typical home page needs JavaScript to be readable?
On the 271 home pages Lantad loaded twice on 20 September 2026, none of it for most of them. 100 pages returned an identical word count with JavaScript disabled and a further 76 gained under a tenth of their words from it. Across all 271 pages JavaScript supplied 7.6 percent of the prose, and the median page moved from 478 words to 522.
Which platforms depended on JavaScript most?
Single page app startups, where JavaScript supplied 18.3 percent of the prose across 39 sites measured on 20 September 2026, ahead of media and local sites at 12.5 percent. Webflow sites depended on it least at 0.6 percent. The no-code stratum averaged 0.1 percent while containing six of the eleven sites that returned no readable words at all, which is why the average is the wrong number to read.
How can I check my own site without a browser?
Request your home page with curl and read what comes back before any script runs. If the words you want quoted are in that response, a client that executes nothing can still read them. If the response is a few kilobytes containing your site name and a loading message, it cannot, and no amount of structured data or llms.txt will change that, because every other signal is computed from text that has to exist first.
See what AI can read on your site
Run a free scan and get a graded report of exactly what AI crawlers can and cannot read, with ranked fixes.