Embed your booking page

Put your company's public booking page on your own website, either inline in a page or as a popup opened from your own button. Your customers see only your company, never Booker.

This guide is for your website's developer. It assumes the public booking page is turned on and has a page name (slug). The examples use the placeholder host https://book.example.com; Booker will confirm your real booking host when you get access.

List your sites

A booking page can only be shown on websites you have listed. Send the list with an API key that has the admin role:

curl -X PUT https://api.example.com/api/v1/company \
  -H "Authorization: Bearer $BOOKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "embed_origins": ["https://www.example.com"] }'

Each entry must be exactly an origin: the scheme and host (and port, if it isn't the default), in lowercase, with no path and no trailing slash. https://www.example.com is accepted; https://WWW.Example.com and https://www.example.com/ are not.

  • https only. The one exception is local testing: http://localhost and http://127.0.0.1, with or without a port.
  • Lowercase only, and the exact origin of the page that shows the booking page.
  • No wildcards. List https://www.example.com and https://example.com separately if you use both.
  • At most 10 entries, with no duplicates.
  • An empty list, [], clears it and turns embedding off.
  • A bad entry is a 400 that names it, and nothing is saved.

GET /api/v1/company returns the current list as embed_origins. Until a site is listed, the embed shows a plain "Book online" link instead of the booking page.

Inline

Add the script once, and a div wherever the booking page should appear. The page name is your company's slug: lowercase letters, digits and dashes, up to 60 characters. Any other value is ignored, with a warning in the browser console.

<div data-booker-page="your-page-slug"></div>
<script src="https://book.example.com/embed.js" async></script>

The page fills the width of the div and grows to fit its content, so give the div no fixed height.

Give any button or link a data-booker-popup attribute. Clicking it opens the booking page in a dialog: full screen on a phone, a centred panel on a larger screen. Escape or the Close button closes it, and focus returns to your button.

<button data-booker-popup="your-page-slug">Book online</button>
<script src="https://book.example.com/embed.js" async></script>

You can use both on one page, and as many buttons as you like.

Show a customer's booking link only on a page only that customer can see, such as their account page behind your login. Never put it on a public page, in a URL others might see or that analytics records in full, or on a page a CDN or shared cache can store. The link is the customer's key to their booking, embedded or not; the same applies to a plain link.

A scheduling request's booking_url (from GET /scheduling-requests/:id), or the token at its end, can be shown inside your page the same way as the booking page:

<div data-booker-link="https://book.example.com/r/<token>"></div>
<script src="https://book.example.com/embed.js" async></script>
<button data-booker-link-popup="https://book.example.com/r/<token>">Book your appointment</button>
<script src="https://book.example.com/embed.js" async></script>

From your own code:

Booker.mount(element, { link: bookingUrl });
Booker.popup({ link: bookingUrl });
  • The same allowed websites (embed_origins) apply. The public booking page doesn't need to be on.
  • A URL from another address, or one that isn't a booking link, is ignored, with a warning in the browser console.
  • booker:booked fires when the customer books, not when they change or cancel.
  • A link that's no longer active says so inside the frame. A link that was replaced (rotated) or is wrong shows an "Open your booking page" link instead. For up to about a minute after a rotation, the old link can still be framed and show "This link is no longer active" inside the frame; after that it shows the "Open your booking page" link.

Your site's security policy

If your site sends a Content-Security-Policy, allow the script and the frame:

script-src https://book.example.com; frame-src https://book.example.com

Add these to the directives you already have. The two failures look different:

  • If script-src blocks embed.js, the script never runs. Nothing is added to the page: no frame and no "Book online" or "Open your booking page" link, and a popup <button> does nothing when clicked (a popup <a href> just follows its link).
  • If frame-src blocks the frame, or your site isn't on the list, the page never loads, and after about 8 seconds the visitor sees the "Book online" link (or "Open your booking page" for a booking link).

Tracking bookings

When a customer finishes booking, a booker:booked event fires on the inline div, or on the popup's opener (the button or link that was clicked), and bubbles up to document. A popup opened from code with Booker.popup(slug) has no opener, so the event fires on the popup dialog and still bubbles to document. Listening on document works in every case:

document.addEventListener('booker:booked', function () {
  // for example, send a conversion to your analytics
});

The event carries no customer data, no appointment details and nothing else. It only says that a booking happened.

Single-page sites

The script looks for data-booker-page and data-booker-popup once, when the page loads. If your site adds markup later, call the script yourself:

// show the page inside an element you created
Booker.mount(element, { page: 'your-page-slug' });

// open the popup from your own code
Booker.popup('your-page-slug');

Troubleshooting

If a "Book online" link (or, for a booking link, "Open your booking page") appears instead of the booking page, the page didn't load in time (about 8 seconds). The link opens your booking page in a new tab, so customers can still book. The usual causes:

  • The site isn't listed. Check embed_origins with GET /api/v1/company, and that the entry matches the address bar exactly: https versus http, www versus none, and the port.
  • The public booking page is turned off for your company.
  • A booking link shows "Open your booking page" instead of the form: check the site is listed, and that the link is the request's current booking_url (rotating a link ends the old one).
  • Your site's frame-src blocks the frame. Check the browser console for a message naming frame-src, and add the booking host as shown above.

If nothing appears at all (no page and no link), or a popup button does nothing, script-src is probably blocking embed.js. The browser console names it; add the booking host to script-src.

After you change the list, the change takes up to a minute to reach every visitor while the booking service can reach its API. If it can't, a site you removed can keep working for up to an hour.

Let’s build the booking layer.

This local preview doesn’t submit access requests yet. The signup destination will be connected in a later version.