BookerKit is a Zenoti booking widget that embeds on any page of your website. It handles the full booking funnel — service selection, provider selection, date and time, and deposit payment — and syncs every booking to Zenoti automatically.
Scope, before anything else.BookerKit covers the booking funnel only. Memberships, gift cards, packages, and loyalty programs stay native to Zenoti. If you need those on your own site, this isn't the tool for that.
This page shows exactly what the widget does, the three ways to embed it, what you can customize, and what data flows out the back when a customer books. For the broader context on why you'd want the booking funnel on your own domain in the first place, start with the full Zenoti webstore alternative explained.
What the booking flow looks like
The widget walks customers through four steps:
- Personal info — name, email, phone. Optional SMS verification (6-digit OTP via Twilio) to confirm the phone number before proceeding.
- Service selection — services are pulled live from your Zenoti account. Optional subcategories for large service menus.
- Provider selection— toggle this step on or off. When on, customers can pick a specific provider or select "Any Available."
- Date and time — availability is fetched in real time from Zenoti. The slot a customer picks is the slot that gets booked.
Optional steps you can layer in: credit card hold (no charge until service), upfront deposit (charged at booking, applied to the total), add-on services, and a gift card cross-promotion link.
You control which steps appear. A med spa that wants to skip provider selection and go straight to time slots can do that. A clinic that requires payment to hold an appointment can do that. All of it is configured from your dashboard.
Three ways to embed it
Method 1 — iframe (recommended)
Best for: Dedicated booking pages, WordPress, Wix, Squarespace, Shopify, and any site with enough vertical space to show the full widget inline.
The widget loads directly on the page inside an iframe. Customers see the full booking interface without clicking anything. No interaction required to reveal the form.
Install:
- Go to Widget → Code in your dashboard
- Select the "iframe (Recommended)" tab
- Click "Copy Code"
- Paste the code into your page's HTML where you want the widget to appear
- Adjust the height using the
data-heightattribute if your layout needs it
Platform-specific notes from the embedding guide:
- WordPress:Use the "Custom HTML" block
- Wix:Add an "Embed a Site" element
- Squarespace:Use a "Code Block"
- Shopify: Edit your theme template and paste at the desired location
Method 2 — Button trigger
Best for:Sites where you want to keep the existing page layout intact, multiple "Book Now" buttons across different pages, and mobile-first experiences.
A styled button renders on your page. When a customer clicks it, the widget opens in a slide-out panel from the right. The widget only loads on click — not on page load — so it doesn't add to your initial page weight.
The panel closes when the customer clicks outside it or presses ESC. On mobile, it opens full-width.
Example — multiple buttons on one page, one script tag:
<!-- Button 1: Haircut -->
<div data-bookerkit-widget="your-account"
data-mode="button"
data-button-text="Book Haircut">
</div>
<!-- Button 2: Massage -->
<div data-bookerkit-widget="your-account"
data-mode="button"
data-button-text="Book Massage"
data-background-color="#10b981">
</div>
<!-- Only include the script once -->
<script src="https://www.bookerkit.com/embed.js" defer></script>Each button has its own settings. One script tag serves all of them. See full button trigger instructions.
Method 3 — Custom trigger element
Best for:Developers building with React, Vue, or Tailwind who already have a button component in their design system and don't want to use the default BookerKit-styled button.
You wrap your own HTML element inside the BookerKit container div. The embed script detects your element and uses it as the trigger — your styling, BookerKit's behavior.
Basic example:
<!-- Custom button trigger -->
<div data-bookerkit-widget="your-account" data-mode="button">
<button class="my-custom-button">
Book Appointment
</button>
</div>
<script src="https://www.bookerkit.com/embed.js" defer></script>Tailwind example:
<div data-bookerkit-widget="your-account" data-mode="button">
<button class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg shadow-md transition-colors">
Schedule Now
</button>
</div>Any clickable element works as a trigger: <button>, <a>, <div>, <span>. See custom trigger instructions.
Customize without code
Appearance settings live in your BookerKit dashboard under Widget → Settings. Changes take effect immediately, and the dashboard shows a live preview as you adjust.
Global settings (apply to all embeds from your account):
- Primary color — the brand color used for buttons, CTAs, and interactive elements
- Button text color — white on dark backgrounds, dark on light ones
- Border radius — 0–32px (0px = sharp corners, 32px = pill)
- CTA text— the label on your main booking button; defaults to "Book Appointment"
Per-embed overrides (data attributes on the container div):
| Attribute | What it does | Example |
|---|---|---|
data-button-text | Different label per embed | "Book Botox" |
data-background-color | Button color for this embed only | "#3b82f6" |
data-text-color | Button text color for this embed | "#ffffff" |
data-border-radius | Corner rounding for this embed | "8px" |
data-sheet-title | Override the widget header title | "Book a Session" |
data-sheet-description | Override the widget header description | "Limited time offer" |
data-service-id | Pre-select a service, skips the selection step | "service-uuid" |
data-service-category | Custom category for tracking and webhooks | "Injectables" |
data-show-promos | Show or hide the promo banner (overrides widget settings) | "true" or "false" |
The data-service-idattribute is especially useful on service-specific landing pages. A "Book Botox" button on your Botox page can skip the service selection step entirely and drop customers straight into provider or time selection.
See all widget settings for the complete configuration reference.
Booking flow controls
These toggles are set per-account in your dashboard. They apply across all your embeds unless overridden.
What customers see:
- Show prices — display service prices in the widget, or omit them if you prefer to discuss pricing in person
- Show providers — add the provider selection step, or skip it for faster booking
- Show add-ons — let customers add enhancements during booking
- Show subcategories — better organization for large service menus
- Show only consultations — limit online booking to initial consultations
Friction controls:
- Require phone number — customers must provide a phone before proceeding
- Require SMS verification — Twilio sends a 6-digit OTP to verify the phone number; designed to reduce spam bookings and no-shows. Requires phone number to be enabled.
- Require payment method — collects credit card information to hold the appointment. No charge until service. Designed to reduce no-shows.
Payment options:
- Advanced deposit — collect a deposit at booking time, charged immediately and applied to the final total
- Gift card URL — link to your gift card purchase page; shown in the widget for cross-promotion
Booking policies:
- Cancellation fee — dollar amount charged for late cancellations
- Cancellation notice — minimum hours of advance notice required (typical: 24–48 hours)
- Late arrival policy — maximum minutes late before the appointment may be cancelled (typical: 15 minutes)
- Maximum booking window — how many days in advance customers can book
What flows out the back when someone books
Every completed booking syncs to Zenoti automatically. The booking appears in your Zenoti calendar as if a front-desk agent had created it — same customer record, same reporting, same calendar view.
Beyond the booking itself, two webhooks fire:
booking_started — fires after step 1 (personal info submitted). This is your abandoned-booking signal. If a customer enters their name, email, and phone and then drops off, you already have their contact details and the full tracking payload.
{
"event": "booking_started",
"timestamp": "2025-01-15T14:25:00.000Z",
"data": {
"sessionId": "abc123...",
"email": "customer@example.com",
"firstName": "Jane",
"lastName": "Doe",
"phone": "(555) 123-4567",
"accountName": "your-salon",
"serviceCategory": "Hair Services",
"tracking": { ... }
}
}booking_completed — fires on confirmation. Includes booking value, service details, provider, date and time, the full tracking object, and any offer code or add-ons used.
{
"event": "booking_completed",
"timestamp": "2025-01-15T14:30:00.000Z",
"data": {
"sessionId": "abc123...",
"bookingId": "zenoti-booking-id",
"reservationId": "zenoti-reservation-id",
"value": 85.00,
"serviceId": "service-123",
"serviceName": "Haircut",
"serviceCategory": "Hair Services",
"date": "2025-01-15",
"startTime": "14:30",
"firstName": "Jane",
"lastName": "Doe",
"email": "customer@example.com",
"phone": "(555) 123-4567",
"accountName": "your-salon",
"offerCode": "SUMMER2025",
"addOns": [
{ "id": "addon-1", "name": "Deep Conditioning", "price": 25.00 }
],
"tracking": {
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "summer-promo",
"term": "haircut near me",
"content": null
},
"click_ids": {
"gclid": "abc123...",
"fbclid": null,
"fbc": null,
"fbp": null,
"msclkid": null
},
"referral": {
"referrer": "https://www.google.com",
"landing_page": "https://yoursalon.com/book"
}
}
}
}Payload signing. Every webhook is signed with HMAC-SHA256. The signature is in the X-Bookerkit-Signature header as sha256=<hex>. Use your per-account webhook_secret (from your dashboard) to verify the signature before processing the payload.
To build your own integration on top of these payloads, see the Zenoti API surface BookerKit wraps.
GTM dataLayer events
The widget pushes an event to window.dataLayer at every step of the booking funnel. If you have GTM installed on your site, these flow automatically — no custom tagging required.
| Event | When it fires |
|---|---|
bookerkit_widget_opened | Widget loads or button is clicked |
bookerkit_booking_started | Customer completes step 1 (personal info) |
bookerkit_service_selected | Customer selects a service |
bookerkit_provider_selected | Customer selects a provider (if step is enabled) |
bookerkit_date_selected | Customer picks an appointment date |
bookerkit_time_selected | Customer selects a time slot |
bookerkit_booking_completed | Booking confirmed — your primary conversion event |
The bookerkit_booking_completed event carries the booking value (value parameter), so you can configure revenue tracking in Google Ads, Facebook, and GA4 directly from the dataLayer.
Events are delivered via postMessagefrom the widget iframe to your page. The embed script only targets origins listed in your widget's allowed_origins setting — it never broadcasts to '*'.
For session attribution data flowing into each event — UTM parameters, gclid, fbclid, msclkid, referrer, and landing page — see what session data is captured.
Set up in 5 minutes
- Sign up at /auth/signup
- Connect Zenoti — paste your Zenoti Center ID and API key in the dashboard. BookerKit verifies the connection before saving.
- Configure the widget — set your brand color, CTA text, booking policies, and which optional features you want enabled
- Test in the dashboard demo — walk through the full booking flow in preview mode before going live
- Copy the embed code from Widget → Code and paste it on your site
That's the full install for most operators. No developer required. For the step-by-step walkthrough, see the full setup guide.
Multi-location and per-page targeting
Multi-location is included in the single $349/month plan — no per-location add-ons. Each location gets its own widget configuration, its own embed code, and its own webhook destination if you want to separate the data.
On any single page, you can add as many booking buttons as you need. Each button can have its own data-service-id, data-button-text, and styling attributes. One shared script tag serves all of them.
For the full context on where BookerKit fits in the Zenoti ecosystem and a comparison of build/buy/default options, see the Zenoti webstore alternative explained and the decision guide for operators evaluating alternatives.
FAQ
Will the widget match my brand?
Yes. Set primary color, button text color, border radius, and CTA text in the dashboard. The widget loads on your domain. Per-embed data attributes let you override any of those settings for individual embeds on different pages.
Does it work with WordPress, Wix, Squarespace, and Shopify?
Yes. Each platform is documented in the embedding guide. Most require a Custom HTML block, Code Block, or Embed element — paste the code, and you're done.
What if a customer drops off mid-booking?
The booking_startedwebhook fires after step 1. You have their name, email, phone number, and the full UTM payload before they've confirmed. Send that to your CRM and run your own re-engagement sequence.
Are bookings real-time?
Yes. Service availability is fetched live from Zenoti when a customer reaches the time selection step. A booking made through BookerKit appears in Zenoti immediately.
Does it handle SMS verification?
Yes, optionally. When enabled, Twilio Verify sends a 6-digit OTP to the customer's phone number at step 1. Rate limits apply: 5 verifications per minute per IP, 3 per hour per phone number.
Does it work on mobile?
Yes. The button-trigger method opens full-width on mobile. The iframe method renders at whatever width its container allows.
Does it replace Zenoti?
No. Zenoti stays your operations system of record. BookerKit replaces the customer-facing booking funnel only. Bookings still flow into Zenoti, your staff works in Zenoti, and everything outside the funnel — memberships, packages, gift cards, loyalty — stays exactly where it is.
A Zenoti booking widget that syncs to Zenoti and gives marketing the data they need.
5 minutes to setup · 30-day free trial · Cancel anytime