Iframe embed
Every booking page has an embeddable version at:
https://www.clndr.pro/embed/{username}/{slug}It's the same booking flow as the hosted page, without clndr.pro's header and footer, and it allows framing from any site. This is what the embed script creates for you. Use the iframe directly when you can't run scripts, or when you want full control of the frame.
<iframe
src="https://www.clndr.pro/embed/ada/intro-call?theme=auto"
title="Book a call with Ada"
style="width: 100%; min-height: 640px; border: 0"
></iframe>Query parameters
theme'light' | 'dark' | 'auto'queryauto follows the guest's system setting.
hideEventTypeDetails'1'queryHides the host's name, the page title, the duration and the description.
primaryColorstringqueryAny CSS colour for buttons and highlights. URL-encode it: #9A5A16 becomes %239A5A16.
namestringqueryPrefills the guest's name.
emailstringqueryPrefills the guest's email.
cstringqueryAn access code, for private pages. Without it a private page shows "Booking page not found".
Build the URL with URLSearchParams so names and colours are encoded properly:
const src = new URL('https://www.clndr.pro/embed/ada/intro-call');
src.search = new URLSearchParams({ theme: 'dark', primaryColor: '#E0913D', email: 'grace@example.com' }).toString();Sizing
The page's height changes as the guest moves from the date picker to the slots to the form. The frame can't know that by itself, so either give it a fixed height (640px fits the date and slot steps on most screens) or listen for the page's resize messages:
<iframe id="clndr" src="https://www.clndr.pro/embed/ada/intro-call" title="Book a call"
style="width: 100%; min-height: 600px; border: 0" scrolling="no"></iframe>
<script>
window.addEventListener('message', (event) => {
if (event.origin !== 'https://www.clndr.pro') return;
const frame = document.getElementById('clndr');
if (event.source !== frame.contentWindow) return;
if (event.data?.type === '__clndr:resize') {
frame.style.height = event.data.payload.height + 'px';
}
});
</script>Check event.origin on every message. The embed posts to *, so any page that frames it receives the messages, and you should only trust the ones that come from clndr.pro.
Events
The embed posts { type, payload } messages to its parent window:
type | payload | Sent when |
|---|---|---|
__clndr:resize | { height: number } | On load, and whenever the content's height changes |
__clndr:route_changed | { path: string } | When the booking page loads, for example /embed/ada/intro-call |
__clndr:booking_successful | { meetingId?: string, startTime: string, endTime: string } | After the guest books; times are UTC ISO strings |
window.addEventListener('message', (event) => {
if (event.origin !== 'https://www.clndr.pro') return;
if (event.data?.type === '__clndr:booking_successful') {
const { meetingId, startTime } = event.data.payload;
console.log('Booked', meetingId, 'for', new Date(startTime).toLocaleString());
}
});On approval pages booking_successful means the request was sent; the booking is pending until the host confirms it.
Private and team pages
A private page needs its access code in c. Anyone who can read your page's HTML can read that code too, so treat an embedded access code as shared with your site's visitors.
team pages don't work inside an iframe. They need the guest to be signed in to clndr.pro, and browsers don't send clndr.pro's cookies to a frame on another site. Link to the hosted page instead.
Quirks worth knowing
- A
selectquestion shows as a plain text input in the embed, aphonequestion as a text input, and acheckboxquestion as a checkbox whose answer is always saved empty. If a page usesselectorcheckboxquestions, render the form yourself with@clndr-pro/react. - The embed asks for slots by the guest's local midnight, and clndr.pro answers with the host's day that contains that moment. When the guest and the host are many hours apart, the times under a date can fall on the day before or after it in the guest's time. The API takes a host-timezone date and leaves out past slots, so custom integrations don't have this problem.