Skip to content

Advanced Usage ​

Analytics & GTM ​

The widget fires standard DOM CustomEvents with bubbles: true and composed: true. They cross the shadow DOM boundary and are visible at window level — no special configuration needed.

Event reference ​

EventFires whenDetail payload
booksea:widget-loadedWidget data has loaded{ companySlug }
booksea:availability-confirmedDate and service are confirmed as available{ service, date, pax }
booksea:checkout-startedGuest confirmed their details and the payment was prepared (clicked Next){ pricingUuid, total, currency }
booksea:payment-successStripe confirms the payment, or the booking needed no payment (e.g. a 100% promo code){ bookingReference, total, currency }
booksea:payment-failureA payment attempt failed, or the payment was cancelled{ errorCode } — see error codes

Listening to events ​

Subscribe to any event in plain JavaScript:

js
window.addEventListener('booksea:payment-success', function (e) {
  console.log('Booking confirmed:', e.detail.bookingReference);
});

Error codes ​

Possible values for errorCode in booksea:payment-failure:

CodeMeaning
payment_cancelledCustomer closed the payment window
payment_declinedCard was declined or its details were rejected (e.g. expired, wrong CVC)
payment_network_errorNetwork or connectivity failure during payment
payment_timeoutPayment window stayed open for more than 5 minutes without completing
payment_failedAny other failure

After a declined card or a network error, the payment window stays open so the guest can try again. The event fires once per failed attempt, so a single checkout can report several failures before a booksea:payment-success. Incomplete card fields are flagged by Stripe in the form and don't fire this event.

GTM bridge example ​

How you bridge events into dataLayer depends on your GTM setup. Here is one way to do it:

html
<script>
(function () {
  window.dataLayer = window.dataLayer || [];

  window.addEventListener('booksea:payment-success', function (e) {
    var detail = e.detail || {};
    window.dataLayer.push({
      event: 'payment_success',
      booksea_total: detail.total || '',
      booksea_currency: detail.currency || 'EUR',
      booksea_reference: detail.bookingReference || '',
    });
  });

  window.addEventListener('booksea:checkout-started', function (e) {
    var detail = e.detail || {};
    window.dataLayer.push({
      event: 'pay_now_click',
      booksea_total: detail.total || '',
      booksea_currency: detail.currency || 'EUR',
    });
  });
})();
</script>

Umami bridge example ​

Umami records page views automatically, but not custom DOM events. Forward the widget's events with umami.track() by adding this to the page that hosts both the widget and your Umami script:

html
<script>
(function () {
  [
    'booksea:widget-loaded',
    'booksea:availability-confirmed',
    'booksea:checkout-started',
    'booksea:payment-success',
    'booksea:payment-failure',
  ].forEach(function (name) {
    window.addEventListener(name, function (e) {
      var data = Object.assign({}, e.detail);
      delete data.bookingReference; // analytics doesn't need the booking id
      if (window.umami) window.umami.track(name, data);
    });
  });
})();
</script>

Each event then appears in Umami's Events view under its booksea: name, with the detail fields (total, currency, errorCode, …) as event properties.

Load the Umami script in the page <head> so it is ready before the widget fires booksea:widget-loaded. Events fired before Umami has loaded, or while it is blocked by an ad blocker, are skipped.