If you are migrating from Booking Widget v2 to Booking Widget v3, please consult the following document to learn what has changed and how to update your implementation.
To facilitate the implementation of the booking widget, you may use the Booking widget v3 code generator. However, the generator does not include all properties; consult the below section for a complete list.
Properties
Here is a complete list of properties supported by the Booking widget v3. A button can be assigned one or several of these properties. Some properties have limited support (*).
Properties | Description |
apiKey | The Merchant API Key; mandatory. |
mode* | Determine whether the widget will be displayed in iFrame or popup. Only iFrame is currently supported. |
iframeId | User-defined id; can be used to assign a top level style to Book Now. |
language | The language in which the booking widget will be presented. |
fallbackLanguage | The language in which the booking widget will be presented when translations aren’t available in the chosen language. |
See relevant section. | |
locationCategory | Make the user select a region when booking ("bookingFlow" must be set to "locations") |
serviceTags | Filter the service list by service tag(s), defined in the back office. |
locationTags | Filter stores by location tag(s), defined in the back office. |
serviceCategoryId | Preselect a service category when opening the booking widget. |
serviceId | Preselect a specific service when opening the booking widget. |
staffId | Automatically set the staff ID when a service is selected. When used, a serviceId must be provided. |
groupEventId | Preselect a specific group event when opening the booking widget. |
groupEventDate | Filter group events by date when opening the booking widget; when used, a valid service ID of type ‘group reservation’ must be provided. |
onClose | Callback function that receives an object as its argument when the widget is closed. |
onBookedRedirectTo | Redirect URL when a booking is created or updated successfully. |
onAbortRedirectTo | Redirect URL when Booking Widget is closed without a successful booking. |
googleTag | gtag() function to send Google Tag Manager events to. |
showDescriptions | Display merchant, location, category, and service extended descriptions:
|
client | Set of properties used to prefill the client section. For more information, consult the "Client object" section. |
hideSteps | Hide the store selection step, service selection step and/or the staff selection step (will only take effect if the applied filters generate only 1 result or if there is a direct match).
These keywords may be combined for further filtering. |
acquisitionChannel | The booking's acquisition channel (i.e. source) obtained upon booking creation. Value defined by the business. |
Implementation
To implement a booking button to your webpage, the below javascript must be included in the header of your page’s HTML code. Select the URL based on your hosting region.
North America
<head>
<script src="https://www.booxi.com/booknow/booknow.js" async="">
</script>
</head>
Europe
<head>
<script src="https://www.booxi.eu/booknow/booknow.js" async="">
</script>
</head>
Implemented Button
Online booking can be implemented into your webpage by mapping a button’s “onclick” event to BookNow.open(...) . Doing so requires configuring properties at the time the function is called. As shown below, the function call must be made between quotes, your data delimited between brackets and parameters between single quotes.
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE', language:'en'})">
Book Now
</button>
</body>
The following example shows how to create a pair of buttons with different properties:
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
language:'fr', bookingFlow:'locations', mode:'iframe'})">
Réserver
</button>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
language:'en', serviceTags:'athome'})">
Book Now
</button>
</body>
The resulting buttons look like this:
Automatically Loading the Booking Widget on a Landing Page
The Booking Widget can be automatically launched upon loading a webpage. This feature can be used to prompt the widget for a specific store, a set of services or for a specific event. For more information, see here --- article.
Customizing the Location Booking Flow
By default, the booking widget will open to a specific location. However, you can apply different configurations to order the booking steps as you see fit.
Using the bookingFlow Property
Using the bookingFlow property allows you to set how the widget will be prompted.
Values | Definition |
locations | When setting the booking flow to “locations”, clients will be asked to select a store location before proceeding further with their booking. |
This setting is only relevant if there are multiple stores associated with your account.
The following examples showcase how to manually set the “bookingFlow” property in your HTML code.
<!-- Set booking flow to “locations” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE', bookingFlow:'locations'})">
Select Store
</button>
</body>
The booking flow can be further supplemented with the geolocation option allowing clients to select stores sorted by proximity. To activate this, contact your Booxi representative.
The above code will display all store locations in the widget (maximum 50). If stores are categorized or sorted by regions, the property “locationCategory” can be employed to require the user to select a category or region instead of listing all stores at once.
Using the locationCategory Property
The property “locationCategory” can be used to supplement a “locations” booking flow. By activating this property, users will be required to select a region, regardless of how many stores a merchant has. The widget will display all stores assigned to the selected region. Note that the property “bookingFlow” must be used and set to “locations” for this to work as expected.
The following example shows how to activate the “locationCategory” property.
<!-- Set booking flow to “locations” and enable “locationCategory” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
bookingFlow:'locations',
locationCategory:'required'})">
Select Store </button>
</body>
This feature can be disabled by setting its value to ‘default’ or by removing it entirely; in this case, the first store category in the list will be preselected.
<!-- Set booking flow to “locations” and disable “locationCategory” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
bookingFlow:'locations',
locationCategory:'default'})">
Select Store </button>
</body>
To further control and filter the content displayed by the widget, you must employ location and service tags.
Using Location and Service Tags
Location and service tags are defined and assigned in the Back Office. They can then be used as parameters to filter content.
The following examples showcase how to include and format serviceTags and locationTags.
Single Location Tag
<!-- Filter stores assigned with the tag “downtown” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
bookingFlow:'locations',
locationTags:'downtown'})">
Book Now
</button>
</body>
Single Service Tag
<!-- Filter services assigned with the service tag “vip” -->
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
serviceTags:'vip'})">
Book Now
</button>
</body>
Locations can also be filtered using serviceTags as its parameter (i.e. only the locations which contain services that have the specified tag(s) will be shown.
Location Tag Using serviceTags
<!-- Filter locations offering at least one service with the tag “vip” -->
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
bookingFlow:'locations',
locationTags:'service:vip'})">
Book Now
</button>
</body>
Combining Tags using Logical Expressions
Service and Location tags can be combined to create complex filters using logical expressions. To combine tags as an “AND” expression, separate each tag with a comma “ , ”; to combine tags as an “OR” expression, separate each tag with a pipe “ | ”. See below examples for proper formatting and usage. Note that services will have to match all tags to appear as a result and only service tags support the “OR” expression.
AND : serviceTags: ‘A,B,C‘
The above will result in a match if an entry contains tag A and B and C.
OR : serviceTags: A|B|C
The above will result in a match if an entry contains A or B or C.
AND with OR: serviceTags: A|B , C|D
The above will result in a match if an entry contains A and B or C and D.
Multiple Tags using Logical Expressions
<!-- Filter locations assigned with the tag “downtown” and -->
<!-- offering at least one “vip” or “special” service -->
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
locationTags:'downtown',
serviceTags:'vip|special'})">
Book Now
</button>
</body>
Using the serviceId property
Use this property to open the booking widget with a preselected service ID.
<!-- Preselect a service ID” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
serviceId: 'YOUR_SERVICE_ID'})">
Book Now
</button>
</body>
Using the staffId property
Use this property to open the booking widget with a preselected staff ID. Note that this property also requires a valid service ID.
<!-- Preselect a staff ID” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
staffId: 'YOUR_STAFF_ID',
serviceId: 'YOUR_SERVICE_ID'})">
Book Now
</button>
</body>
When service ID is of type ‘group reservation’, only group events associated with the chosen staff ID parameter will be shown. (*Note: you may also combine the staffId property with the groupEventDate property, which will filter the results even further.)
Using the groupEventId property
Use this property to open the booking widget with a preselected group event ID; only the event corresponding to your chosen ID will be shown.
<!-- Preselect a group event ID” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
groupEventId: 'YOUR_GROUP_EVENT_ID'})">
Book Now
</button>
</body>
Using the groupEventDate property
Use this property to open the booking widget with a preselected group event date (must be in “YYYY-MM-DD” format); only group events whose start date occurs on the chosen date will be shown.
This property requires a valid service ID of type ‘group reservation’; if no valid service ID is passed and/or if the service ID is not of type ‘group reservation’, this parameter will be ignored.
<!-- Preselect a group event date” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
groupEventDate: 'YOUR_GROUP_EVENT_DATE',
serviceId: 'YOUR_SERVICE_ID'})">
Book Now
</button>
</body>
Using the availabilityTags Property
This property provides the ability to filter availability to time slots assigned with one or several tags. Each time slot supports up to 10 tags and 100 characters. Tags can be defined from the Booking API.
The following example shows how to include and format this property.
Single Availability Tag
<!-- List availabilities assigned with the tag “accessible” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
bookingFlow:'locations',
locationTags:'downtown'
availabilityTags: 'accessible'})">
Book Now
</button>
</body>
Multiple Tags Using Logical Expressions
<!-- Filter availabilities assigned with the tag “accessible” and “vip” -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
locationTags:'downtown'
availabilityTags: 'accessible,vip'})">
Book Now
</button>
</body>
Using the hidesteps property
Use this property to hide the service selection step and/or the staff selection step.
Service selection: to apply, enter “service”. Note that this will only take effect if there is only 1 service to select (i.e. if the service filter tag(s) only generates 1 result or the merchant has only 1 service available) or the service was preselected by providing the service id.
<!-- Hide the service selection step -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
hideSteps: service})">
Book Now
</button>
</body>
Staff selection: to apply, enter “staff”. Take note that this will only take effect if your ‘Online Personnel Selection’ setting (Service > Booking rules) is set to either ‘Personnel selection” or ‘No Preference + Personnel selection’ and there is only 1 staff member to select, or the staff was preselected by providing the staff id.
<!-- Hide the staff selection step -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
hideSteps: staff})">
Book Now
</button>
</body>
You may combine keywords “service” and staff” to filter the selection even further. See example below: combination of (“service,staff”). Any combination of these keywords is allowed.
<!-- Hide the service and staff selection steps -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
hideSteps: service,staff})">
Book Now
</button>
</body>
Using the acquisitionChannel property
Use this property to tag your booking widget(s) with a custom acquisition channel value, which is used to identify the source of your bookings. This value will be included in the booking data.
Specifications
64 characters max (truncated if over 64 characters)
Supports the following characters:
Numbers, letters
+-.,_=
Spaces are not supported.
<!-- Assign an acquisition channel value -->
<body>
<button onclick="BookNow.open({apiKey: 'YOUR_API_KEY_HERE',
acquisitionChannel: "e-commerce"})">
Book Now
</button>
</body>
Callback Functions and Redirections
Callback Priority
Note that callback functions and redirections are subject to the following priorities:
Call Priority | Function |
First | onClose |
Second | onBookedRedirectTo / onAbortRedirectTo |
Third | merchant.shoppingCartUrl |
onClose
The callback function “onClose” receives an object as its argument when the widget is closed. That object contains booking data at the time of closure. It is therefore crucial to validate the value of “bookNowStatus” to identify if a booking has been successfully completed or aborted. When “onClose” is mapped, calls to that function will have priority over any URL redirection.
Redirect URLs
As an alternative to “onClose”, customers can be redirected to predefined URLs upon completing or aborting a booking. URLs must be assigned to their appropriate parameters (see below for reference and example).
onBookedRedirectTo
Redirect to the assigned URL once a booking is successfully created or updated. Upon such redirection the value of “bookNowStatus” is “booked”.
onAbortRedirectTo
Redirect to the assigned URL when a booking is aborted. Upon such redirection, the value of “bookNowStatus” is “abort”.
<!-- Assigning redirect URL for successful and aborted booking -->
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
onBookedRedirectTo:'https://booxi.com/thankyou.html',
onAbortRedirectTo:'https://booxi.com/home.html'})">
Book Now
</button>
</body>
Retrieving Booking Data
Booking data is passed as an argument to the callback function “onClose” or as a URL query parameter named booking if URL redirection is used. Its value is a JSON object encoded as a base 64 UTF-8 string.
To retrieve booking data, follow these steps (assuming “query” has been previously parsed):
Create a temporary buffer.
Decode data from the base64 string using Buffer.from().
Parse the resulting string into a JSON using JSON.parse().
Here’s an example for URL redirection:
// Assuming query has been extracted from URL
const buffer = Buffer.from(query.booking, "base64");
const booking = JSON.parse(buffer.toString("utf-8"));
Booking data properties:
Properties | Type | Description |
bookNowStatus | string | Whether the booking is complete or was aborted.
|
bookingMethod | string | Type of booking:
|
bookingId | string | ID associated with the completed booking. |
groupEventId | integer | Group event ID for group reservations. |
staffId | integer | ID of the selected staff, if any. |
staffFirstName | string | First name of the selected staff, if any. |
staffLastName | string | Last name of the selected staff, if any. |
startsOn | string | Booking start date/time in RFC-3339/ISO-8601 format (ex. 2021-01-02T12:34:56Z) |
clientCount | integer | Number of attendees. |
payment | object | Information about the Payment stored as an object. |
client | object | Information about the Client stored as an object. |
items | array | Array of Items (services) associated with a booking. |
clientAvailability | array | Array of availability. |
merchantId | integer | ID of the merchant |
bizName | string | Name of the merchant |
bizAddress | object | Containing:
|
merchantGroupLocationCode | integer | Store number identifying a store that is part of a group |
Properties may not be set if they are irrelevant to the booking method or if the client didn’t provide meaningful values. If a booking status is set to “abort”, do not rely on the information since it will be partial.
Payment
Properties | Type | Description |
onlinePaymentAmount | string | Payment amount due. |
onlinePaymentId | string | Unique ID associated with a payment. |
total | string | Total payment amount due. |
Example of a “payment” found in the URL query parameter “booking”.
"payment":
{
"onlinePaymentAmount": "1.00",
"onlinePaymentId": "P012345",
"total": "1.00"
}
Items
Properties | Type | Description |
serviceId | integer | ID of the service associated with an appointment or reservation. |
serviceName | string | Name of the service. |
serviceCategoryName | string | Name of the service's category. |
productId | string | User-defined product ID. Can be assigned to a service in the Back Office once online payment and shopping cart are enabled. |
reservedTimeSpan.duration | integer | Duration of the booked appointment or reservation, in minutes. |
Example of an “item” found in the URL query parameter “booking”.
"items":
[
{
"serviceId": 789,
"serviceName": "Group Activity",
"serviceCategoryName": "Main Services",
"productId": "PRODUCT-123",
"reservedTimespan": { "duration": 60 }
}
]
Using the showDescriptions Property
The property “showDescriptions” provides the ability to display merchant, location, category and service extended descriptions. By default, this property is set to “expand”, where it is initially collapsed with a button to expand. To display all descriptions, set its value to ‘always’, to hide set its value to ‘never’.
Implementation
<body>
<button onclick="BookNow.open({apiKey:'YOUR_API_KEY_HERE',
showDescriptions: 'always'})">
Book Now
</button>
</body>
Client Object
The table below lists all supported properties of the object “client” used to prefill the client section. Note that fields marked with an asterisk (*) are mandatory when prefilling the client info. Furthermore, fields in italic are not returned by the callback function and are not available when retrieving the booking data.
Properties | Type | Description |
client.IsAttending | boolean | Is the client attending? Default value is true. |
client.firstName* | string | Client’s first name. |
client.lastName* | string | Client’s last name. |
client.email | string | Client’s email address. |
client.mobilePhoneNumber | string | Client’s mobile phone number in E164 format. If an invalid phone number is provided, the field will be left blank. |
client.remindByEmail | boolean | Whether a client requests reminders via email. |
client.remindBySMS | boolean | Whether a client requests reminders via text message. |
client.address | array | Array of property describing a client’s address. If set, street, city, country and postal code are mandatory. If the address is located in North America (US and Canada), its state is also mandatory. |
client.address.street* | string | Client’s street address. Mandatory field. |
client.address.city* | string | Client’s city. Mandatory field. |
client.address.country* | string | Client’s country. Mandatory field. |
client.address.state* | string | Client’s state, province or territory Mandatory field (US and Canada only). |
client.address.postalCode* | string | Client’s ZIP or postal code. Mandatory field. |
client.additionalRequest | string | Client’s request. |
client.hideAdditionalRequest | boolean | Hides the additional request field from the client info form. Default value is "false". |
client.membershipId | string | Client’s membership Id. |
client.customerId | string | Client’s customer Id. |
client.skipClientForm | boolean | Skips the client info form if provided info is valid and complete. |
<button onclick="BookNow.open({
apiKey: 'YOUR_API_KEY_HERE',
client:
{
clientCount: 1,
isAttending: true,
firstName: 'John',
lastName: 'Smith',
email: 'john.smith@example.org',
mobilePhoneNumber: '+17219992437',
remindByEmail: true,
remindBySMS: false,
address: {
street: '42b Avenue',
city: 'Montreal',
country: 'CA',
state: 'QC',
postalCode: 'L5W0A1'
},
additionalRequest: 'Must leave before 2PM'
hideAdditionalRequest: true,
membershipId: 'MEMBER-123',
customerId: 'CUSTOMER-123',
skipClientForm: false
}
})">
Book Now
</button>
Supported Languages (ISO 639-1)
Here is the list of languages supported by the booking widget. For best results, provide both a language and region (e.g. fr-CA is preferred over just fr). Refer to examples provided below.
Language | Code | Language | Code | Language | Code |
Bulgarian | bg | French | fr | Romanian | ro |
Chinese | zh | Greek | el | Russian | ru |
Czech | cs | Italian | it | Spanish | es |
Danish | da | Japanese | ja | Swedish | sv |
Deutsch | de | Korean | ko | Thai | th |
Dutch | nl | Polish | pl | Turkish | tr |
English | en | Portuguese | pt |
|
|
Language + Region
en-KW: English, Kuwait
fr-FR: French, France region
fr-NC: French, New Caledonia
zh-HK: Chinese, Hong Kong region
zh-TW: Chinese, Taiwan region
Any value assigned to the language property will supersede the language preferences set by a user in their browser or OS. If a customer wishes to display Book Now in the user's preferred language, the language property should be left unset.
The property “fallbackLanguage” can be used when English is not the default fall back language or for unsupported languages or missing translations.
Country Codes (ISO 3166)
Country, Region | Code | Country, Region | Code | Country, Region | Code |
Algeria | DZ | Guyana | GY | Oman | OM |
Andorra | AD | Haiti | HT | Panama | PA |
Antigua | AG | Honduras | HN | Paraguay | PY |
Argentina | AR | Hong Kong | HK | Peru | PE |
Aruba | AW | Hungary | HU | Philippine | PH |
Australia | AU | Iceland | IS | Poland | PL |
Austria | AT | India | IN | Portugal | PT |
Barbados | BB | Indonesia | ID | Puerto Rico | PR |
Belgium | BE | Ireland | IE | Qatar | QA |
Bermuda | BM | Israel | IL | Reunion | RE |
Brazil | BR | Italy | IT | Romania | RO |
Bulgaria | BG | Jamaica | JM | Saint Lucia | LC |
Canada | CA | Japan | JP | Saint Martin | MF |
Cayman Islands | KY | Kenya | KE | Saudi Arabia | SA |
Chile | CL | Korea | KR | Senegal | SN |
Colombia | CO | Kuwait | KW | Singapore | SG |
Costa Rica | CR | Latvia | LV | Slovakia | SK |
Croatia | HR | Lebanon | LB | Slovenia | SI |
Cyprus | CY | Lithuania | LT | South Africa | ZA |
Czech Republic | CZ | Luxembourg | LU | Spain | ES |
Denmark | DK | Macau | MO | Sweden | SE |
Dominican Republic | DO | Malaysia | MY | Switzerland | CH |
Ecuador | EC | Malta | MT | Taiwan | TW |
Egypt | EG | Martinique | MQ | Thailand | TH |
El Salvador | SV | Mauritius | MU | The Bahamas | BS |
Estonia | EE | Mexico | MX | Trinidad & Tobago | TT |
Finland | FI | Morocco | MA | Tunisia | TN |
France | FR | Netherlands | NL | Turkey | TR |
French Guiana | GF | New Caledonia | NC | United Arab Emirates | AE |
Germany | DE | New Zealand | NZ | United Kingdom | GB |
Ghana | GH | Nicaragua | NI | United States | US |
Greece | GR | Niger | NE | Uruguay | UY |
Guadeloupe | GP | Nigeria | NG | Vietnam | VN |
Guatemala | GT | Norway | NO | Zimbabwe | ZW |
Rendering in a Webview
If you intend to use the Booking Widget in a webview within a mobile application, the widget may be displayed in 2 columns (like it would be on PC) or as a single column but with very small font making its content unreadable. To avoid such problems, add the following code in the <head> tag of the web page containing the widget.
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
Stack Order
The CSS property “z-index” can be used to set the stack order in which the booking widget will be displayed.
CSS Syntax
z-index: auto | number | initial | inherit;
Implementation
In a .CSS file, create an ID selector with a “z-index” property and assign it a numeral value. Elements with higher stack order are displayed in front of those with lower stack order.
CSS
<style>
#my_custom_iframe_id { z-index: 500;}
</style>
On your webpage, upon calling the method “BookNow.open()”, add the parameter “iframeId” and set its value as shown below.
HTML
<button onclick="BookNow.open({
apiKey: 'YOUR_API_KEY_HERE',
iframeId: 'my_custom_iframe_id',
})"> Book Now
</button>
UI Customization
All UI customizations are performed by Booxi and solely on a request basis. Contact your Booxi representative to make such a request.
Customizations are currently limited to:
Font Family*
Colors
UI Styles
For more information, consult the Widget Customization Guide.
If you're expecting to use a proprietary font or font without a free license, contact your Booxi representative.
Test and Validation
Before implementing any changes to your webpage, testing and validation can be performed on an unbound landing page or using an online HTML editor. For a simple solution use w3schools Tryit Editor.
Payment
The booking widget supports all methods of online payment.
By Email*
At Online Booking*
Capture Card Info*
Shopping Cart
*Requires Stripe integration
When booking a single service, the payment method is based on the service's online payment option. However, when booking multiple services at the same time, the payment option will be based on the following rules (in order of priority):
If one of the services is of type "At Online Booking", the payment will be processed through online booking.
If one of the services is of type "By email", the payment will be processed through email.
If one of the services is of type "Capture Card info”, the payment will be processed through the capture of the card info.
In other words, in case the chosen services have different payment options, the "At Online Booking" option will take precedence, followed by "By email", then "Capture Card info".
Limitations
The booking widget is limited in the following ways:
The property “mode” only supports “iFrame”.
The booking widget does not support rentals.
Google Analytics 4 Integration
To enable Google Analytics (GA4), consult the following integration guide. If you wish to integrate with Google Tag Manager, consult this article.