PageSourceSearch

https://www.mindbodyonline.com/modules/custom/e3_marketo-master/js/tealiumSubmit.js

js mindbodyonline.com collected 2026-10-02 08:29:15 UTC 11,987 bytes, 249 lines download raw bytes

1/*
2  Purpose: Send event data for form submissions through Tealium so that they can be used in Google Analytics and other tools.
3  Reference:
4    - https://docs.tealium.com/platforms/javascript/track/
5    - https://developers.marketo.com/javascript-api/forms/api-reference/
6  Area of use:
7    - All pages with forms.
8  How it works:
9    Set up a mapping between the Marketo form ID and a key in the formID2Key array. The key should be the tealium_event value.
10    In the eventNames object, set up a mapping between the tealium_event and an array that contains (in this order): event_category, event_action, event_detail.
11    The event_detail attribute can use {} to indicate the value should be grabbed dynamically. How the data is grabbed is defined in the detailGetters object.
12*/
13(function () {
14  'use strict';
15
16  // For some reason, if the same Marketo form exists more than once on a page, it will be submitted
17  // that number of times every time one of instances is submitted. This causes duplicate analytics data.
18  // In order to prevent this, we set a global variable to remember that this form was submitted and prevent it from being submitted again during the same page load.
19  window.marketoFormsSubmitted = new Set();
20
21  // The MktoForms2 object is the top-level publicly visible namespace for Marketo Forms2 functionality
22  MktoForms2.whenReady(function (form) {
23    let dataForTealium = '';
24
25    var formID2Key = {
26      // Map Marketo form IDs to eventNames (AKA Event Label in Google Analytics)
27      // Production
28      // This mapping should include every form in /admin/content/marketo-forms
29      // Grouped by event name
30      // Keep IDs in sync with e3_marketo_forms.js
31      "3196": "chilipiper_assignment", // FO - ChiliPiper Booking
32      "2987": "customer_inquiry", // FO - Customer Inquiry
33      "1508": "customer_referral", // FO - Customer Referral
34      "2765": "customer_referral", // FO - Customer Referral - French
35      "3590": "customer_referral", // FO - Customer Referral - Italian
36      "2766": "customer_referral", // FO - Customer Referral - Spanish
37      "2195": "email_preferences_update", // FO - Preference Center
38      "1065": "gated_content_download", // FO - Gated Learning Assets
39      "2473": "partner_referral", // FO - Business Partner Self Serve (AKA Partner Referral Program)
40      "1528": "research_interest", // FO - Participate in Research
41      "2535": "sales_inquiry", // FO - ClassPass Guarantee
42      "1560": "sales_inquiry", // FO - Get Started Multi-Step Demo Request
43      "3703": "sales_inquiry", // FO - Get Started Multi-Step Demo Request - French
44      "3709": "sales_inquiry", // FO - Get Started Multi-Step Demo Request - Italian
45      "3705": "sales_inquiry", // FO - Get Started Multi-Step Demo Request - Spanish
46      "1068": "sales_inquiry", // FO - Professional Services
47      "1311": "sales_inquiry", // FO - Sales Inquiry
48      "1318": "sales_inquiry", // FO - Sales Inquiry - French
49      "1319": "sales_inquiry", // FO - Sales Inquiry - German
50      "2985": "sales_inquiry", // FO - Sales Inquiry - Italian
51      "1317": "sales_inquiry", // FO - Sales Inquiry - Spanish
52      "3307": "sales_qualification", // FO - Sales Inquiry Secondary Form
53      "3507": "sales_qualification", // FO - Sales Inquiry Secondary Form - French
54      "3510": "sales_qualification", // FO - Sales Inquiry Secondary Form - German
55      "3514": "sales_qualification", // FO - Sales Inquiry Secondary Form - Italian
56      "3515": "sales_qualification", // FO - Sales Inquiry Secondary Form - Spanish
57      "3561": "sales_qualification", // FO - Paid Social Secondary Form
58      "3712": "sales_qualification", // FO - Paid Social Secondary Form - French
59      "3713": "sales_qualification", // FO - Paid Social Secondary Form - Italian
60      "3711": "sales_qualification", // FO - Paid Social Secondary Form - Spanish
61      "1067": "subscribe_request", // FO - Learning Digest
62      "1943": "subscribe_request", // FO - Learning Digest - English GB
63      "3735": "subscribe_request", // FO - Playlist subscription form
64      "1987": "subprocessor_notifications", // FO - Subprocessor Notifications
65      "1070": "webinar_register", // FO - Webinar (Recorded)
66      "1288": "webinar_register", // FO - Webinar (Upcoming)
67    };
68
69    // Make formID2Key globally accessible so that it can be used in e3_marketo_forms.js
70    window.formID2Key = formID2Key;
71
72    var eventNames = {
73      // Tealium Event Name is AKA Event Label in Google Analytics
74      // Map tealium_event to remaining event attributes
75      // "tealium_event" : ["event_category", "event_action", "event_detail", "business_email", "business_postal_code", "customer_vertical"]
76      /* Sales Conversion */
77      "customer_inquiry": ["sales_conversion", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // Existing customers raising their hand (not a net new lead)
78      "customer_referral": ["sales_conversion", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // Can become a lead in Salesforce
79      "partner_referral": ["sales_conversion", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // Can become a lead in Salesforce
80      "sales_inquiry": ["sales_conversion", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}","{customer_vertical}","{number_of_staff}"], // Can become a lead in Salesforce
81      /* Other */
82      "chilipiper_assignment": ["chilipiper_assignment", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // ChiliPiper Assignment
83      "sales_qualification": ["sales_qualification", "form_submit", "{page_name}", "{business_postal_code}"],  // Held in Marketo. This is the secondary form for the two-step sales inquiry flow (not a standalone form)
84      "email_preferences_update": ["consent_management", "form_submit", "{content_title}", "{business_email}", "{business_postal_code}"],
85      "gated_content_download": ["download", "form_submit", "{content_title}", "{business_email}", "{business_postal_code}"], // Held in Marketo
86      "research_interest": ["research_interest", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // Open to customers. Routed to Research team via Marketo
87      "subprocessor_notifications": ["legal_request", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"],
88      "subscribe_request": ["subscribe", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"], // Held in Marketo
89      "webinar_register": ["content_conversion", "form_submit", "{content_title}", "{business_email}", "{business_postal_code}"], // Held in Marketo
90      "email_collect": ["email_collect", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"],
91      "unnamed_form_submit": ["uncategorized", "form_submit", "{page_name}", "{business_email}", "{business_postal_code}"],
92    };
93
94    // For Google Analytics 4, there is a solution duct-taped together in Tealium
95    // See tag "GA4 (gtag.js) - www.mindbodyonline.com"
96    // It uses maps variables from this old GA event structure to the newer one
97    // For reference (last updated November 24, 2024):
98    // generate_lead = sales_inquiry, customer_referral, partner_referral
99    // generate_prospect = gated_content_download, webinar_register
100    // subscribe = subscribe_request
101
102    var buildTealiumData = function (form, context, key) {
103
104      var dataObj = {
105        "tealium_event": key,
106        "event_category": context[0],
107        "event_action": context[1],
108        "event_detail": context[2],
109        "business_email": context[3],
110        "business_postal_code": context[4],
111        "customer_vertical": context[5],
112        "number_of_staff": context[6],
113      };
114
115      // Support dynamic values in event_detail
116      var isInBrackets = dataObj.event_detail.match(/\{(.*?)\}/);
117      if (isInBrackets) {
118        let funcName = "get_" + isInBrackets[1];
119        if (functionExists(funcName)) {
120          dataObj.event_detail = detailGetters[funcName]();
121        }
122      }
123
124      // Replace {business_email} with dynamic value from form
125      dataObj.business_email = form.getValues()['Email'];
126
127      // Replace {business_postal_code} with dynamic value from geolocation cookie
128      dataObj.business_postal_code = ''; // Submit empty string if we fail to get a postal code for the user.
129      var geolocationCookie = document.Cookie.read("STYXKEY_mbGeolocation");
130      if (geolocationCookie) {
131        var geolocationInfo = JSON.parse(geolocationCookie);
132        var postalCode = geolocationInfo.postalCode;
133        if (postalCode) {
134          dataObj.business_postal_code = postalCode;
135        }
136      }
137
138      // Added {customer_vertical} to the data object with dynamic value from form
139      dataObj.customer_vertical = form.getValues()['Secondary_Market__c'];
140
141      //  Add order_id if it exists on the form
142      let orderIdValue = form.getValues()['tealiumOrderID'];
143      if (orderIdValue) {
144        dataObj.order_id = orderIdValue;
145      }
146
147      // Add business_phone if it exists on the form
148      let phoneValue = form.getValues()['basicPhone'];
149      if (phoneValue) {
150        dataObj.business_phone = phoneValue;
151      }
152
153      // Add number_of_staff if it exists on the form
154      let staffValue = form.getValues()['Number_of_Staff__c'];
155      if (staffValue) {
156        dataObj.number_of_staff = staffValue;
157      }
158      else {
159        dataObj.number_of_staff = '';
160      }
161
162      // Add is_this_your_full_time_job if it exists on the form (custom15)
163      let fullTimeJobValue = form.getValues()['custom15'];
164      if (fullTimeJobValue) {
165        dataObj.is_this_your_full_time_job = fullTimeJobValue;
166      }
167
168      // Add is_your_business_open if it exists on the form (custom8)
169      let businessOpenValue = form.getValues()['custom8'];
170      if (businessOpenValue) {
171        dataObj.is_your_business_open = businessOpenValue;
172      }
173
174      // Store data to be submitted later (onSuccess)
175      dataForTealium = dataObj;
176    }
177
178    function functionExists(funcName) {
179      if (typeof detailGetters[funcName] === "function") {
180        return 1;
181      }
182    }
183
184    function findEventName(formNum) {
185      if (formID2Key[formNum]) {
186        return formID2Key[formNum];
187      } else {
188        return "unnamed_form_submit";
189      }
190    }
191
192    var detailGetters = {
193      get_content_title: function () {
194        if (window.utag_data) {
195          return utag_data.content_title || "";
196        }
197      },
198
199      get_page_name: function () {
200        if (window.utag_data) {
201          return utag_data.page_name || "";
202        }
203      }
204    };
205
206    form.onSubmit(function () {
207      var formID = form.getId(),
208        key = findEventName(formID);
209
210      if (eventNames[key]) {
211        buildTealiumData(form, eventNames[key], key);
212      }
213    });
214
215    function onlyValuesSet(data) {
216      var out = {};
217      for (var key in data) {
218        if (Object.prototype.hasOwnProperty.call(data, key)) {
219          var val = data[key];
220          if (val !== undefined && val !== null && val !== '') {
221            out[key] = val;
222          }
223        }
224      }
225      return out;
226    }
227
228    // onSuccess handler for Marketo form
229    form.onSuccess(function () {
230      var formID = form.getId();
231      // Prevent duplicate submissions to Tealium when the form exists more than once on the page.
232      if (window.marketoFormsSubmitted.has(formID)) {
233        return;
234      }
235      window.marketoFormsSubmitted.add(formID);
236      // Submit form event data to Tealium (only properties with a value set)
237      try {
238        utag.link(onlyValuesSet(dataForTealium));
239      } catch (err) {
240        if (typeof newrelic != "undefined") {
241          newrelic.noticeError(err);
242        } else {
243          console.log('newrelic not found');
244          console.error('Error sending form event data to Tealium: ', err);
245        }
246      }
247    });
248  });
249})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.