Skill Tracer
Skills › Marketing Skills › conversion-tracking › wix-scheduling.js

wix-scheduling.js

78 lines · skills/conversion-tracking/assets/snippets/wix-scheduling.js at 88c79f6

1/*! Wix Bookings conversion detection (MIT)
2 * Detects: booking made. Pushes dataLayer event: wix_appointment_scheduled
3 * From the conversion-tracking skill in Marketing Skills */
4(function () {
5 if (window.__ctDetectWixScheduling) return;
6 window.__ctDetectWixScheduling = true;
7 window.dataLayer = window.dataLayer || [];
8
9 // Wix Bookings checks out through Wix eCommerce. Once the order exists,
10 // the shared Thank You page reports a Purchase through Wix's own site
11 // analytics stream (window.wixDevelopersAnalytics). Its line items name
12 // the Wix app that sold them, so a booking is an item from Wix Bookings
13 // and a Wix Stores order is not. Only the event name, the line items'
14 // app IDs and the order ID are read, never the buyer's details.
15 var BOOKINGS_APP_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
16 var LISTENER_ID = 'ctRecipeWixScheduling';
17 var seen = {};
18 var registered = false;
20 function isBookingsItem(item) {
21 try {
22 return !!item && typeof item === 'object' && !!item.catalogReference &&
23 item.catalogReference.appId === BOOKINGS_APP_ID;
24 } catch (e) {
25 return false;
26 }
27 }
29 function orderIdOf(params) {
30 var id = params.orderId;
31 if (typeof id !== 'string' || !id) id = params.id;
32 return typeof id === 'string' && /^[A-Za-z0-9-]{1,64}$/.test(id) ? id : '';
33 }
35 function onWixEvent(name, params) {
36 try {
37 if (name !== 'Purchase' || !params || typeof params !== 'object') return;
38 var items = params.contents;
39 if (!items || typeof items.length !== 'number') return;
40 var booking = false;
41 for (var i = 0; i < items.length; i++) {
42 if (isBookingsItem(items[i])) { booking = true; break; }
43 }
44 if (!booking) return;
45 var orderId = orderIdOf(params);
46 if (!orderId || seen[orderId]) return;
47 seen[orderId] = true;
48 window.dataLayer.push({
49 event: 'wix_appointment_scheduled',
50 booking_id: orderId
51 });
52 } catch (e) {
53 // Never throw back into Wix's analytics.
54 }
55 }
57 // Wix doesn't replay earlier events to a late listener, so register as
58 // soon as the stream exists.
59 function register() {
60 if (registered) return true;
61 var wda = window.wixDevelopersAnalytics;
62 if (!wda || typeof wda.register !== 'function') return false;
63 try {
64 wda.register(LISTENER_ID, onWixEvent);
65 registered = true;
66 } catch (e) {}
67 return registered;
68 }
70 if (!register()) {
71 try { window.addEventListener('wixDevelopersAnalyticsReady', register); } catch (e) {}
72 var tries = 0;
73 var timer = setInterval(function () {
74 tries++;
75 if (register() || tries > 300) clearInterval(timer);
76 }, 100);
77 }
78})();