The SEO Cost of JavaScript-Only Content
If your content only exists after JavaScript runs, you are betting your search presence on a rendering step that is slower, later, and more fragile than plain HTML.
Ask a modern web developer for the source of a page and they’ll show you components, not documents. The page, as far as their code is concerned, is a program. The browser downloads a nearly empty HTML shell and a bundle of JavaScript, the JavaScript runs, and the content assembles itself in front of the visitor. This architecture won for reasons that have nothing to do with search: it makes complex interfaces tractable to build. But it changed something fundamental about what a web page is. A page used to be a thing you fetch. Now it’s often a thing you compute. And search engines were built to fetch.
The standard reassurance is that Google runs JavaScript now, and this is true. Googlebot renders pages with an up-to-date version of Chrome and can see what the script produces. If the reassurance ended the discussion, I wouldn’t be writing this. It doesn’t, for a few reasons that compound.
Rendering is expensive, so it’s rationed. Fetching HTML costs a search engine almost nothing; executing a JavaScript application for every one of the trillions of pages it crawls costs enormously more. Google handles this by splitting the work: pages get crawled, and rendering happens as resources permit, sometimes promptly, sometimes later. For a stable page this delay is a footnote. For anything where freshness matters, a changed price, a corrected article, a new listing, it means the index can lag reality in a way it wouldn’t if the content were in the HTML from the start.
Rendering can also simply fail, and fail silently. The script errors out on some edge case. A request for data gets blocked, times out, or requires a cookie the crawler doesn’t have. The renderer gives up before a slow bundle finishes. In each case the crawler doesn’t see your content; it sees your loading state, or nothing. And here’s the vicious part: you won’t know. The page works in your browser, works on your phone, works for every human who checks it. The only visitor who sees the empty shell is the one visitor who decides whether you exist in search, and it doesn’t send complaints.
And Google is not the only reader that matters. Other search engines render less reliably or less often. Social platforms building link previews mostly read raw HTML and give up. Messaging apps unfurling a link, feed readers, and the growing population of AI crawlers ingesting the web to answer people’s questions, many of these take what the initial response contains and go no further. Every one of them that meets an empty shell is a channel where your page has no body, sometimes not even a title. The JavaScript-only bet isn’t one bet on Google’s renderer. It’s a spread of bets on every machine that will ever try to read you.
The test takes one minute, and almost nobody runs it. Fetch your page the way a crawler first sees it, the raw response, before any script runs, and read it. Is your headline in there? Your paragraphs? A real title tag, a meta description, an H1? Or is it a div with an id of root and a script tag? When GazeSite audits a page it examines the served HTML alongside the rendered screenshots, and this gap between them is one of the most consequential things it can surface, precisely because it’s invisible from inside a browser. A finding like no H1 heading found is mildly bad on a plain site. On a JavaScript-heavy site it’s often a symptom of this larger condition: the document you’re serving says nothing, and everything you actually say is contingent on execution.
The fixes are well understood and none of them require abandoning your framework. Server-side rendering runs your components on the server and sends the resulting HTML, so the first response contains the content and the JavaScript takes over afterward for interactivity. Static generation goes further for content that doesn’t change per visitor: render once at build time and serve finished pages. Every major framework now supports one or both, which tells you the industry recognized the problem. What remains is the decision to care, made per project, and it’s easiest at the start; retrofitting server rendering into a large client-only application is genuinely painful, which is why the right time to run the one-minute test is before you’ve built very much.
The principle underneath is older than JavaScript and will outlast whatever replaces it. The web’s unit of durable meaning is the document. HTML that contains its content is legible to everything: browsers old and new, crawlers rich and poor, tools that exist and tools that don’t yet. Content that exists only as the output of a program is legible to whatever can run the program, under conditions you don’t control. There are real applications, dashboards, editors, anything behind a login, where none of this matters, because search was never the point. But if the page exists to be found, the safest thing you can do is embarrassingly simple: put the words in the page. Everything that can execute JavaScript can also read HTML. The reverse has never been true.
More articles
Most audit reports are written to impress you with volume; a good one is written to be acted on, one finding at a time.
Read →Pricing pages fail not because the price is wrong but because they leave the buyer's practical questions unanswered.
Read →The same finding means different things on different pages, so a useful report has to change shape with the page it describes.
Read →