/ โ† AI Agent Compatibility Fixes / JavaScript-Only Content
In this guide
  1. What "JavaScript-only" means
  2. Who sees what
  3. How to find the missing facts
  4. The fix, step by step
  5. Common culprits and what to do about each
  6. Before and after: a price that depends on a script
  7. Choosing how to render
  8. Edge cases
  9. Stopping it from coming back
  10. Questions and answers

What "JavaScript-only" means

Every page starts as a response from your server: a block of HTML. A browser then runs any scripts on the page, and those scripts can add, change or remove content. Content is JavaScript-only when it is absent from that first HTML response and only appears once a script has run.

That can happen in a few different ways:

Who sees what

Different visitors see different versions of the same page, which is why the problem hides so well.

VisitorRuns JavaScript?What it gets from a JavaScript-only page
A person in a normal browserYesThe full page, perhaps after a short flicker or spinner.
An AI tool that fetches the pageUsually notThe raw HTML only. Prices, dates and text added by scripts are missing.
An agent driving a browserYesUsually the full page, but it may read or screenshot the page before slow scripts finish, or give up on a page still showing placeholders.
Link preview bots and many SEO toolsUsually notThe raw HTML only.
GooglebotYes, in a later rendering stepThe rendered page eventually, though the raw HTML is processed first.

The safe assumption is that anything essential to a customer's decision should be readable in the raw HTML. Scripts can then improve the experience for visitors who run them, without anyone losing the basic facts.

How to find the missing facts

The AI Agent Compatibility audit flags content hidden behind JavaScript. To pin down exactly what is missing on a given page, use three quick checks.

View source, not Inspect

Right-click the page and choose View Page Source, or press Ctrl+U (Cmd+Option+U on a Mac). This shows the HTML exactly as the server sent it. Use the browser's find box to search for the price, the date or a sentence from the main description. The Inspect or Elements panel is misleading here, because it shows the page after scripts have changed it.

Fetch it from the command line

curl -s -A "Mozilla/5.0" https://www.example.co.uk/courses/pottery-taster \
  | grep -o -i -E "£[0-9]+(\.[0-9]{2})?|in stock|sold out|[0-9]{1,2} (jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*" \
  | sort -u

This prints any prices, stock words or dates found in the raw HTML. If the page shows "£45, 3 places left, Saturday 14 November" but the command prints nothing, those facts are JavaScript-only. Adapt the pattern to the facts that matter on your page.

Switch JavaScript off

In Chrome or Edge, open developer tools, press Ctrl+Shift+P (Cmd+Shift+P on a Mac), type "Disable JavaScript" and press Enter, then reload. Firefox has a similar setting in about:config. What remains is roughly what a fetcher sees. Pay attention to empty boxes, permanent spinners, "Loading..." text and buttons that do nothing.

๐Ÿ’ก Also check the Network panel with JavaScript on. Filter by Fetch/XHR and reload: each request that returns price, stock or content after the page loads is a candidate for moving into the server template.

The fix, step by step

Step 1

Compare the raw HTML with the rendered page

Pick one page from each important template, such as a product, a service, an event and a location page. For each, save the view-source HTML and a copy of the page with JavaScript switched off, then compare them with what a normal visitor sees. Note every difference, however small, including blank spaces where a price, a badge, a date, a map or a block of text should be.

Step 2

List the facts missing from the raw HTML

Turn the differences into a short list of facts, not page areas: current price, stock or places left, delivery estimate, opening hours, event date and time, main description, reviews summary and contact details. Rank them by how much a customer needs each one to decide. Price, availability and dates almost always come first, while carousels of related products and recently viewed items can safely stay in JavaScript.

Step 3

Print those facts in the server template

Change the page template so the server reads the price, stock, dates and main text from your database or platform and writes them into the HTML as ordinary text, inside elements such as <p>, <dl> or <time>. If a script currently fetches them from an API after load, call the same data source on the server instead. Keep the element IDs so existing scripts can still update values later.

Step 4

Give third-party widgets a server-side fallback

For reviews, booking calendars, menus and store finders loaded from another service, find out whether the provider offers server-side output, a static embed or an API you can call when building the page. If not, print a plain summary yourself, such as the average rating and review count, the next available dates or a link to the booking page, so the essential fact exists before the widget loads.

Step 5

Keep collapsed content in the page

Tabs, accordions and "read more" sections are fine as long as their content is already in the HTML and simply hidden with CSS or the hidden attribute until opened. Change any component that only fetches or creates the content when clicked. The native <details> and <summary> elements are a good option, because they open and close without any script at all.

Step 6

Let JavaScript enhance rather than supply

Once the facts are in the HTML, scripts can still refresh them, for example updating stock every minute or switching price when a size is chosen. Write those scripts so they replace the server value rather than filling an empty box, and so a failed request leaves the server value in place. Remove spinners and placeholder text from the initial HTML wherever the real value is now available.

Step 7

Retest with scripts switched off

Repeat the view-source, curl and JavaScript-off checks on each template and confirm every fact on your list now appears as readable text. Check that the values match the page with JavaScript on, including after picking a variant. Run the AI Agent Compatibility audit again, and add a simple automated check that fetches key pages and looks for the price or date text.

Common culprits and what to do about each

