Website / JavaScript API

Website

JavaScript API

Every widget command, option, callback and browser event.

The widget's JavaScript API is a single global function, cauliflower(command, ...args), plus a window.Cauliflower object with the same methods. This page lists every command, option, callback and event. For installation and a guided setup, start with Website widget.

Calling commands

The loader snippet defines cauliflower() as a queue before embed.js arrives. Commands you call early are stored and run, in order, as soon as the script loads. After that, calls run immediately.

JavaScript
cauliflower("init", { workspace: "acme" });
cauliflower("identify", { email: "[email protected]" });
cauliflower("form", { router: "inbound", selector: "#demo-form" });

Once embed.js has loaded, window.Cauliflower exposes the commands as methods, which is convenient when you want a return value:

JavaScript
const result = await window.Cauliflower.route({ router: "inbound", lead: { email: "[email protected]" } });

cauliflower("route", …) returns the same promise once the script has loaded, but returns nothing while calls are still being queued. Use callbacks or events when you can't be sure the script has loaded. Unknown commands log a warning, and errors thrown by a command are logged to the console instead of breaking your page.

Commands

CommandArgumentsReturns
init{ workspace, host? }Nothing
identifyfields objectNothing
formForm optionsNothing
routeRoute optionsPromise of the route response
open{ link, prefill?, ...callbacks }Nothing
inline{ target, link?, token?, prefill? }The created iframe
closeNoneNothing
onevent, handlerNothing

init

Sets the workspace. Call it before any other command.

OptionTypeDescription
workspacestringYour workspace slug, for example acme. Required.
hoststringBase URL of your Cauliflower server. Defaults to the origin embed.js was loaded from, so you only need it when you serve the script from somewhere else.

identify

Stores lead fields for the rest of the page view. They're merged into every route call (values passed to route win) and used to prefill booking links opened with open and inline. Only string values are used for prefill.

JavaScript
cauliflower("identify", { email: "[email protected]", name: "Jane Cooper", company: "Acme" });

form

Binds one or more forms to a router. On submit, the form's fields are routed and the outcome is shown to the visitor.

OptionTypeDefaultDescription
routerstringRequiredRouter slug or rtr_… id.
selectorstring"form"CSS selector for the forms to bind. Without selector or form, every form on the page is bound.
formHTMLFormElementA form element to bind instead of a selector.
mapobjectCopies your field names to Cauliflower's: { email: "contact_email" }.
submit"prevent" or "after""prevent""after" submits the form natively once the modal closes.
beforeRoutefunctionReceives the collected fields. Return the fields (modified or not) to continue, or false to skip routing.
source"widget" or "link""widget"The router entry point to use. "widget" is the Website form entry point; "link" is the Router link entry point used by the hosted router page.
CallbacksfunctionsAny of the callbacks.

When selector matches nothing yet, the widget keeps checking for about 10 seconds so forms rendered after page load are still bound. A form is never bound twice.

route

Routes a lead you've collected yourself and shows the outcome exactly like a bound form.

