postMessage events

React to widget interactions, open the widget from your own page code, and control the calendar theme.

Available onFreePlusPro

Your widgets tell the page around them what the guest is doing: the dates they picked, the rental they chose, the booking they finished. Your page can talk back, to open the booking form or to set the calendar's theme. This page is the full list of both directions, with every field each message carries.

None of this is needed to put a widget on a page. The embed guides do that with a snippet and nothing else. Reach for this page when you want your own page to react to what the guest picked, and hand it to whoever writes code on your site.

Outbound events (from widgets)

RentalBeam widgets emit window.parent.postMessage events to the parent page. You can listen for these on any page where a widget is embedded to react to user interactions without modifying the widget code. Booking events come from the booking widget (Pro); the widget.resized event comes from iframe embeds of both widgets and from booking widget script embeds.

Listening for events

JavaScript
window.addEventListener('message', function (event) {
  // Always check the source before acting on messages.
  if (!event.data || event.data.source !== 'rentalbeam') return;

  switch (event.data.event) {
    case 'widget.ready':
      console.log('The widget is listening. Safe to open or prefill it now.');
      break;

    case 'booking.dates_selected':
      console.log('Dates selected:', event.data.data);
      break;

    case 'booking.dates_cleared':
      console.log('Dates cleared');
      break;

    case 'booking.unit_selected':
      console.log('Unit selected:', event.data.data);
      break;

    case 'booking.completed':
      console.log('Booking completed:', event.data.data);
      break;
  }
});
Always guard with event.data.source !== 'rentalbeam'. Browser pages receive postMessage events from all iframes on the page. The source check prevents your handler from reacting to unrelated messages.

widget.ready

Emitted once per page load by every script embed, on any site, as soon as the loader has installed itself and is listening. It is the moment it is safe to call RentalBeam.openBooking or to post a booking.open message in. Before it, there may be nothing on the other end yet. It carries no fields.

JavaScript
// event.data shape when widget.ready fires
{
  source: 'rentalbeam',
  event: 'widget.ready',
  data: {}
}
This matters most inside a site builder frame, where page code cannot tell when the embed finished loading. Send your message from inside the handler for this event and the timing takes care of itself.

booking.dates_selected

Emitted by the booking widget each time a valid check-in and check-out date pair is selected. Fires on every change, not just on form submit.

JavaScript
// event.data shape when booking.dates_selected fires
{
  source: 'rentalbeam',
  event: 'booking.dates_selected',
  data: {
    checkIn: '2026-10-03',   // YYYY-MM-DD local date string
    checkOut: '2026-10-07',  // YYYY-MM-DD local date string
    nights: 4,
    guests: 2,               // null when the rental collects no guest count
    adults: 2,               // equals guests on the shared picker
    children: null,          // the shared picker never counts children
    widgetId: 'a1b2c3d4-...'
  }
}
FieldTypeDescription
checkInstringYYYY-MM-DD local date string for the selected check-in date.
checkOutstringYYYY-MM-DD local date string for the selected check-out date.
nightsnumberInteger number of nights between check-in and check-out.
guestsnumberGuest count currently set in the form, adults and children together. Null when the rental collects no guest count, which is every vehicle and equipment rental.
adultsnumberThe adults in that count. Null when the rental collects no guest count.
childrennumberThe children in that count. Null when the rental does not count children separately, in which case adults equals guests. Send both back in booking.open or as data-rb-adults and data-rb-children so the next form opens with the same party, not the total read as adults.
widgetIdstringUUID of the booking widget that emitted the event.

booking.dates_cleared

Emitted by the booking widget when both dates are fully cleared. Useful for resetting dependent UI state.

JavaScript
// event.data shape when booking.dates_cleared fires
{
  source: 'rentalbeam',
  event: 'booking.dates_cleared',
  data: {
    widgetId: 'a1b2c3d4-...'
  }
}
FieldTypeDescription
widgetIdstringUUID of the booking widget that emitted the event.

booking.unit_selected

Emitted by the booking widget in a collection whenever the booked rental changes: when the guest picks a rental after choosing dates (the default dates-first flow) or up front (the Cards and Dropdown pickers). Useful for per-rental analytics or reflecting the chosen rental elsewhere on your page. Single-rental widgets do not emit it.

