There is a specific, expensive way for an independent hotel to be invisible in AI answers, and almost nobody talks about it because it hides behind a working website. Your site looks perfect. The rates load, the room types show up, the calendar spins, the amenities list scrolls. A human sees a polished property. An AI crawler sees a blank room.
The culprit is JavaScript-only rendering, and if your most important facts, your prices, your room names, your policies, live inside a booking widget or a script-injected block, you may be handing ChatGPT, Perplexity, and Claude an empty page while the OTAs feed them a clean data sheet.
This is the fringe-but-practical corner of AI visibility. Let me walk you through the risk, a five-minute test you can run today, and the fix that keeps your booking engine intact.
The core problem: crawling is not the same as rendering
When people say a bot “reads” a page, they are collapsing two different steps.
Crawling is fetching the raw HTML document the server sends. It is fast, cheap, and it is what almost every bot does first.
Rendering is running the JavaScript in that document to build the page a human actually sees, injecting content, calling APIs, populating the booking widget. It is slow, expensive, and it is what most AI crawlers skip.
Googlebot is the famous exception. It has a rendering stage, so over time it can see JavaScript-injected content. But even Google delays rendering, and even Google has limits. The crawlers behind the AI answer engines, the ones deciding whether your hotel gets named when someone asks “best boutique hotel near [your city] convention center”, are a different animal. GPTBot, PerplexityBot, ClaudeBot, and the rest largely fetch raw HTML and read what is literally in the document. If the fact is not in the source, the fact does not exist to them.
This is exactly the mechanism I described in is your hotel invisible to ChatGPT. JavaScript-only content is one of the most common, least diagnosed reasons a property gets skipped.
The uncomfortable summary: your guests see a beautiful, interactive site. The AI deciding whether to recommend you sees the HTML your server sent before a single script ran. Those can be two completely different pages.

