Skip to content

Embed the calendar on your site

Paste the snippet below and your site shows a real, month-at-a-time calendar for one resource — availability plus a per-night price hint, nothing else. There’s no booking flow here at all: no quote, no hold, no payment. If you want guests to book and pay from your site, see Embed the widget instead — that’s the full booking flow, as a separate, larger script.

Want to see it running before you paste anything? The live calendar demo embeds this exact snippet against a real resource.

<script async src="https://docs.booking-engine.davidvalentino.com/widget/calendar-v1.js"></script>
<div
data-availability-calendar
data-key="pk_live_..."
data-resource="<RESOURCE_ID>"
data-api-base="https://<your-api-host>"
></div>

Both lines are required. calendar-v1.js is a separate, smaller script from the booking widget’s v1.js — a site that only wants this calendar shouldn’t have to load the booking flow’s code too, and vice versa. It finds every [data-availability-calendar] element on the page and mounts one calendar into each, inside a Shadow DOM, same isolation the booking widget uses.

  • data-key — your pk_live_… or pk_test_… key. Required. A missing or malformed key replaces the element with a plain “Availability calendar misconfigured — see console” message, visible only in the browser console, never to a guest.
  • data-resource — one resource’s ID. Required. There’s no multi-resource or “all rooms” view — embed one calendar per resource, same limitation as the booking widget’s data-resource.
  • data-api-base — the API URL the calendar calls, for example https://<your-api-host>. Required in practice: without it the calendar calls the origin of its own script (the docs site, not the API) and every request fails.
  • data-lang — en or id. Optional, defaults to en.
  • data-fallback-contact — optional. A tel:, mailto:, or WhatsApp link shown if the calendar can’t reach the API.

There’s no data-rate-plan-id here — the calendar API has no rate-plan input at all (priceHintMinorUnits is per-resource, not per-plan). If you need an exact, bookable price, that’s what POST /v1/quotes and the booking widget are for.

The script adds window.BookingCalendar. It works like window.BookingWidget in Embed the widget:

BookingCalendar.mount(el: HTMLElement, options?: { key, resource, apiBase, lang, accent, radius, font, density, fallbackContact }): { destroy(): void }
BookingCalendar.scan(root?: ParentNode): void
  • mount returns a handle. handle.destroy() removes the calendar, and you can mount again in the same element.
  • Mounting an element that already has a calendar does nothing.
  • A value passed to mount wins over the data-* attribute.
  • Wait for the script’s load event before you call mount. The React, Next.js, Vue, Nuxt, Svelte, and WordPress examples in Embed the widget work for the calendar too. Use the calendar script URL, window.BookingCalendar, and no ratePlanId.
<div id="calendar"></div>
<script src="https://docs.booking-engine.davidvalentino.com/widget/calendar-v1.js"></script>
<script>
const handle = BookingCalendar.mount(document.getElementById("calendar"), {
key: "pk_live_...",
resource: "<RESOURCE_ID>",
apiBase: "https://<your-api-host>",
});
// Later: handle.destroy();
</script>

One month at a time, with previous/next navigation. Each available night shows a compact price hint under the day number; unavailable nights show as unavailable, with no further detail. There’s no way to click a date to start a booking — this widget doesn’t carry that flow.

The same five options as the booking widget, all as data-* attributes: data-accent, data-radius, data-font, data-density, data-lang. See Embed the widget for the values each one accepts and what happens if you get one wrong — the behavior is identical between the two embeds.

Your dashboard’s widget configurator (under Keys) generates both snippets — the booking widget’s and this calendar’s — from the same form, so you don’t hand-type either one.

Same posture as the booking widget: a bad snippet (missing key, missing resource id) is a mistake in your page, shown only in the console. A working snippet that can’t reach the API never renders an empty calendar that could be mistaken for “no availability” — it shows a clear “Calendar temporarily unavailable” message instead, with your data-fallback-contact link if you set one.

  • Embed the widget — the full booking flow, if you want guests to book and pay from this same calendar.
  • Calendar and iCal feeds — the underlying API, if you want to build your own calendar UI instead of using this embed.