JavaScript
// event.data shape when booking.unit_selected fires
{
  source: 'rentalbeam',
  event: 'booking.unit_selected',
  data: {
    unitId: 'a1b2c3d4-...',        // UUID of the booked rental
    unitLabel: 'Cabin A',          // the rental's display name
    collectionId: 'c1d2e3f4-...',  // UUID of the collection (this event only fires inside one)
    price: 540,                    // total for the selected range, or null when a rental is picked before dates
    checkIn: '2026-10-03',         // the dates the guest already picked, or null in a rental-first picker
    checkOut: '2026-10-07',
    nights: 4,
    guests: 2,                     // null when the rental collects no guest count
    adults: 2,
    children: 0
  }
}
FieldTypeDescription
unitIdstringUUID of the booked rental.
unitLabelstringDisplay name of the booked rental.
collectionIdstringUUID of the collection. This event only fires inside a collection, so it is never null.
pricenumberThe total for the selected date range when the picker already knows it (the dates-first flow, where dates are chosen before a rental). Null in rental-first flows (Cards, Dropdown), where a rental is picked before dates. The event is not re-emitted once pricing later resolves.
checkInstringThe check-in date the guest already picked, as YYYY-MM-DD. Null in the Cards and Dropdown pickers, where the rental comes first.
checkOutstringThe check-out date the guest already picked, as YYYY-MM-DD. Null in the Cards and Dropdown pickers.
nightsnumberNights in the picked range. Null in the Cards and Dropdown pickers.
guestsnumberGuest count the guest already set. Null in the Cards and Dropdown pickers, and null for a rental that collects no guest count.
adultsnumberEquals guests: the shared picker asks for one plain count. Null when guests is.
childrennumberAlways null here. The shared picker never counts children; the chosen rental's own form does, and reports them in its booking.dates_selected.

In the default dates-first flow the dates and guest count come with the event, so one message carries everything you need to send the guest on to that rental's own page. In the Cards and Dropdown pickers the guest picks the rental before any dates, so those four fields are null; the chosen rental's own form then emits booking.dates_selected when the guest picks dates, and its widgetId is that rental's id. That handover is the recipe on Search then book on another page.

booking.completed

Emitted by the booking widget once a booking reaches its final state: a request-only booking being submitted, or an in-widget payment settling. It fires once per booking. Use it to record a conversion, or to send the guest somewhere on your own site.

JavaScript
// event.data shape when booking.completed fires
{
  source: 'rentalbeam',
  event: 'booking.completed',
  data: {
    widgetId: 'a1b2c3d4-...',
    bookingReference: 'b9c8d7e6-...',  // the booking's id, the one your dashboard shows
    status:   'confirmed',   // or 'pending' for a request-only booking
    paid:     true,
    total:    420,
    currency: 'USD',
    nights:   4,
    checkIn:  '2026-10-03',
    checkOut: '2026-10-07',
    guests:   2,             // null when the rental collects no guest count
    adults:   2,             // the split behind guests
    children: 0,             // null when the rental does not count children
    redirectUrl: '/thank-you'  // the redirect you set, or null when you set none
  }
}
FieldTypeDescription
widgetIdstringUUID of the widget the booking came from.
bookingReferencestringThe booking's id, the same reference your dashboard shows. Null when the id was not available on the success path that fired. It is a reference, not a key to anything a guest could open.
statusstring'confirmed' when the booking is final, 'pending' when it still needs your approval.
paidbooleanWhether the guest paid in the widget. False for request-only and pay-later bookings.
totalnumberBooking total, or null when the widget shows no pricing.
currencystringCurrency of the total, or null when there is no total.
nightsnumberNumber of nights booked.
checkInstringCheck-in date as YYYY-MM-DD.
checkOutstringCheck-out date as YYYY-MM-DD.
guestsnumberGuest count on the booking, adults and children together, or null when the rental collects no guest count.
adultsnumberAdults on the booking, or null when the rental collects no guest count.
childrennumberChildren on the booking, or null when the rental does not count children separately.
redirectUrlstringThe post-booking redirect set in the rental's Booking form section, exactly as you typed it, or null when you set none. The script embed only follows it when it resolves to your own site.
This event carries no guest details: no name, email, phone, or form answers. It is broadcast to the page the widget sits on, so it deliberately contains nothing that identifies the guest. Read guest details from your dashboard or the booking email instead.
JavaScript
// Record a conversion when a booking completes.
window.addEventListener('message', function (event) {
  if (!event.data || event.data.source !== 'rentalbeam') return;
  if (event.data.event !== 'booking.completed') return;

  var d = event.data.data;
  gtag('event', 'purchase', {
    value:    d.total,
    currency: d.currency,
    items:    [{ item_id: d.widgetId, quantity: d.nights }]
  });
});
If all you want is to send the guest to a thank-you page, you do not need this event. Set a redirect in the rental's Booking form section and RentalBeam does it for you. The redirect must point at your own site, and it is skipped when your site builder puts the widget inside its own sandboxed frame (Wix and Google Sites do). This event always fires either way, so it is the reliable option when you need one.

