# JavaScript SEO: Making Dynamic Sites Crawlable by Google and AI

**Author:** John Morabito (Founder, /winston)
**Published:** September 18, 2026
**Reading time:** 10 minutes
**Canonical:** https://www.winstondigitalmarketing.com/playbooks/javascript-seo-making-dynamic-sites-crawlable/

Here is a failure mode that catches good businesses off guard: the site looks perfect, everything works, and yet whole sections of it are invisible to search engines and AI. It happens because the modern web is built to assemble pages in the browser. The server sends a mostly empty shell, then JavaScript runs and fills in the products, the menu, the listings, the content. A person sees the finished result and assumes a crawler sees the same thing. Often it does not. The content that only appears after JavaScript runs can be partly or entirely missing from what search engines index and what AI engines read, which means traffic that should exist simply does not. This is JavaScript SEO, and this is how to tell if you have the problem and how to fix it.

## Why JavaScript breaks crawling

Start with what a crawler actually receives, because that is the whole issue. When a crawler requests your page, the server sends back HTML. On a traditional site, that HTML contains the content: the text, the links, the products. On a JavaScript-heavy site, that first HTML is often nearly empty, a container waiting to be filled, and the real content arrives only after the browser downloads and runs the JavaScript.

Google can run JavaScript, so it is not hopeless, but the way it does matters. Rendering is a second, delayed, resource-limited pass that happens after the initial crawl, and Google does not always complete it, especially on large or slow sites. Other crawlers do far less. Many of the bots that feed AI answers execute little or no JavaScript and rely on the raw HTML they are served. So content that depends on JavaScript to appear sits somewhere on a spectrum from reliably indexed to completely invisible, and you usually cannot tell which from the front end, because to you the page always looks complete. That invisibility from the front end is exactly why this problem goes undiagnosed while the traffic quietly never shows up.

## How to tell if you have the problem

The test is simple: look at your page the way a crawler first does, without JavaScript, and see whether your content is still there.

- **View the page source.** Look at the raw HTML the server sent, not the inspector's live DOM, and search it for a distinctive sentence from your main content. If the text is not in the source, JavaScript added it, and it is at risk.
- **Disable JavaScript and reload.** If the page goes blank or loses its content and links, that is close to the crawler's-eye view.
- **Use Search Console URL Inspection.** Google's [Search Console](https://search.google.com/search-console/about) URL Inspection tool shows the rendered HTML and a screenshot of what Google actually produced, so you can confirm whether your content and links made it in.