Download this study as a one-page PDF
Why booking widgets are the worst offenders
Booking engines are the single most likely place for this to bite you, and it is not the vendors’ fault, it is how they are built.
Most third-party booking engines, the ones from the big property-management and channel-manager platforms, embed as an iframe or a script that phones home to their servers, pulls live availability and pricing, and paints it into your page after load. That architecture is correct for a live booking flow. Rates change by the minute; you want real-time data.
But it means the actual numbers, the thing a rate-shopping AI wants most, never touch your HTML. They live on the vendor’s server and appear only after JavaScript executes in a real browser. A raw-HTML crawler sees a div with an ID and a spinner. That is it.
Now stack the same problem on the content around the widget:
- Room descriptions loaded from a headless CMS via client-side fetch
- Amenity lists rendered by a React or Vue component
- Policy text, cancellation terms, pet rules, tucked into a JavaScript accordion that only builds on click
- “From 189 a night” hero pricing pulled by script
Each of those is a fact an AI needs to answer a real traveler question. Each of those may be missing from the document the crawler reads.
Meanwhile the OTA listing for your exact property is a clean, server-rendered wall of structured text: room types, bed configs, amenities, price, cancellation policy, all in the raw HTML. Guess which one the model quotes. This is the same asymmetry I broke down in how OTAs steal search and the OTA destination landers mega guide. The OTAs are not smarter than you. Their pages are just more readable to a machine.
The five-minute test: read your site the way a crawler does
You do not need tools or a developer to check this. You need to look at the raw HTML instead of the rendered page. Here are three ways, easiest first.
Test 1: View Page Source
In Chrome or Firefox, right-click anywhere on your homepage or a room page and choose View Page Source (not Inspect, that shows the rendered DOM and will lie to you). You get the raw document the server sent.
Now use Ctrl+F inside that source view and search for:
- A specific room name, for example “Garden King”
- A price you can see on the live page, for example “189”
- A distinctive amenity phrase, for example “rooftop plunge pool”
If you can see it on the page but cannot find it in the source, it is JavaScript-injected. That is your red flag.
Test 2: curl the raw HTML
If you are comfortable with a terminal, fetch the page as a plain bot would:
curl -A "Mozilla/5.0 (compatible; GPTBot/1.0)" https://yourhotel.com/rooms
Pipe it to a file and search it, or just eyeball it. Same logic: if the room names, rates, and amenities are not in that text, non-rendering crawlers are not seeing them.
Test 3: Disable JavaScript and reload
In Chrome DevTools, open the command menu (Ctrl+Shift+P), type “Disable JavaScript”, hit enter, and reload the page. What survives is roughly what a raw-HTML crawler gets. If your booking widget collapses to nothing and your room grid goes blank, you have found the problem, and you have found it exactly the way the machine finds it.
Run all three on your homepage, a room-type page, and one destination or area page. Most independent hotels I audit fail at least one. The Google Search Console URL Inspection tool’s “View crawled page” and “Rendered HTML” comparison is a useful fourth check specifically for Googlebot, but it will not tell you what the non-rendering AI bots see, tests 1 to 3 do that.
The fix: keep the widget, expose the facts
Here is the part that matters. You do not rip out your booking engine. You do not sacrifice the live, interactive flow your guests need. You add a parallel, crawlable layer that states the same facts in plain HTML. Guests use the widget; machines read the text. Everyone wins.
1. Put the important facts in server-rendered body text
Every page that matters should state, in ordinary readable HTML that appears in View Page Source, the facts a traveler and an AI care about. For a room page that means: the room name, the bed configuration, the square footage or size, the key amenities, the typical or starting rate, and the view or floor. Written as real sentences and lists, not locked in a component.
You can, and should, still show the live price in the widget. But also write something crawlable like: “Our Garden King rooms start from around 189 a night, sleep two, and include a private balcony, rain shower, and Nespresso machine.” That sentence is now a fact the model can lift. A starting-from or typical range is honest and safe; you are not promising a rate, you are describing your product. No false precision, no fake guarantees, just readable truth.
2. Add Hotel and Offer schema in the raw HTML
Structured data is how you hand a machine the facts in a format it trusts. Use Hotel, LodgingBusiness, and Offer schema (JSON-LD) covering your name, address, geo coordinates, amenity list, room types, and price range.
One critical catch that trips up half the sites I review: the schema must be in the server-rendered HTML. JSON-LD injected by JavaScript has the exact same visibility problem as the widget it is trying to compensate for. If your tag-manager or client-side script writes the schema after load, a raw-HTML crawler never sees it. Put it in the source. Verify it with View Page Source, not just Google’s Rich Results Test, which renders.
3. Give the booking engine a crawlable fallback
If your booking widget is an iframe or script, wrap it with, or place beside it, a static block of HTML that lists your room types and starting rates and links to the same booking flow. Think of it as the noscript version of your rate table. Humans with JavaScript see the live widget; crawlers, and any human without scripts, see a readable rate summary. This is the single highest-leverage change for most properties, because it targets the exact content OTAs beat you on.
4. Consider server-side rendering or prerendering for key templates
If your site is built on a modern JavaScript framework (React, Vue, Next, Nuxt, etc.), the durable fix is to render the important templates on the server, or prerender them to static HTML, so the content ships in the first response. This is a developer task, but it is the difference between hoping crawlers render and knowing your facts are in the document. Prioritize the templates that carry commercial and factual weight: home, room types, rates, location, amenities.
5. Do not hide the same facts behind interaction
Content that only appears on click, hover, or scroll, tabbed room details, an accordion of policies, a “show more” amenities toggle, is often present in the DOM but sometimes built on demand. Where you can, have the full text in the HTML and use CSS to show and hide it, rather than building it with JavaScript on interaction. The fact should exist in the source whether or not anyone clicks.
Where this fits in the bigger AI-visibility picture
Fixing JavaScript rendering is plumbing. It does not, by itself, make you the answer. But it is a precondition: no amount of great content or reputation helps if the crawler reads a blank shell. Once your facts are crawlable, the rest of the playbook can actually work.
- Your Google Business Profile and the GBP for hotels playbook feed the local and map surfaces, which are server-rendered by Google, not you, and are a strong parallel signal.
- Your review and content signals, the stuff in content and reputation, only get quoted if the underlying page is readable.
- The structured, machine-friendly facts you expose are exactly what the AI visibility, AEO and GEO work builds on, and they connect to the broader shift I wrote about in the Flip.to and Spacetime piece on AI data.
- And because more direct AI and search visibility means more direct bookings, it ties straight into the book-direct math on OTA commission and your book-direct conversion work. Every booking a model sends you directly is a booking you did not pay 15 to 25 percent to acquire.
If you run an extended-stay or aparthotel property, this is doubly true, longer factual content about kitchens, laundry, and weekly rates is prime AI-answer material and prime JavaScript-hiding territory, as I cover in aparthotel and extended-stay marketing.
The 20-minute action list
If you do nothing else this week, do this:
- Run the three tests above on your homepage, one room page, and one location page.
- Write down every important fact, room names, rates, amenities, policies, that is missing from raw HTML.
- Add a static, crawlable rate summary next to your booking widget.
- Move your Hotel and Offer schema into the server-rendered source, and verify it in View Page Source.
- Put your key room and amenity facts into plain body text, with honest starting-from pricing.
None of this touches your booking flow. All of it makes you legible to the machines now deciding which hotels get named.
Want us to run the crawler-eye audit on your site and tell you exactly which facts are invisible, then fix the rendering and schema so the AI answers start including you? That is the core of what we do. Book a call and we will show you your raw HTML the way ChatGPT sees it, blank rooms and all, and hand you the fix list.