ResytechResytech Docs

Checkout Events & Callbacks

Listen to booking lifecycle events — track conversions, redirect after checkout, and integrate analytics.

ResytechClient emits events at each stage of the booking flow. Use on() and off() to subscribe.

Events

EventPayloadWhen
checkout:openCheckoutRequestThe booking modal has opened
checkout:readyundefinedThe iframe has loaded and is ready to interact
checkout:complete{ confirmationCode, price, ... }The customer completed a booking
checkout:return{ returnUrl }The customer clicked the post-purchase Continue button. Informational only -- the iframe navigates the top frame to returnUrl regardless
checkout:closeundefinedThe modal has been closed
giftcard:complete{ giftCardCode, amount }A gift card purchase succeeded
giftcard:closeundefinedThe customer dismissed the gift card success view
membership:complete{ membershipNumber, planName }A membership purchase succeeded
membership:closeundefinedThe customer dismissed the membership success view

checkout:open

Fires immediately when showUI() is called. The payload is the CheckoutRequest object passed to showUI(), including any pre-fill options and the location from config.

client.on('checkout:open', (data) => {
  console.log('Booking started for activity:', data.activity);
  console.log('Pre-selected date:', data.date);
});

Payload

{
  location: string;                  // Location UUID (always present)
  activity?: string;                 // Activity UUID (if pre-selected)
  equipment?: string | EquipmentSelection[];  // Equipment selections, or a single equipment UUID as shorthand (quantity 1, no add-ons)
  date?: string;                     // Date (if pre-selected)
  durationMins?: number;             // Duration in minutes (if pre-selected)
  timeSlotStart?: string;            // Time slot start (if pre-selected)
  timeSlotEnd?: string;              // Time slot end (if pre-selected)
  timeSlotPrice?: number;            // Price (if pre-selected)
}

interface EquipmentSelection {
  equipmentUuid: string;
  quantity: number;
  addons?: AddonSelection[];
}

interface AddonSelection {
  addonUuid: string;
  quantity: number;
}

checkout:ready

Fires when the iframe has loaded and the booking UI is visible. This event has no payload.

The iframe sends a checkout-ready PostMessage when it is fully initialized. If no message is received within 3 seconds, the iframe is shown anyway (timeout fallback).

client.on('checkout:ready', () => {
  console.log('Booking UI is loaded and visible');
});

checkout:complete

Fires when the customer successfully completes a booking. The payload includes the confirmation code and price, along with any additional data sent by the booking iframe.

client.on('checkout:complete', (data) => {
  console.log('Confirmation:', data.confirmationCode);
  console.log('Total price:', data.price);
});

Payload

{
  confirmationCode: string; // Booking confirmation code
  price: number;            // Total price charged
  // ...additional fields from the booking iframe
}

checkout:return

Fires when the customer clicks the Continue button on the confirmation page (only present when a returnUrl is configured for the checkout). The iframe navigates the top frame to the URL regardless — this event is informational so you can run analytics, conversion pixels, or cleanup synchronously before the page is replaced.

client.on('checkout:return', (data) => {
  console.log('Customer is being sent to:', data.returnUrl);
  // fire pixels, etc. — you can't cancel the navigation
});

Payload

{
  returnUrl: string; // The URL the top frame is about to navigate to
}

checkout:close

Fires when the modal is closed, either by the user or by calling client.close(). This event has no payload. Fires regardless of whether a booking was completed.

client.on('checkout:close', () => {
  console.log('Modal closed');
});

giftcard:complete

Fires when a gift card purchase succeeds. Mutually exclusive with checkout:complete — gift card flows do not produce a booking confirmation.

client.on('giftcard:complete', (data) => {
  console.log('Gift card code:', data.giftCardCode);
  console.log('Amount:', data.amount);
});

giftcard:close

Fires when the customer dismisses the gift card success view. No payload.

membership:complete

Fires when a membership purchase succeeds.

client.on('membership:complete', (data) => {
  console.log('Membership #:', data.membershipNumber);
  console.log('Plan:', data.planName);
});

membership:close

Fires when the customer dismisses the membership success view. No payload.

Registering and Removing Listeners

// Register
client.on('checkout:complete', handleComplete);

// Remove (must use the same function reference)
client.off('checkout:complete', handleComplete);

You can register multiple listeners for the same event:

client.on('checkout:complete', trackConversion);
client.on('checkout:complete', showConfirmationBanner);
client.on('checkout:complete', sendAnalyticsEvent);

PostMessage Communication

The booking iframe communicates with the parent window using window.postMessage. The library handles this internally -- you do not need to work with PostMessage directly.

The iframe sends these message types:

Message TypeMaps To EventDescription
checkout-readycheckout:readyIframe is loaded and ready
checkout-closecheckout:closeUser closed the booking from inside the iframe
checkout-completecheckout:completeBooking was successfully completed
checkout-returncheckout:returnUser clicked the post-purchase Continue button
gift-card-purchase-completegiftcard:completeGift card purchase succeeded
gift-card-closegiftcard:closeUser dismissed the gift card success view
membership-purchase-completemembership:completeMembership purchase succeeded
membership-purchase-closemembership:closeUser dismissed the membership success view

Messages are parsed as JSON. Non-JSON messages and messages without a type field are silently ignored. When debug mode is enabled, all received messages are logged to the console.

checkout-close reason field

checkout-close may include an optional reason field that describes how the user dismissed the modal:

ReasonSourceGated by config
(none)The X button in the header, or completion redirectAlways closes
'escape'The user pressed Escape inside the iframecloseOnEscape
'backdrop'The user clicked outside the booking cardcloseOnBackdropClick

When the booking UI sends a checkout-close with reason: 'escape' or reason: 'backdrop', the lib only actually closes the modal if the corresponding config option is true (the default). Reason-less closes (the X button, post-checkout dismissal) always close.

Practical Examples

Conversion Tracking with Google Analytics

client.on('checkout:complete', (data) => {
  gtag('event', 'purchase', {
    transaction_id: data.confirmationCode,
    value: data.price,
    currency: 'USD'
  });
});

Facebook Pixel

client.on('checkout:open', () => {
  fbq('track', 'InitiateCheckout');
});

client.on('checkout:complete', (data) => {
  fbq('track', 'Purchase', {
    value: data.price,
    currency: 'USD'
  });
});

Redirect After Booking

client.on('checkout:complete', (data) => {
  window.location.href = `/confirmation?code=${data.confirmationCode}`;
});

Show a Confirmation Banner

client.on('checkout:complete', (data) => {
  const banner = document.createElement('div');
  banner.className = 'success-banner';
  banner.textContent = `Booking confirmed! Your code: ${data.confirmationCode}`;
  document.body.prepend(banner);
});

client.on('checkout:close', () => {
  // Refresh availability after the modal closes
  refreshCalendar();
});

Log All Events (Debugging)

[
  'checkout:open', 'checkout:ready', 'checkout:complete', 'checkout:return', 'checkout:close',
  'giftcard:complete', 'giftcard:close',
  'membership:complete', 'membership:close',
].forEach(event => {
  client.on(event, (data) => {
    console.log(`[Resytech] ${event}`, data || '');
  });
});

Error Handling

If the iframe fails to load or an error occurs during PostMessage handling:

  • With debug: true, errors are logged to console.error
  • With debug: false (default), errors are silently caught
  • The checkout:ready event fires after a 3-second timeout even if the iframe does not send a ready message, so the user is never stuck on a spinner indefinitely
  • There is no dedicated error event. If you need to detect load failures, use the checkout:ready event timing combined with your own timeout logic.

On this page