OptionTypeDescription
routerstringRouter slug or rtr_… id. Required.
leadobjectThe lead's fields. An email is required.
source"widget" or "link"Entry point. Defaults to "widget" (the router's Website form entry point).
CallbacksfunctionsAny of the callbacks.
JavaScript
cauliflower("route", {
  router: "inbound",
  lead: { email: "[email protected]", first_name: "Jane", company: "Acme", company_size: "201-1000" },
  onBooked: function (meeting) {
    console.log("Booked with", meeting.host.name, "at", meeting.start_time);
  },
  onDisqualified: function (result) {
    console.log("Disqualified:", result.reason);
  },
});

The promise rejects when the request fails, for example when the email is missing, the router is paused or doesn't accept website submissions, the site isn't an allowed origin or the visitor hits the rate limit. The error event fires in the same cases.

open

Opens a booking link in the modal.

OptionTypeDescription
linkstringThe meeting type's slug. Required.
prefillobjectValues for the form: name, email, phone and question keys or lead fields. Merged over identify values.
onBooked, onClosefunctionsSee callbacks.
JavaScript
document.querySelector("#talk-to-sales").addEventListener("click", function () {
  cauliflower("open", { link: "product-demo", prefill: { email: "[email protected]" } });
});

inline

Embeds a booking page inside an element on your page. The iframe fills the element's width, starts at 640px high and resizes to fit its content as the visitor moves through the steps.

OptionTypeDescription
targetstring or HTMLElementSelector or element to render into. Its current content is replaced. Required.
linkstringA meeting type slug.
tokenstringA router booking token, for example from a REST API routing response. Use instead of link.
prefillobjectPrefill values, as for open. Used with link.
HTML
<div id="calendar"></div>
<script>
  cauliflower("inline", { link: "product-demo", target: "#calendar", prefill: { company: "Acme" } });
</script>

Inline embeds don't take callbacks. Listen for the booked event instead.

close

Closes the open modal or message card, if any. The close event fires with reason: "user".

on

Registers a handler for a widget event. Handlers registered with on receive the event's data as their only argument.

JavaScript
cauliflower("on", "booked", function (meeting) {
  window.dataLayer && window.dataLayer.push({ event: "meeting_booked", host: meeting.host.name });
});

Callbacks

Callbacks are passed in the options of form, route and open, and only fire for that call.

CallbackArgumentWhen it runs
onRoutedRoute responseThe router returned a decision, whatever the outcome. Runs before anything is shown.
onBookedBooked meetingThe visitor booked a meeting in the modal.
onDisqualifiedRoute responseThe outcome is disqualified.
onAssignedRoute responseThe outcome is assigned.
onCloseNoneThe modal or message card closed, for any reason.

For a lead sent to a calendar, the order is onRouted, then onBooked if they book, then onClose.

Events

Events fire for every widget interaction on the page, no matter which command started it. Subscribe with on, or listen for the matching cauliflower:<event> browser event on window, where the data is in event.detail.

EventDataFires when
open{ url }A booking page opened in the modal.
routedRoute responseA routing request succeeded, whatever the outcome.
bookedBooked meetingA meeting was booked in a modal or an inline embed.
disqualifiedRoute responseA lead was disqualified.
assignedRoute responseA lead was assigned an owner without a meeting.
close{ reason }A modal or message card closed.
errorErrorA routing request failed.

reason is "user" when the visitor closed it from your page (close button, backdrop click or Escape) or you called close. It's "done" when the booking page closed itself, for example with its Close button after booking, or when the widget replaced one modal with another.

JavaScript
window.addEventListener("cauliflower:routed", function (e) {
  console.log("Outcome:", e.detail.outcome);
});

window.addEventListener("cauliflower:booked", function (e) {
  console.log("Meeting", e.detail.uid, "starts", e.detail.start_time);
});

Browser events are handy when another script, such as your analytics or tag manager, needs to react without touching the widget setup.

Route response

route, onRouted, onDisqualified, onAssigned and the routed, disqualified and assigned events all receive this object.

FieldTypeDescription
outcomestringbook, assigned, disqualified, redirect, no_match or error. error means the path couldn't run, for example because nobody was available to host.
tokenstring or nullBooking session token when the outcome is book.
booking_urlstring or nullThe router booking page, https://cal.example.com/r/<token>. Valid for 7 days.
embed_urlstring or nullThe same page with ?embed=1, which the modal loads.
messagestring or nullThe calendar headline for book, or the path's message for disqualified and assigned.
redirect_urlstring or nullThe URL of the path's Redirect step. The widget follows it for redirect, disqualified and assigned outcomes. Always null for book: redirects after booking are handled by the booking page.
redirect_delay_secondsnumber or nullSeconds to show the message before redirecting.
reasonstring or nullThe disqualification reason, such as "Personal email".
meeting_typeobject or null{ title, duration_minutes } of the meeting type for book.
assigned_userobject or null{ name } of the chosen rep when the router picked one person, such as the record owner or the assignee of an assign step.
brandobject{ name, color } of your workspace.
JSON
{
  "outcome": "book",
  "token": "q3Zt8kLm…",
  "booking_url": "https://cal.example.com/r/q3Zt8kLm…",
  "embed_url": "https://cal.example.com/r/q3Zt8kLm…?embed=1",
  "message": "Pick a time with one of our specialists",
  "redirect_url": null,
  "redirect_delay_seconds": null,
  "reason": null,
  "meeting_type": { "title": "Product demo", "duration_minutes": 30 },
  "assigned_user": null,
  "brand": { "name": "Acme", "color": "#1f8a5b" }
}

Booked meeting

onBooked and the booked event receive the meeting as the booking page saw it:

FieldDescription
uidThe booking's public id, also used in the manage URL.
titleMeeting type name.
start_time, end_timeISO 8601 timestamps.
timezoneThe invitee's time zone.
host{ name } of the host.
meeting_urlVideo link, if any.
locationLocation text, such as "Google Meet" or an address.
manage_urlhttps://cal.example.com/booking/<uid>, where the invitee can reschedule or cancel when the meeting type allows it.
can_reschedule, can_cancelWhether the meeting type lets the invitee reschedule or cancel the booking themselves.
confirmation_messageThe meeting type's confirmation message, or null.

Data attributes

For simple pages you can skip JavaScript entirely:

AttributeOnEffect
data-workspaceThe embed.js script tagSets the workspace without calling init.
data-cauliflower-routerA formBinds the form to this router slug, like form.
data-cauliflower-submit="after"A form with data-cauliflower-routerSubmits the form natively after the modal closes.
data-cauliflower-linkAny elementOpens this booking link in the modal on click, like open.
HTML
<script src="https://cal.example.com/embed.js" data-workspace="acme" async></script>

<form data-cauliflower-router="inbound" data-cauliflower-submit="after" action="/thanks" method="post">
  <input name="email" type="email" required />
  <button type="submit">Request a demo</button>
</form>

<a href="#" data-cauliflower-link="product-demo">Book a call</a>

data-workspace only works on a plain script tag like the one above, not with the loader snippet. A plain script tag doesn't define the cauliflower() queue, so use the loader snippet if you also call commands. Attributes are read once when the page loads; bind elements added later with form or open.