widget.resized

Emitted by both the availability calendar and the booking widget whenever the widget's rendered height changes: on first load, calendar navigation, or as the booking form expands. It fires from iframe embeds of both widgets, and from booking widget script embeds too. A booking widget script embed renders the form through a frame it sizes automatically, so you never need to handle the event there. A copied <iframe> snippet for either widget is deliberately fixed-height with no relay on the host page. Listen for this event yourself (see below) if you want a plain iframe embed to reflow with its content. The availability calendar's script embed renders directly in the page and grows with it naturally, so it does not emit this event.

JavaScript
// event.data shape when widget.resized fires
{
  source: 'rentalbeam',
  event: 'widget.resized',
  data: {
    height: 612   // widget content height in pixels
  }
}
FieldTypeDescription
heightnumberWidget content height in pixels (bound to a sane range). Set this as the iframe height.

To size a custom iframe to its content:

JavaScript
// Size a RentalBeam iframe to its content. Needed for a plain <iframe> embed -
// those are fixed-height with no relay. Script embeds manage their own iframe
// and resize automatically, so you never need this listener for them.
window.addEventListener('message', function (event) {
  if (event.source !== iframe.contentWindow) return;
  var d = event.data;
  if (d && d.source === 'rentalbeam' && d.event === 'widget.resized'
      && typeof d.data.height === 'number') {
    iframe.style.height = d.data.height + 'px';
  }
});

Event envelope fields

Every outbound event from a RentalBeam widget shares the same top-level envelope:

FieldTypeDescription
sourcestringAlways "rentalbeam". Use this to filter events in your listener.
eventstringDot-namespaced event name. Format: widget.action (e.g. booking.dates_selected).
dataobjectEvent-specific payload. Shape varies by event. See individual tables above.
Every field added to these payloads is added alongside the old ones, never in place of them. A listener written against an earlier version of this page keeps working.

Reserved internal events

On pages using the booking widget script embed you may also see widget.overlay, widget.prefill, and widget.open_launch messages. These coordinate the embed script with the booking form and are not part of the public contract. Their names and payloads may change at any time, so do not build on them. The events documented above are the stable surface.

Events inside a site builder's frame

Some builders run your embed code inside a frame of their own. Wix's Embed Code element is the common one, and Google Sites does it too. A booking.* event used to stop at that frame and never reach the page outside it. The script embed now passes every booking.* event outward, to the page that holds the frame, so whatever page code your builder offers can listen for them just as it would on any other site. Each builder has its own way of listening: on Wix it is $w('#html1').onMessage(...) on the Embed Code element, not a window listener. Nothing changes for sites where the script already runs on the page itself.

A plain <iframe> embed has no RentalBeam script on the builder's page, so there is nothing there to pass the event along. Use the script embed when you want these events inside a builder's frame.

Inbound message: booking.open

This is the message form of window.RentalBeam.openBooking(...), for page code that cannot call the loader directly. Builder page code is the usual case: it sits outside the frame holding the embed and cannot reach into it, so it sends a message in instead. Wix Velo is the worked example below.

JavaScript
// Send this INTO the frame that holds the embed
{
  source: 'rentalbeam-host',   // not 'rentalbeam' - that is the widget's own source
  event: 'booking.open',
  data: {
    rentalId: 'a1b2c3d4-...',  // or collectionId
    checkIn: '2026-10-03',     // optional
    checkOut: '2026-10-07',    // optional
    guests: 2,                 // optional, the whole party
    adults: 2,                 // optional, with children: the split
    children: 0                // optional
  }
}
FieldTypeDescription
sourcestringAlways "rentalbeam-host". It is deliberately not "rentalbeam", so your message can never be mistaken for an event the widget itself sent.
eventstringAlways "booking.open".
data.rentalIdstringWhich embed to target. Use this or data.collectionId.
data.collectionIdstringTargets a collection embed instead of a single rental.
data.checkInYYYY-MM-DDOptional. Prefills check-in.
data.checkOutYYYY-MM-DDOptional. Prefills check-out.
data.guestsnumberOptional. Prefills the guest count, adults and children together.
data.adultsnumberOptional. Prefills the adults stepper. Send it with data.children when you have both from a booking.dates_selected event; on its own, guests is read as adults.
data.childrennumberOptional. Prefills the children stepper on a rental that counts children separately. Ignored elsewhere.

