JavaScript integration
This option is the right fit if you have access to your website HTML and JavaScript and want to control where and how the widget opens.
What you need
- Online booking enabled for the location.
- The correct
slugfor the location or profile you want to show. - Access to the page where the code will be added.
Basic initialization
Add the following code to the page where you want to initialize the widget:
<script>
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
};
!(function (b, c, d) {
var a,
e = b.getElementsByTagName(c)[0];
b.getElementById(d) ||
(((a = b.createElement(c)).id = d),
(a.src = 'https://js-widget.reservation.studio/v2/widget.min.js'),
e.parentNode.insertBefore(a, e),
(a.onload = function () {
window.RSWidget(RSConfig);
}));
})(document, 'script', 'rs-booking-widget-js');
</script>
This loads the widget runtime and passes the core configuration. After that, you still need to decide how the user will open it.
What the required fields do
type
It defines what the widget opens. The confirmed values in the current integrations are:
location_profilelocation_serviceslocation_service_categorylocation_classesbusiness_profile
slug
This is the identifier of the profile the widget should open. If slug is missing or does not match the selected type, the widget will not load the correct target.
language
If you do not pass a language, the widget uses the browser language with fallback to supported languages. The confirmed values in the current code are:
bgende
Example:
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
language: 'en',
};
How the user opens the widget
From a page button or link
Use buttons_selector when you want the widget to open from one or more elements on the page:
<button class="open-booking-widget">Book now</button>
<script>
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
buttons_selector: '.open-booking-widget',
};
</script>
All elements matching the selector will open the same target.
Different targets with data-* attributes
If you want different buttons or links to open different targets, you can keep one shared buttons_selector and pass overrides through data-* attributes on the clicked element.
The confirmed per-element overrides in the current JavaScript widget are:
data-slugdata-typedata-languagedata-utm
Example:
<button class="open-booking-widget" data-slug="location-2">
Book at location 2
</button>
<button class="open-booking-widget" data-language="en">Book in English</button>
<button class="open-booking-widget" data-type="business_profile">
Open the business profile
</button>
<button
class="open-booking-widget"
data-utm='{"source":"newsletter","medium":"email","campaign":"spring"}'
>
Book from the newsletter
</button>
<script>
window.RSConfig = {
type: 'location_services',
slug: 'default-location',
buttons_selector: '.open-booking-widget',
};
</script>
On click, the widget takes the base configuration and overrides it only for the selected element.
How values are passed through data-*
data-slugoverrides the targetslug.data-typeoverrides the target type, for examplelocation_servicesorbusiness_profile.data-languagesets the language for one specific trigger.data-utmpasses a JSON object with:sourcemediumcampaigncontentterm
UTM-only example:
<button
class="open-booking-widget"
data-utm='{"source":"facebook","medium":"paid","campaign":"summer"}'
>
Book from the campaign
</button>
Important:
data-utmmust contain valid JSON;data-typeanddata-languageonly work with values the widget recognizes;- in the current confirmed code, the per-element overrides are
slug,type,language, andutm, not arbitrary nested parameters from older integrations.
From a sticky button
If you want the widget to open from a floating button, pass sticky_button:
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
sticky_button: {
text: 'Book now',
text_color: '#ffffff',
background_color: '#343232',
position: 'right-middle',
},
};
The confirmed sticky button fields in the current integrations are:
texttext_colorbackground_colortooltip_texttooltip_show_delaytooltip_expire_timeposition
The confirmed positions are:
top-left,top-middle,top-rightright-top,right-middle,right-bottombottom-left,bottom-middle,bottom-rightleft-top,left-middle,left-bottom
How to configure the modal widget
modal
You can limit the maximum modal size with:
max_widthmax_height
Example:
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
modal: {
max_width: '1320px',
max_height: '95%',
},
};
These settings apply only to the modal widget. They are not used for iframe embed.
UTM parameters
You can pass UTM parameters in the base configuration:
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
utm: {
source: 'facebook',
medium: 'paid',
campaign: 'summer',
},
};
Supported keys are:
sourcemediumcampaigncontentterm
If you do not pass UTM values, the widget may use:
- UTM parameters from the current URL;
- previously cached UTM values;
- the fallback
reservation.studio / js-widgetvalues when nothing else is available.
Connecting your website's cookie banner
If your website has its own cookie banner, you can pass the visitor's choice to the widget. The booking window then does not show a second cookie message, and your Facebook Pixel, Conversions API and Google Analytics follow the choice made in your website's banner.
Add this line to the code your banner runs when the visitor makes a choice, with the values of that choice:
window.RSWidgetConsent = { marketing: true, analytics: true };
marketing— marketing cookies: your Facebook Pixel and the Conversions API.analytics— analytics cookies: your Google Analytics.
Both are optional: a category you leave out counts as declined — without analytics, Google Analytics does not start in the widget. While the visitor has not yet answered your banner, you can set window.RSWidgetConsent = {};: our message is not shown, and nothing starts until they decide.
When the visitor declines or withdraws their consent, run the line with false:
window.RSWidgetConsent = { marketing: false, analytics: false };
Where exactly the code goes depends on your banner: look in its settings for a place for your own code when the visitor makes a choice. If your banner can only block scripts until consent — the way it blocks the Facebook Pixel on your website — add a line that declines both, without blocking, and below it one blocked line per category, marked the way your banner marks scripts:
// not blocked
window.RSWidgetConsent = { marketing: false, analytics: false };
// blocked until marketing consent
window.RSWidgetConsent = { ...window.RSWidgetConsent, marketing: true };
// blocked until analytics consent
window.RSWidgetConsent = { ...window.RSWidgetConsent, analytics: true };
What happens next:
- As soon as the line runs, the booking window does not show our cookie message. Until it runs, the visitor sees our message.
- With
marketing: true, your Pixel receives the events from the widget, and if you have turned on the Conversions API, bookings are also sent from the server. Withanalytics: true, the events also reach your Google Analytics. Withfalse, the matching ones are not sent. - If the visitor withdraws consent while the booking window is open, the Pixel and Google Analytics stop right away.
- The line works before or after the widget code, and as many times as the visitor changes their choice. It also works when the widget is added with the WordPress plugin.
- Your website's choice does not affect the Reservation.Studio tools — the "Cookie settings" link below the booking window is for them. There is only one Pixel in the window, though: if marketing is switched off there, your Pixel stops too.
- If the visitor reaches the page of another business inside the window, your website's choice applies to its Pixel, Conversions API and Google Analytics as well.
If our message still appears, check that the value is an object in which marketing and analytics are exactly true or false, and that it is set with window.RSWidgetConsent = …. Do not declare it with var: then only the first value counts, and later changes, withdrawal included, never reach the window. Set the whole object on every change — changing only one of its fields has no effect. With a wrong value or an unknown field, the browser shows a warning in the console.
Your website's banner and privacy policy must say that booking through the widget sends visitor data to Meta and to Google. You are responsible for this data towards your visitors.
When the booking page is in your own iframe
If you have embedded the booking page in an iframe on your website, the line works for it as well, as long as the widget script is on the page. The script also passes the Facebook, Instagram or Google ad click to the iframe, if the visitor came from such an ad. The script does not change the iframe itself: its address and settings stay as you set them. The WordPress plugin loads the script itself. For an iframe you added by hand, its address must be on https://reservation.studio — the script answers only pages from that address — and you add just the script to the same page, with no settings:
<script src="https://js-widget.reservation.studio/v2/widget.min.js" async></script>
Most common ready-made configurations
Button to a services catalog
<button class="open-booking-widget">Book now</button>
<script>
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
buttons_selector: '.open-booking-widget',
};
</script>
Sticky button
window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
sticky_button: {
text: 'Book now',
text_color: '#ffffff',
background_color: '#343232',
position: 'right-middle',
},
};
Different buttons to different targets
<button class="open-booking-widget" data-slug="location-1">Location 1</button>
<button class="open-booking-widget" data-slug="location-2">Location 2</button>
<button class="open-booking-widget" data-type="business_profile">
Business profile
</button>
<script>
window.RSConfig = {
type: 'location_services',
slug: 'default-location',
buttons_selector: '.open-booking-widget',
};
</script>
Button with dedicated UTM values
<button
class="open-booking-widget"
data-utm='{"source":"newsletter","medium":"email","campaign":"spring"}'
>
Book from the newsletter
</button>
When this approach is the right one
- when you have a custom website;
- when you want to manage the integration directly in page code;
- when you want a modal widget opened from your own button, link, or sticky button;
- when you do not want to depend on the WordPress shortcode generator.
Important
type + slugdefines the target, but you still need to decide how the user opens the widget.buttons_selector,sticky_button, andmodalare modal widget settings.data-*overrides belong to the JavaScript trigger flow. WordPress shortcode buttons and links use the same principle under the hood, but the shortcode usage is documented separately in WordPress integration.- In the current documentation, inline iframe embed is documented through the WordPress shortcode flow, not as a separate JavaScript API path.