PatternWhat fetchers seeBetter approach
Price fetched from a pricing API on loadAn empty price box or "£--"Print the current price in the template; let the script refresh it.
Stock badge filled by a stock appNo stock information, or a default "In stock"Print the stock status from the platform's own inventory.
Reviews widget in a placeholder divNothingPrint the average and count server-side, and link to a page of reviews.
Booking calendar in an iframeA frame address, not the datesShow the next available dates or a clear "Book at" link in the page itself.
Description loaded when a tab is clickedThe tab labels onlyPut all tab panels in the HTML, hidden until opened.
"Load more" button for events or productsThe first batch onlyGive each batch a real paginated address, such as ?page=2, and link to it.
Currency or tax converter rewriting pricesThe base price, then a different one in the browserGenerate localised prices on the server, or show the charging currency plainly.
Text drawn in a canvas or baked into imagesNo text at allUse real HTML text; keep images for decoration.

Contact details that exist only as an image or behind a click-to-reveal button are a special case with their own guide: fixing unreachable contact details.

Before and after: a price that depends on a script

Here is a typical pattern. The template prints an empty element and a script fills it in.

<!-- Before: the server sends an empty price -->
<p class="price" id="price"><span class="spinner"></span></p>
<script>
  fetch('/api/price?sku=PT-TASTER')
    .then(r => r.json())
    .then(d => { document.getElementById('price').textContent = '£' + d.price; });
</script>

After the fix, the server writes the price and the script only updates it if something has changed since the page was built.

<!-- After: the server sends the price; the script refreshes it -->
<p class="price" id="price" data-sku="PT-TASTER">£45.00</p>
<p id="places">3 places left on Saturday 14 November</p>
<script>
  const el = document.getElementById('price');
  fetch('/api/price?sku=' + el.dataset.sku)
    .then(r => r.ok ? r.json() : null)
    .then(d => { if (d) el.textContent = '£' + d.price; })
    .catch(() => {});
</script>

If the request fails, the server value stays. If the page is cached for a few minutes, the script corrects any change. Every visitor, including a fetcher that never runs the script, gets a real price.

Choosing how to render

How you get facts into the first HTML depends on how the site is built.

โš ๏ธ Serving a pre-rendered snapshot only to visitors that look like bots, often called dynamic rendering, is a stopgap. Google describes it as a workaround rather than a recommended solution, the snapshots go stale, and agents that use an ordinary browser identity will still get the JavaScript-only version. Fix the page for everyone instead.

Speed matters too. Even when an agent does run scripts, a page that takes many seconds to show its facts may be abandoned. If your pages render correctly but slowly, see fixing slow rendering for agents.

Edge cases

Stopping it from coming back

JavaScript-only content tends to creep back with each new app, widget or redesign. A few habits keep it out:

  1. Make "the key facts are in view-source" part of the definition of done for any new template or component.
  2. Before installing a widget or app that shows prices, stock, reviews or dates, ask the supplier how the content appears to visitors who do not run JavaScript.
  3. Keep a small list of important pages and the text each must contain, and fetch them automatically after every release.
  4. Re-run the AI Agent Compatibility audit after theme updates and major plugin or app changes.
Questions and answers

1. Why does my price show in the browser but not in view source?

Because a script adds it after the page loads. The server sends HTML with an empty space for the price, and JavaScript fetches the value from an API or a third-party app and writes it in. View source shows the server's original HTML, while the Inspect panel shows the page after scripts have run. Any tool that reads the HTML without running JavaScript sees the empty space, so the price needs to be printed by the server template.

2. Don't AI agents run JavaScript like a normal browser?

Some do and some do not. Agents that drive a real browser run scripts, but they may read the page before slow scripts finish, and they cannot see content that only loads after a click they did not make. Many lighter AI tools just download the HTML and never run scripts at all. Putting key facts in the first HTML works for both kinds, so it is the safer choice whichever tools your customers use.

3. Is content in tabs and accordions hidden from agents?

Not if it is already in the HTML. A tab or accordion that hides its content with CSS or the hidden attribute until clicked is fine, because the text is there for any tool that reads the page. The problem is a component that only fetches or builds its content when someone clicks it. Check by viewing the source and searching for a sentence from inside a closed tab. If you cannot find it, change the component.

4. Is dynamic rendering a good way to fix this?

It works as a temporary measure but is not a good long-term fix. Dynamic rendering serves a pre-rendered snapshot to visitors that identify as bots and the normal JavaScript page to everyone else. Snapshots go stale, the setup adds cost and complexity, and agents that use an ordinary browser identity still get the JavaScript-only version. Google itself calls it a workaround. Server rendering or printing the facts in the template fixes the page for everyone.

5. Will putting content in the HTML slow my page down?

Usually the opposite. When the server sends the facts in the HTML, visitors see them as soon as the page arrives instead of waiting for a script to download, run and make another request. The HTML gets a little larger, but a price, a date or a few paragraphs of text add very little. The exception is printing very long lists in one response, which is best handled with pagination and real page addresses.

6. My reviews come from a third-party app. What can I do?

Check whether the review provider offers server-side output, such as a snippet your template can include or an API your server can call when building the page. Many do, often on higher plans. If not, store the average rating and review count in your own system and print them in the template, with a link to a page listing the reviews. Keep any review markup consistent with what is shown, and only use reviews collected for that product.

7. How can I check a whole site for JavaScript-only content?

Start with your templates rather than every page, because pages built from the same template usually share the problem. Run the AI Agent Compatibility audit on one page of each type, then use view source or curl to confirm what is missing. For ongoing monitoring, keep a list of important addresses and the text each must contain, such as a price or a date, and fetch them automatically after each release to catch regressions early.

See what agents miss on your page

The AI Agent Compatibility audit tests your page for bot blocks, content hidden behind JavaScript, unlabelled forms and controls, navigation agents cannot follow and missing structured data, and links each finding to the guide that fixes it.

Open AI Agent Compatibility Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All AI Agent Compatibility Fixes  ·  Agent Compatibility in Single-Page Apps  ·  Fixing Slow Rendering for Agents  ·  Fixing Structured Data for Agents  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.