Docs
Ctrl+K

Embed Widget

Embedding the booking widget on your own website.

Overview#

The Bokko embed widget allows you to embed the entire booking process into any website — under your own domain, without visitors ever leaving.

Tipp
If you only need a simple iframe or popup button embed code, you can find the ready-made HTML code for copy-pasting in the Booking page section of the Bokko dashboard. Detailed UI guide: Help: Embedding on your website.
Tipp
Using the embeddable widget requires at least a Bokko Starter subscription. For Free plans, the fallback link is displayed instead of the widget, which redirects the user to the booking page hosted by Bokko.
  • Two display modes: inline (embedded iframe) and popup (modal overlay).
  • Single script tag: https://booking.bokko.app/bokko-widget.js.
  • Automatic fallback: If the widget does not load, the visitor is directed straight to the booking page.
  • postMessage communication: Be notified about the booking status through events.

Quickstart#

Inline Mode#

The simplest embedding — the widget appears directly on the page:

html
<div class="bokko-widget" data-mode="inline" data-slug="my-salon">
  <a href="https://booking.bokko.app/my-salon">Open Booking</a>
</div>
<script src="https://booking.bokko.app/bokko-widget.js"></script>

The booking process appears in a modal window that opens on a button click:

html
<div class="bokko-widget" data-mode="popup" data-slug="my-salon"
     data-button-text="Book appointment!">
  <a href="https://booking.bokko.app/my-salon">Book appointment!</a>
</div>
<script src="https://booking.bokko.app/bokko-widget.js"></script>
Tipp
The <a> tag placed inside the <div> serves a dual purpose: it acts as a fallback link if JavaScript does not load, and remains accessible to the booking page in noscript environments.

Display Modes#

Inline#

An embedded iframe that appears directly on the page in place of the <div>.

  • Fills the parent element at full width.
  • Minimum height: 500px.
  • Automatic height adjustment: The widget sends a resize message when content height changes, and the iframe height adjusts accordingly.
  • Appears without borders, as a natural part of the page.

A modal overlay that opens on button click.

  • Maximum width: 580px, height: 90vh.
  • Centered with a background overlay.
  • Full-screen display for screen widths below 640px (mobile optimization).
  • Closing options:
  • Clicking the background (backdrop).
  • Escape key.
  • X button in the upper right corner.

Data Attributes#

You can configure the widget's behavior using data-* attributes on the <div> element:

AttributeRequiredValuesDefaultDescription
data-slugYesstringThe provider's URL slug
data-modeNoinline, popupinlineDisplay mode
data-button-textNostringBook appointment!Popup button text (only in popup mode)

The data-slug is the only mandatory attribute. It determines which provider's booking interface is displayed. The slug matches the identifier in the provider's public URL (e.g., booking.bokko.app/my-salondata-slug="my-salon").

Events (postMessage)#

The widget communicates with the host page via the window.postMessage API. Every message includes the source, version, and type fields.

Available Events#

EventPayloadDescription
readyThe widget has loaded and can be displayed
booking:confirmed{ slug: string }The booking was successfully created
booking:closedThe user closed the widget (popup mode)
resize{ height: number }The content height has changed (inline mode only)

Message Format#

Every postMessage follows this structure:

json
{
  "source": "bokko-widget",
  "version": 1,
  "type": "booking:confirmed",
  "payload": { "slug": "my-salon" }
}

Monitoring Events#

javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'bokko-widget') return;
  if (event.data.version !== 1) return;

  switch (event.data.type) {
    case 'ready':
      console.log('Widget loaded');
      break;
    case 'booking:confirmed':
      console.log('Successful booking:', event.data.payload.slug);
      // e.g., send analytics event, show thank you page
      break;
    case 'booking:closed':
      console.log('Widget closed');
      break;
    case 'resize':
      console.log('New height:', event.data.payload.height);
      break;
  }
});
Figyelmeztetés
Always verify the event.data.source and event.data.version fields before processing the message. Messages can come from any source via the postMessage API — without source and version checks, you might accidentally process messages from other scripts.

Fallback Behavior#

The widget has a built-in fallback mechanism in case the embedded iframe does not load:

  1. The script initializes the iframe.
  2. Wait for the ready event — for a maximum of 8 seconds.
  3. If ready does not arrive in time, the widget reverts to the fallback link.
  4. The fallback URL: https://booking.bokko.app/{slug}.
Tipp
Always place an <a> tag within the widget <div> with the appropriate booking URL. This ensures that the booking interface remains accessible in environments without JavaScript (noscript) and in case of loading errors.

Security Model#

Origin Validation#

The host-side widget script only accepts messages coming from Bokko booking origins:

  • https://booking.bokko.app
  • https://foglalas.bokko.app

Any postMessage arriving from another origin is silently discarded. This list is hardcoded in the widget JS — other origins (own staging, local dev iframe hosting) are not supported in v1.

Handshake Protocol#

The widget uses a simple handshake initiated by the iframe:

  1. The iframe sends a ready message after it has loaded.
  2. The host validates the origin (see above), then sends a handshake message back to the iframe with the targetOrigin: https://booking.bokko.app parameter.
  3. Further communication takes place over this verified channel.

Messages arriving before ready are ignored by the iframe; after ready, the host only processes those that contain the source: 'bokko-widget' and version: 1 fields.

PII Minimization#

postMessage messages only contain the provider's slug. The following are not transmitted via the widget:

  • Guest personal data (name, email, phone number).
  • Booking ID.
  • Payment information.

Accessibility#

The widget provides the following accessibility features:

  • Focus trap in popup mode: The Tab key navigates cyclically within the modal window, not exiting to the background.
  • Escape key closes the popup.
  • Backdrop click closes the popup.
  • ARIA attributes: The close button has an aria-label tag.
  • The fallback <a> link ensures basic accessibility for screen readers as well.

Testing#

Local Development#

The widget can be tested from a host page served from any origin (the widget does not check the host page origin) — however, the booking app serving the iframe is loaded under the booking.bokko.app domain via HTTPS. Locally:

  • Load an HTML file in any way (file://, localhost, custom domain) — the bokko-widget.js will run.
  • The iframe and postMessage communication only work if the iframe is served by the official booking.bokko.app (or foglalas.bokko.app).
  • Customization for your own staging / your own bookingapp instance is not supported in v1 (the ALLOWED_ORIGINS list is hardcoded).

Debugging#

  1. Network tab (browser DevTools): Check if bokko-widget.js loads successfully (200 OK).
  2. Console tab: You can monitor postMessage events using the listener described in the monitoring events section.
  3. Elements tab: Check if the iframe appears within the .bokko-widget div.

Checklist#

  • [ ] The data-slug attribute points to the correct provider.
  • [ ] The fallback <a> link contains the correct URL.
  • [ ] In popup mode, the button appears and is clickable.
  • [ ] The ready event arrives in the console.
  • [ ] In mobile view (below 640px), the popup is full-screen.
  • [ ] The Escape key closes the popup.