Send it into the frame that holds the embed. On Wix that is $w('#html1').postMessage(message), where #html1 is the Embed Code element; another builder with page code has its own equivalent. Wait for widget.ready first, because the element may not be loaded when your page code runs. On a site where the script runs directly on the page, use window.postMessage(message, '*') or just call RentalBeam.openBooking(data) once the script has loaded; listening for widget.ready works there too.

JavaScript (Wix Velo)
// Wix Velo - #html1 is the Embed Code element holding the booking widget.
// The element may not be loaded yet when page code runs, so wait for the
// embed to say widget.ready before posting into it.
$w.onReady(function () {
  $w('#html1').onMessage(function (event) {
    var message = event.data;
    if (!message || message.source !== 'rentalbeam') return;
    if (message.event !== 'widget.ready') return;

    $w('#html1').postMessage({
      source: 'rentalbeam-host',
      event: 'booking.open',
      data: {
        rentalId: 'a1b2c3d4-...',
        checkIn: '2026-10-03',
        checkOut: '2026-10-07',
        guests: 2
      }
    });
  });
});

The behavior matches openBooking: it prefills the mounted embed with that id and, for a compact search bar, opens it.

One page template, many rentals

If no embed with that id is mounted yet, but the page has a .rentalbeam-booking-form container with no id attribute on it, the loader mounts that container as the rental (or collection) named in the message, with the prefill already applied. That is how one page template serves many rentals: a Wix dynamic page, or any CMS template. Leave the id off the container and send booking.open with the rental id from page code.

Links like ?checkin=2026-10-03&checkout=2026-10-07&guests=2 are read off the page address automatically on a normal site. On Wix and Google Sites the loader runs inside the builder's frame and cannot see the page address, so read the query in page code there (on Wix, wixLocation.query) and send booking.open yourself.

Example: Wix Velo integration

Wix is the worked example here, not the rule: any builder that gives you page code works the same way, using its own way of listening to and posting into the frame. The common case is a page holding a collection booking widget, where the guest picks dates, sees which rentals are free, picks one, and should then land on that rental's own page with the dates already filled in. Listen for booking.unit_selected and send them there.

JavaScript (Wix Velo)
// Wix Velo - paste in the JavaScript panel of the page that holds the
// collection booking widget. #html1 is the Embed Code element.
import wixLocation from 'wix-location-frontend';

// One path per rental in the collection.
const PATHS = {
  'a1b2c3d4-...': '/rentals/seaside-cottage',
  'e5f6a7b8-...': '/rentals/cabin-a'
};

$w.onReady(function () {
  // Page code listens to the element, not to the window.
  $w('#html1').onMessage(function (event) {
    var message = event.data;
    if (!message || message.source !== 'rentalbeam') return;
    if (message.event !== 'booking.unit_selected') return;

    var d = message.data;
    var path = PATHS[d.unitId];
    // No dates means a rental-first picker, so there is nothing to carry over.
    if (!path || !d.checkIn) return;

    wixLocation.to(path
      + '?checkin=' + d.checkIn
      + '&checkout=' + d.checkOut
      + (d.guests ? '&guests=' + d.guests : '')
      + (d.adults ? '&adults=' + d.adults : '')
      + (d.children != null ? '&children=' + d.children : ''));
  });
});

The other half, what goes on each rental's page, is written out in full on Search then book on another page, with a version for Wix and a version for any other site.

Wix Velo runs in a sandboxed environment. If the listener does not fire, verify that the embed is added via the Wix Embed Code element and not a Wix iframe element. Velo has different message routing for each.

Inbound event (to the calendar widget)

The availability calendar widget accepts one inbound postMessage from the parent page to control its theme. This is separate from the outbound events emitted by the booking widget above.

rentalbeam-theme-change

Send this from your page to the calendar iframe to switch between light and dark mode at runtime.

JavaScript
// Send from the parent page to the calendar iframe
calendarIframe.contentWindow.postMessage(
  { type: 'rentalbeam-theme-change', theme: 'dark' },
  'https://rentalbeam.com'
);
FieldValueDescription
typestring"rentalbeam-theme-change"
themestring"light" or "dark"