ResytechClient Reference
Complete API reference for ResytechClient — the iframe-based booking widget.
ResytechClient opens the booking UI in an iframe. It handles the overlay, loading spinner, body scroll lock, and cross-frame communication automatically.
Two presentations are available: the default full-screen modal, and an opt-in side drawer. See Presentation: modal or drawer.
Constructor
const client = new ResytechClient(config);ResytechClientConfig
| Property | Type | Required | Description |
|---|---|---|---|
locationId | string | Yes | Your Resytech location UUID |
baseUrl | string | Yes | Base URL of your booking platform (e.g. https://booking.yourdomain.com) |
theme | object | No | Theme overrides |
theme.primaryColor | string | No | Primary brand color (CSS color value) |
theme.fontFamily | string | No | Font family for the booking UI |
debug | boolean | No | Enable debug logging to the console. Default: false |
closeOnEscape | boolean | No | Close the modal when the user presses Escape. Default: true |
closeOnBackdropClick | boolean | No | Close the modal when the user clicks outside the booking card. Default: true |
otaCode | string | No | OTA attribution code, when embedding as an authorized partner. See OTA Partner Integration |
presentation | 'modal' | 'drawer' | No | How the booking UI is presented. Default: 'modal' — the full-screen overlay every existing embed uses. See Presentation: modal or drawer |
drawer | DrawerOptions | No | Drawer geometry. Ignored unless presentation is 'drawer'. See DrawerOptions |
const client = new ResytechClient({
locationId: 'abc123-def456',
baseUrl: 'https://booking.yourdomain.com',
theme: {
primaryColor: '#e63946',
fontFamily: '"Poppins", sans-serif'
},
debug: true
});Throws an Error if locationId or baseUrl is missing.
Auto-Initialization
When loaded via a script tag with data-resytech-location-id and data-resytech-base-url attributes, the library automatically creates a ResytechClient instance and assigns it to window.resytech.
<script
src="https://js.resytech.com/latest/resytech.js"
data-resytech-location-id="YOUR_LOCATION_ID"
data-resytech-base-url="https://booking.yourdomain.com"
data-resytech-debug="true">
</script>
<script>
// The client is ready to use
window.resytech.showUI();
</script>Auto-initialization also scans the DOM for elements with data-resytech-activity-id, data-resytech-equipment-id, or data-resytech-gift-card and binds click handlers to them. See Embedding the Booking UI for details.
Methods
showUI(options?)
Opens the booking modal. If the modal is already open, this is a no-op.
client.showUI();With pre-fill options:
client.showUI({
activity: 'activity-uuid',
equipment: [
{ equipmentUuid: 'equipment-uuid', quantity: 1 }
],
date: '2025-07-15',
durationMins: 120,
timeSlotStart: '2025-07-15T14:00:00',
timeSlotEnd: '2025-07-15T16:00:00',
timeSlotPrice: 199.99
});equipment is an array — each entry can include a quantity and add-ons:
client.showUI({
activity: 'activity-uuid',
equipment: [
{
equipmentUuid: 'single-kayak-uuid',
quantity: 2,
addons: [
{ addonUuid: 'dry-bag-uuid', quantity: 2 }
]
}
]
});CheckoutRequest Options
| Property | Type | Description |
|---|---|---|
location | string | Location UUID. Auto-filled from config. |
activity | string | Activity UUID to pre-select |
equipment | string | EquipmentSelection[] | Equipment selections to pre-fill the cart (see EquipmentSelection). A single equipment UUID can be passed as a string — shorthand for [{ equipmentUuid: <uuid>, quantity: 1 }]. |
equipmentCategory | string | Equipment category UUID to filter the activity's selection page to. Requires activity. On activities with equipment mixing enabled, the multi-item picker shows only that category's section; on standard activities the equipment card list is narrowed to the category's members. Ignored when equipment is also provided, and silently ignored (unfiltered page) when the category has no equipment on the activity. |
showCalendarPricing | boolean | Show per-day starting prices inside the date calendar. Default true; pass false for a plain availability-only calendar. |
showSeatsAvailable | boolean | Pass false to hide remaining seat counts on time slots and the tour guest selector for this session. Omit to follow the location's Show Seats Available checkout setting. When that setting is off, counts are stripped from the API response server-side, so true cannot re-enable them. "Fully booked" always shows. |
date | string | Date to pre-select (format: YYYY-MM-DD) |
durationMins | number | Duration in minutes |
timeSlotStart | string | Time slot start (ISO 8601 datetime) |
timeSlotEnd | string | Time slot end (ISO 8601 datetime) |
timeSlotPrice | number | Price for the selected time slot |
lockSchedule | boolean | When true, hides the "Choose another date/time" link inside the modal so the customer can't swap the slot you've pre-selected. The modal runs in SchedulingOnly nav mode, so suppressing the only crumb effectively hides the navbar entirely. Default false. |
presentation | 'modal' | 'drawer' | Presentation override for this open only. Parent-side chrome only — it is stripped before the payload reaches the booking UI. |
giftCard | GiftCardSelection | Opens the modal in gift card purchase mode instead of the activity flow. Presence is the discriminator — when set (even to {}), the activity/equipment fields are ignored. See GiftCardSelection and the Gift Card Mode walkthrough. |
voucher | VoucherSelection | Opens the modal to an Activity Voucher flow: the redeem page for a code, or an offer's purchase page for a slug. Activity/equipment fields are ignored; giftCard wins if both are set. See VoucherSelection and the Activity Voucher Mode walkthrough. |
EquipmentSelection
| Property | Type | Required | Description |
|---|---|---|---|
equipmentUuid | string | Yes | Equipment UUID |
quantity | number | Yes | How many of this equipment to add to the cart |
addons | AddonSelection[] | No | Add-ons to attach to this equipment |
AddonSelection
| Property | Type | Required | Description |
|---|---|---|---|
addonUuid | string | Yes | Add-on UUID. Must belong to the parent equipment. |
quantity | number | Yes | How many of this add-on to attach |
Add-on availability is date/time-specific: operators can black out add-ons for a window,
in which case the eligible-addons response returns them with available: false and a
customer-facing unavailableMessage to display. Don't submit unavailable add-ons — the
cart rejects them with AddonNotAvailable and the same message. See
Custom Booking Flow — Add-on availability and blackouts
for the full contract; the <resytech-addon-selector> component handles it automatically.
GiftCardSelection
All properties are optional. Pass an empty object (giftCard: {}) to open the gift card form with no pre-fills.
| Property | Type | Description |
|---|---|---|
amount | number | Gift card amount. Matches a flat amount when configured by the operator; otherwise the form switches to custom-amount mode (if allowed). |
purchaser.name | string | Purchaser's full name |
purchaser.email | string | Purchaser's email |
purchaser.phone | string | Purchaser's phone number |
recipient.name | string | Recipient's name |
recipient.email | string | Recipient's email |
recipient.message | string | Custom message sent with the gift card |
client.showUI({
giftCard: {
amount: 100,
purchaser: { name: 'Alex Morgan', email: 'alex@example.com' },
recipient: { name: 'Jamie Lee', email: 'jamie@example.com', message: 'Happy birthday!' }
}
});Gift card purchases emit giftcard:complete / giftcard:close events — see Checkout Events.
VoucherSelection
Needs a slug (purchase page) or a code (redeem page). code wins when both are present; pass code: '' to open the redeem page empty. The rest are optional purchase-form pre-fills.
| Property | Type | Description |
|---|---|---|
slug | string | Offer slug to sell |
code | string | Voucher code to check on the redeem page (AV + 32 hex; a malformed value is ignored) |
quantity | number | Number of vouchers to pre-select |
purchaser.name | string | Purchaser's full name |
purchaser.email | string | Purchaser's email |
recipient.name | string | Recipient's name |
recipient.email | string | Recipient's email (switches the form to gift mode) |
client.showUI({ voucher: { slug: 'black-friday-kayak', quantity: 2 } });
client.showUI({ voucher: { code: 'AV0123456789ABCDEF0123456789ABCDEF' } });A voucher purchase emits voucher:complete; a redemption is a booking and emits checkout:complete — see Checkout Events.
Presentation: modal or drawer
The default presentation is the full-screen modal — a fixed overlay covering the whole viewport with the booking card centred inside it. This is unchanged, and every existing embed keeps it without any configuration.
Set presentation: 'drawer' to open the booking UI as a side panel instead: a
narrow drawer pinned to the left or right edge of the viewport, sliding in over a
dimmed backdrop.
const client = new ResytechClient({
locationId: 'abc123-def456',
baseUrl: 'https://booking.yourdomain.com',
presentation: 'drawer',
drawer: {
side: 'right',
width: '460px',
fullScreenBelow: 640,
showCloseButton: true
}
});Or on the script tag, for auto-initialized embeds:
<script
src="https://js.resytech.com/latest/resytech.js"
data-resytech-location-id="YOUR_LOCATION_ID"
data-resytech-base-url="https://booking.yourdomain.com"
data-resytech-presentation="drawer"
data-resytech-drawer-side="right"
data-resytech-drawer-width="460px"
data-resytech-drawer-full-screen-below="640"
data-resytech-drawer-close-button="true">
</script>DrawerOptions
| Property | Type | Default | Description |
|---|---|---|---|
side | 'right' | 'left' | 'right' | Viewport edge the panel is pinned to |
width | string | '460px' | Panel width as any CSS length ('32rem', '30vw', …). Never exceeds the viewport width. |
fullScreenBelow | number | 640 | Below this viewport width (px) the panel fills the screen and the floating close button is hidden — the booking UI's own header close button takes over. Pass 0 to always keep the configured width. |
showCloseButton | boolean | true | Render the circular close button on the backdrop beside the panel |
Choosing a presentation per open
presentation is also accepted on showUI() and as a data-resytech-presentation
attribute, so a site that uses the modal everywhere can use the drawer on one surface:
client.showUI({ activity: 'activity-uuid', presentation: 'drawer' });<button data-resytech-activity-id="activity-uuid"
data-resytech-presentation="drawer">
Book Now
</button>setPresentation('drawer' | 'modal') changes the client-level setting for subsequent
opens, and getPresentation() reads it back.
Behaviour notes
- The panel is narrow, so the booking UI renders in its mobile layout — the same layout customers already see on phones.
- The parent page owns the backdrop in drawer presentation, so backdrop clicks are
handled directly rather than reported from the iframe.
closeOnBackdropClickandcloseOnEscapework exactly as they do for the modal. - The slide animation is skipped for visitors with
prefers-reduced-motion: reduce. - The drawer only injects its stylesheet when it is actually used — a modal-only embed adds nothing to the page.
Locking the schedule
When the parent page has already chosen the slot (via your own calendar UI or a third-party scheduler), set lockSchedule: true so the customer can't navigate back to pick a different time from inside the modal:
client.showUI({
activity: 'kayak-uuid',
equipment: [{ equipmentUuid: 'single-kayak-uuid', quantity: 1 }],
date: '2025-07-15',
durationMins: 120,
timeSlotStart: '2025-07-15T10:00:00',
timeSlotEnd: '2025-07-15T12:00:00',
timeSlotPrice: 89.99,
lockSchedule: true
});The modal always runs in SchedulingOnly nav mode, where the only crumb is the "Choose another date/time" link. lockSchedule removes that crumb, leaving an empty navbar that hides itself.
When showUI() is called it:
- Creates a fixed-position overlay covering the entire viewport with a dark blurred backdrop
- In drawer presentation, adds the side panel over that overlay and slides it in
- Displays a loading spinner while the iframe loads
- Loads the booking UI in an iframe — filling the overlay in modal presentation, or the panel in drawer presentation
- Locks body scroll (
document.body.style.overflow = 'hidden') - Emits the
checkout:openevent
close()
Closes the booking UI, removes the iframe and overlay, and restores body scroll. In drawer presentation the panel slides out first, and the DOM is removed once the animation finishes.
client.close();Emits the checkout:close event. If the modal is not open, this is a no-op.
on(event, callback)
Registers an event listener.
client.on('checkout:complete', (data) => {
console.log('Booking confirmed:', data.confirmationCode);
});| Parameter | Type | Description |
|---|---|---|
event | string | Event name (see Checkout Events) |
callback | (data: any) => void | Function called when the event fires |
off(event, callback)
Removes a previously registered event listener. You must pass the same function reference used with on().
function onComplete(data) {
console.log('Done:', data);
}
client.on('checkout:complete', onComplete);
// Later...
client.off('checkout:complete', onComplete);| Parameter | Type | Description |
|---|---|---|
event | string | Event name |
callback | (data: any) => void | The same function reference passed to on() |
setOtaCode(otaCode)
Sets the OTA attribution code at runtime. Pass null or undefined to clear it. Takes effect on the next showUI() call — the iframe URL is built at open time, not edited live. See OTA Partner Integration.
client.setOtaCode('viator');
// later, switch partners
client.setOtaCode('getyourguide');
// or clear it
client.setOtaCode(null);| Parameter | Type | Description |
|---|---|---|
otaCode | string | null | undefined | OTA code from the operator, or null/undefined to clear |
Useful when:
- Creating a
ResytechClientprogrammatically without knowing the OTA code yet - Configuring the auto-init'd
window.resytechinstance from a script that loads afterresytech.js - Running multiple
ResytechClientinstances on one page that target different OTA partners
getOtaCode()
Returns the currently configured OTA code, or undefined if none is set.
const code = client.getOtaCode(); // "viator" | undefinedupdateConfig(config)
Merges new configuration values into the current config. Does not affect an already-open modal.
client.updateConfig({
debug: true,
theme: { primaryColor: '#22c55e' }
});| Parameter | Type | Description |
|---|---|---|
config | Partial<ResytechClientConfig> | Properties to merge |
destroy()
Closes the modal (if open), removes the window.message listener, and clears all event listeners. Call this when you no longer need the client (e.g. in a SPA on route change).
client.destroy();Modal Behavior
When showUI() is called, the widget:
- Creates a fixed-position overlay at
z-index: 2147483645covering the full viewport (100dvw x 100dvh) - Applies a dimmed backdrop (
rgba(0, 0, 0, 0.5)) with ablur(4px)backdrop filter - Shows a loading spinner centered in the overlay while the iframe loads
- Loads the booking UI in an iframe that fills the entire overlay. The booking UI's own internal layout centers a white card; the transparent area around it shows the dimmed/blurred backdrop through the iframe. The iframe fades in (
opacity 0 -> 1over 300ms) once thecheckout-readymessage is received from the iframe (or after a 3-second timeout) - Locks body scroll to prevent background scrolling
- The iframe has the
allow="payment"attribute for Stripe payment integration
Dismiss Behavior
By default, the modal can be dismissed three ways:
- The X button in the booking UI header
- Pressing Escape — disable with
closeOnEscape: false - Clicking outside the booking card (on the dimmed backdrop area) — disable with
closeOnBackdropClick: false
The X button always closes regardless of config. ESC and click-outside are detected by the booking UI inside the iframe and reported to the parent via PostMessage with a reason field; the lib gates close on the corresponding config option. See Checkout Events.
Full Example
<!DOCTYPE html>
<html>
<head>
<title>My Rental Shop</title>
</head>
<body>
<h1>Kayak Rentals</h1>
<button id="book-btn">Book a Kayak</button>
<script src="https://js.resytech.com/latest/resytech.js"></script>
<script>
const client = new ResytechClient({
locationId: 'YOUR_LOCATION_ID',
baseUrl: 'https://booking.yourdomain.com'
});
// Listen for completed bookings
client.on('checkout:complete', (data) => {
alert('Booking confirmed! Code: ' + data.confirmationCode);
});
// Open modal on button click
document.getElementById('book-btn').addEventListener('click', () => {
client.showUI({
activity: 'kayak-activity-uuid',
date: '2025-08-01'
});
});
</script>
</body>
</html>