Skip to main content

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 slug for 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_profile
  • location_services
  • location_service_category
  • location_classes
  • business_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:

  • bg
  • en
  • de

Example:

window.RSConfig = {
type: 'location_services',
slug: 'your-location-slug',
language: 'en',
};

How the user opens the widget​

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-slug
  • data-type
  • data-language
  • data-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-slug overrides the target slug.
  • data-type overrides the target type, for example location_services or business_profile.
  • data-language sets the language for one specific trigger.
  • data-utm passes a JSON object with:
    • source
    • medium
    • campaign
    • content
    • term

UTM-only example:

<button
class="open-booking-widget"
data-utm='{"source":"facebook","medium":"paid","campaign":"summer"}'
>
Book from the campaign
</button>

Important:

  • data-utm must contain valid JSON;
  • data-type and data-language only work with values the widget recognizes;
  • in the current confirmed code, the per-element overrides are slug, type, language, and utm, 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:

  • text
  • text_color
  • background_color
  • tooltip_text
  • tooltip_show_delay
  • tooltip_expire_time
  • position

The confirmed positions are:

  • top-left, top-middle, top-right
  • right-top, right-middle, right-bottom
  • bottom-left, bottom-middle, bottom-right
  • left-top, left-middle, left-bottom

How to configure the modal widget​

You can limit the maximum modal size with:

  • max_width
  • max_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:

  • source
  • medium
  • campaign
  • content
  • term

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-widget values when nothing else is available.

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. With analytics: true, the events also reach your Google Analytics. With false, 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.

note

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 + slug defines the target, but you still need to decide how the user opens the widget.
  • buttons_selector, sticky_button, and modal are 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.
💡No business profile yet?

To use these features in Business, you need a business profile. Create one and continue with setup.