Run these across your page templates, not the homepage alone, because the problem usually hides in templates like product listings, location or menu pages, and search results, where the content is fetched dynamically. If your important content is missing from any of those views, you have a rendering problem worth fixing. This is one of the standard checks in a full technical review, which is laid out in the [90-minute technical SEO audit](https://www.winstondigitalmarketing.com/playbooks/technical-seo-audit-90-minutes-claude/).

## The fixes, from most to least robust

Every fix has the same goal: get the important content and links into the HTML a crawler receives, instead of only after client-side JavaScript runs. Which one fits depends on your stack, but the options are well established.

### Server-side rendering

The most robust answer is to render on the server, so the server sends a complete HTML page with the content already in it and JavaScript enhances the experience afterward. Crawlers and users both get the content immediately, and you stop depending on anyone's rendering step. Most modern frameworks support this, and it is the default worth reaching for on anything that needs to rank.

### Static generation and prerendering

For pages that do not change on every request, static generation pre-builds the HTML so it is served complete, which is fast and fully crawlable. A related approach, prerendering, serves a pre-built HTML snapshot, sometimes specifically to bots. These are strong options for content-style pages and catalogs that do not need to be personalized per visitor.

### Progressive enhancement and real links

Underneath the specific techniques is a principle: build so the core content and navigation work in plain HTML, then layer interactivity on top, rather than making the content itself depend on the script. A big part of that is using real links, actual anchor tags with real URLs, for your internal navigation, instead of click handlers that only move the page with JavaScript. Crawlers follow href links and frequently cannot follow scripted navigation, so real links are how a crawler discovers the rest of your site. This is often the difference between a site that gets fully explored and one where deep pages are never found.

## AI engines raise the stakes

This mattered when Google was the main audience. It matters more now, because a growing share of discovery runs through AI engines, and they generally do less JavaScript execution than Google. Content that Google might eventually render could still be invisible to an assistant deciding whether to cite you. So the safe assumption in an AI-search world is that a crawler reads your raw HTML and little else, which makes server-rendered, crawlable content more valuable than it was before. If you want your pages both to rank in search and to be pulled into AI answers, serve the content in HTML rather than betting each engine will run your scripts. The mechanics of earning those AI citations, on top of being crawlable, are in [how to get cited by ChatGPT in 2026](https://www.winstondigitalmarketing.com/playbooks/how-to-get-cited-by-chatgpt-in-2026/). Building for the least capable crawler is how you stay visible to all of them.

## The dispensary iframe problem is a special case

If this sounds familiar, it is because a very common version of it has its own playbook. Many dispensaries load their menu through a third-party embed inside an iframe, so the products render from another company's domain and none of that content exists in the dispensary's own HTML, which leaves the site thin to search and AI. That is one specific, widespread case of the broader pattern here: content that is not in your own HTML is content a crawler cannot count. The detailed treatment of that specific case, including the fix, is in [the Dutchie iframe SEO problem](https://www.winstondigitalmarketing.com/playbooks/dutchie-iframe-seo-problem/). If your business runs on an embedded menu, start there; if it runs on a dynamic app, an infinite-scroll feed, or a set of widgets, this broader guide is your version of the same fight.

The takeaway is one clear test you can apply to any page: does the content show up in the raw HTML the server sends. If yes, both search and AI can read it. If no, you are relying on a rendering step that may never happen, and the fix is to get the content into the HTML through server-side rendering, static generation, or genuine progressive enhancement. This kind of technical foundation work, alongside speed and crawlability, is part of our [SEO service](https://www.winstondigitalmarketing.com/services/seo/), and the free AI visibility check on our [contact page](https://www.winstondigitalmarketing.com/contact/) is a quick way to find out whether your content is actually reaching the engines that decide who gets found.

## Frequently asked questions

### What is a JavaScript SEO problem?

A JavaScript SEO problem is when the content that matters on your page only exists after JavaScript runs in the browser, and a search engine or AI crawler does not reliably see it. Modern sites often build the page in the browser: the initial HTML the server sends is nearly empty, and JavaScript fetches and assembles the real content afterward. A human sees the finished page and assumes everything is fine. A crawler may see only the empty shell. Google can render JavaScript, but it does so as a second, delayed, resource-limited step, and it does not always complete it, while many other crawlers and several AI engines do far less JavaScript rendering than Google. So content that depends on JavaScript to appear is at risk of being partly or entirely invisible in search and in AI answers, even though it looks perfect to you. The problem is invisible from the front end, which is exactly why it goes unnoticed until traffic that should exist simply is not there.

### How do I know if my site has a JavaScript rendering problem?

Check what the page looks like without JavaScript, because that is closer to what a crawler first sees. The fastest test is to view the page's source, the raw HTML the server sent, rather than the inspector's rendered view, and search it for a distinctive sentence from your main content: if the text is not in the source, it was added by JavaScript and is at risk. You can also disable JavaScript in your browser and reload; if the page goes blank or loses its content, that is the crawler's-eye view. The authoritative check is Google Search Console's URL Inspection tool, which shows the rendered HTML and screenshot Google actually produced for the page, so you can confirm whether your content and links made it in. Do this across your page templates, not the homepage alone, because the problem usually lives in templates like product listings, menus, or search results. If the content is missing from any of those views, you have a rendering problem worth fixing.

### How do you fix JavaScript SEO issues?

The goal is to make sure the important content and links exist in the HTML a crawler receives, rather than only after client-side JavaScript runs. The most robust fix is server-side rendering, where the server sends a complete HTML page and JavaScript enhances it afterward, so crawlers and users both get the content immediately. A related option is static generation or prerendering, which serves pre-built HTML for pages that do not change per request, and some setups prerender specifically for bots. Progressive enhancement is the underlying principle: build so the core content and navigation work in plain HTML, then layer interactivity on top, rather than making the content depend on the script. And make sure your internal links are real anchor tags with real URLs, not click handlers that only work with JavaScript, because crawlers follow href links and often cannot follow scripted navigation. Which fix fits depends on your stack, but the test is always the same: does the content show up in the raw HTML.

### Do AI engines handle JavaScript the same way Google does?

Generally they do less, which raises the stakes. Google has invested heavily in rendering JavaScript and will often, though not always, execute it as a delayed second pass. Many other crawlers, including several of the ones that feed AI answers, do much less JavaScript execution and lean on the raw HTML they are served. So content that Google might eventually render could still be invisible to an AI engine deciding whether to cite you. As more discovery shifts to AI answers, the safe assumption is that a crawler reads your raw HTML and little else, which makes server-rendered, crawlable content more important than it was when Google was the only audience that mattered. If you want your pages both to rank and to be cited by assistants, the reliable path is to serve the content in HTML rather than betting each engine will run your JavaScript. Building for the least capable crawler is the way to be visible to all of them.

### Is the dispensary menu iframe problem a JavaScript SEO issue?

It is a close relative, and it is worth seeing them together. The classic dispensary problem is a menu loaded through a third-party embed inside an iframe, so the products render from another company's domain and none of that content exists in your page's HTML, which leaves the site thin in the eyes of search and AI. The general JavaScript SEO problem is broader: any content assembled by client-side JavaScript, whether a single-page app, an infinite-scroll feed, a widget, or an embed, can be invisible to a crawler for the same underlying reason, that the content is not in the HTML the crawler receives. So the iframe menu is one specific, common case of the wider pattern. The fix rhymes too: get real, crawlable content about your products or services into your own HTML rather than relying on the embedded or scripted version. If your business runs on an embedded menu specifically, the dispensary version of this has its own detailed treatment; if it runs on a dynamic app or widgets, this broader guide applies.
