An availability calendar and a booking-request form for hotels on the 99tales widget API, embeddable on any web page. No backend, no build step, no framework — one script tag and two elements.
<availability-checker> is the calendar with a live
bookability verdict; <booking-widget> is the request
form. Use either or both — on the same page the checker hands its dates to
the form automatically. Everything else is configuration, and all of it
rides on the script tag.
https://www.hotel.com) have
to be registered with the service. An unregistered origin is refused — this
is what stops anyone else from putting a hotel's booking form on their own
site. Ask us to add yours.
Set the hotel, the look and the behaviour on the left. The snippet on the right is the finished embed — it updates as you go, and it is the whole integration.
Two independent elements — the dashed outlines are this page's, not theirs. Place them wherever you like, together or pages apart; when they share a page the checker hands its dates to the form. The preview always runs on our test hotel, whatever ID you type on the left — so you can submit it as often as you like without anyone receiving anything.
Each knob is data-<name> on the script tag, or
?<name>= on the script URL. Unset knobs keep the values in
the second column. Colours accept hex, rgb(), or a CSS colour
name; lengths accept any CSS length (a bare number means pixels).
Options that change behaviour rather than looks. Same two channels
as the theme knobs — data-<name> on the script tag or
?<name>= on its URL — and each one also works as a plain
attribute on the element itself, which is what you want when two instances
on one page need to differ. The attribute wins.
Language, bot protection and the API credentials need no configuration: the script arms Turnstile for the hotel by itself, the widget-API secret never leaves the service, and the language is detected from the page.
Two things are deliberately not on this list.
turnstile-site-key comes from the hotel's registration, so you
cannot get it wrong. room-options / room-groups
are JSON built from a property's room data rather than something to hand-write
into a script tag — set those on the element if your page can.
privacy-policy-url and thank-you-page-url take
either shape, and the difference matters:
https://www.hotel.com/datenschutz
— is used exactly as written. This is the one to use
unless your site is organised by language path.
/datenschutz — gets the visitor's
current language prefixed onto it: /de/datenschutz. That is
right for a site whose pages live under /de/,
/it/, /en/, and wrong for everyone else — the
language is guessed from the browser when the URL doesn't say, so a path
can resolve to a language your site has no pages for.
Anything else — www.hotel.com/datenschutz, with no
https:// and no leading slash — is refused with a message in
the browser console rather than turned into a broken link.
Paste the snippet. That is the whole integration — the script registers the two elements and everything else is theming.
Some hosts load the script themselves and strip data-
attributes on the way. Every option is therefore also accepted as a query
parameter on the script URL, which nothing can strip:
In a hex colour, # has to be written %23 in a
URL — or just leave it off, primary=6b5244 is read as hex too.
Where the host also won't let you set attributes on the elements, the
behaviour options above are unavailable; the theme knobs all still work.
One example: on Wix, use Add → Embed Code → Custom Element
with Server URL set to the script URL and
Tag name to booking-widget; a second Custom
Element with the same URL and the tag name
availability-checker adds the calendar. Loading the script
twice is harmless.
An iframe-based embed box — Wix's "Embed HTML", and its equivalents elsewhere — runs the page on the builder's own sandbox domain, not on the hotel's. That is a different origin from the one registered for the hotel, so the requests are refused. Use a real custom-element or raw-HTML block that runs on the site's own domain.