1(function() { 2 class MonitoringHubEventMonitor { 3 4 storageKey = "monitoringhub_events"; 5 6 consentModeInitialized = false; 7 8 config = { 9 debug: false, 10 log_errors: true, 11 store_enabled: false, 12 set_only_required_consents: false, 13 ga: '', 14 gtm: '', 15 aw: { 16 account: '', 17 labels: { 18 page_view: '', 19 view_item: '', 20 add_to_cart: '', 21 purchase: '', 22 lead: '' 23 } 24 }, 25 meta: '', 26 tiktok: '', 27 linkedin: { 28 account: '', 29 labels: { 30 purchase: '', 31 lead: '' 32 } 33 } 34 }; 35 36 /** 37 * @typedef {Object} StorageData 38 * @property {MonitoringHub.UTM} utm 39 * @property {string} monitor 40 * @property {string} latest_referer_url 41 * @property {number} latest_referer_time 42 * @property {Object<string, any>} cookie_data 43 * @property {Object<string, boolean>} enabled 44 */ 45 46 /** 47 * @type {StorageData} 48 */ 49 storageData = null; 50 51 /** 52 * @typedef {Object} ListenerSettings 53 * @property {MonitoringHub.Listener} listener 54 * @property {boolean} enabled 55 * @property {boolean} loaded 56 */ 57 58 /** 59 * @type {Object.<string, ListenerSettings>} 60 */ 61 listeners = {}; 62 63 /** 64 * @typedef {Object} EventData 65 * @property {MonitoringHub.Event} event 66 * @property {Object.<string, boolean>} fired 67 * @property {boolean} logged 68 */ 69 70 /** 71 * @type {EventData[]} 72 */ 73 events = []; 74 75 constructor() { 76 this.config = { ...this.config, ...( window['monitoringhub_event_config'] || {}) }; 77 78 this.initErrorHandling(); 79 this.initDataLayer(); 80 this.initiateStorage(); 81 82 } 83 84 log(...args) { 85 if (!this.config.debug) return; 86 87 console.info.apply(console, args); 88 } 89 90 91 initErrorHandling() { 92 const log = this.log.bind(this); 93 log("ð¨ MonitoringHub: Initialisiere Fehler-Handling..."); 94 95 const logErrors = this.config.log_errors; 96 97 const LOGGING_ENDPOINT = "/wp-json/monitoringhub/v1/log_error"; 98 99 function sendLog(errorData) { 100 if (!logErrors) { 101 log("ð¨ MonitoringHub disabled logging errors...", errorData); 102 return; 103 } 104 105 log("ð¨ MonitoringHub logged error...", errorData); 106 navigator.sendBeacon(LOGGING_ENDPOINT, JSON.stringify(errorData)); 107 } 108 109 function formatError(error, source, lineno, colno) { 110 return { 111 message: error?.message || error || "Unknown error", 112 stack: error?.stack || null, 113 source: source || null, 114 lineno: lineno || null, 115 colno: colno || null, 116 userAgent: navigator.userAgent, 117 timestamp: new Date().toISOString(), 118 page: window.location.href 119 }; 120 } 121 122 window.onerror = function (message, source, lineno, colno, error) { 123 const errorData = formatError(error || message, source, lineno, colno); 124 sendLog(errorData); 125 }; 126 127 window.onunhandledrejection = function (event) { 128 const errorData = formatError(event.reason, null, null, null); 129 sendLog(errorData); 130 }; 131 132 (function interceptConsoleErrors() { 133 const originalConsoleError = console.error; 134 console.error = function (...args) { 135 originalConsoleError.apply(console, args); 136 sendLog(args); 137 }; 138 })(); 139 } 140 141 initDataLayer(variable="dataLayer") { 142 window[variable] = window[variable] || []; 143 if (!window['gtag']) { 144 window['gtag'] = function(){window[variable].push(arguments)}; 145 } 146 this.initConsentMode(); 147 window['gtag']('js', new Date()); 148 console.log('ð¨ MonitoringHub: gtag initialisiert', window[variable]); 149 } 150 151 /** 152 * 153 * @param {Object|null} defaults 154 * @returns 155 */ 156 getStorageData(defaults=null) { 157 if (!this.storageData) { 158 this.storageData = { 159 'utm': { 160 updated: null, 161 source: "(direct)", 162 medium: "(none)", 163 campaign: null, 164 content: null, 165 term: null 166 }, 167 'monitor': null, 168 'latest_referer_url': null, 169 'latest_referer_time': null,
170 'cookie_data': null, 171 'enabled': {} 172 } 173 try { 174 this.storageData = {...this.storageData, ...JSON.parse(localStorage.getItem(this.storageKey) || '{}')}; 175 if (!this.config.store_enabled) { 176 this.storageData.enabled = {}; 177 } 178 this.log("ð¦ MonitoringHub: Daten aus dem LocalStorage geladen!", this.storageData); 179 } catch (error) { 180 this.log("ð¨ MonitoringHub: Fehler beim Laden der Daten aus dem LocalStorage!", error); 181 } 182 } 183 if (defaults) { 184 this.storageData = { ...defaults, ...this.storageData }; 185 } 186 return this.storageData; 187 188 } 189 setStorageData(data=null) { 190 let storage = this.getStorageData(); 191 if (data) { 192 this.storageData = { ...storage, ...data }; 193 } 194 localStorage.setItem(this.storageKey, JSON.stringify({...this.storageData, ...(!this.config.store_enabled ? { 'enabled': {} } : {}) })); 195 } 196 197 initiateStorage() { 198 let storage = this.getStorageData(); 199 200 if (document.referrer && document.referrer.indexOf(window.location.hostname) === -1) { 201 this.setStorageData({ 202 'latest_referer_url': document.referrer, 203 'latest_referer_time': Date.now() 204 }); 205 } 206 207 if (!storage.monitor) { 208 this.setStorageData({ 'monitor': this.uuid() }); 209 } 210 211 let utm = storage.utm; 212 var updated = utm.updated ? false : true; 213 var params = new URLSearchParams(window.location.search); 214 ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(param => { 215 if (params.has(param)) { 216 this.log('update', param, params.get(param)); 217 utm[param.replace('utm_', '')] = params.get(param); 218 updated = true; 219 } 220 }); 221 222 if (updated) { 223 utm.updated = Date.now(); 224 this.setStorageData({ 'utm': utm }); 225 } 226 } 227 228 uuid() { 229 return crypto.randomUUID(); 230 } 231 232 /** 233 * 234 * @param {MonitoringHub.Event} event 235 * @param {string[]} listeners 236 */ 237 logEventToServer(event, listeners=[]) { 238 const hub = this; 239 240 /** 241 * @typedef {Object} Payload 242 * @property {MonitoringHub.Event} event 243 * @property {string} monitor 244 * @property {Object<string, any>} params 245 * @property {string[]} onlyForListeners 246 * @property {MonitoringHub.Webdata} webdata 247 */ 248 249 let storage = hub.getStorageData(); 250 /** 251 * @type {Payload} 252 */ 253 let payload = { 254 event: event, 255 monitor: storage.monitor, 256 params: storage.cookie_data, 257 onlyForListeners: listeners, 258 webdata: { 259 utm: storage.utm, 260 userAgent: window.navigator.userAgent, 261 referrer: storage.latest_referer_url, 262 url: window.location.href, 263 title: document.title, 264 language: window.navigator.language, 265 timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, 266 viewport: { 267 width: window.innerWidth, 268 height: window.innerHeight 269 } 270 } 271 }; 272 273 let jsonData = JSON.stringify(payload); 274 let size = (new Blob([jsonData]).size) / 1024; 275 if (size > 64) { 276 hub.log("ð¡ Sende post an Server:", { payload, listeners, size }); 277 fetch('/wp-json/monitoringhub/v1/monitor_event', { 278 method: 'POST', 279 headers: { 280 'Content-Type': 'application/json' 281 }, 282 body: jsonData 283 }); 284 } else { 285 hub.log("ð¡ Send beacon '"+ (event.name) +"' to server:", { payload, listeners, size }); 286 navigator.sendBeacon('/wp-json/monitoringhub/v1/monitor_event', JSON.stringify(payload)); 287 } 288 } 289 290 /** 291 * 292 * @param {MonitoringHub.Event} event 293 */ 294 logEvent(event) { 295 event.id = this.generateEventId(); 296 event.timestamp = Date.now();
297 event.monitor = this.getStorageData().monitor; 298 const eventState = { 299 event: event, 300 fired: {}, 301 logged: false 302 }; 303 this.events.push( eventState ); 304 setTimeout(() => { 305 this.processEventsForListeners(); 306 }, 0); 307 308 309 const hub = this; 310 311 setTimeout(() => { 312 hub.logEventToServer(event); 313 eventState.logged = true; 314 }, 1); 315 } 316 317 processEventsForListeners() { 318 Object.keys(this.listeners).forEach(listenerId => { 319 this.processEventsForListener(listenerId); 320 }); 321 } 322 323 /** 324 * 325 * @param {string} listenerId 326 */ 327 processEventsForListener(listenerId) { 328 /** 329 * @type {ListenerSettings} 330 */ 331 let listenerSetting = this.listeners[listenerId] || null; 332 333 if (!listenerSetting) { 334 this.log("ð MonitoringHub: "+listenerId+" listener does not exist .... maybe no key set in config"); 335 return; 336 } 337 338 if (!listenerSetting.enabled ) { 339 this.log("ð MonitoringHub: "+listenerId+" listener not enabled! - use monitoringHubEventMonitor.enable('"+listenerId+"'); "); 340 return; 341 } 342 const listener = listenerSetting.listener 343 344 if (!listenerSetting.loaded) { 345 this.initConsentMode(); 346 this.log("ð MonitoringHub: Load "+listenerId+" listener "); 347 if (listener['init']) listener.init(); 348 this.listeners[listenerId].loaded = true; 349 } 350 351 if (!listener['isAvailable'] || !listener.isAvailable()) { 352 this.log("ð MonitoringHub: "+listenerId+" loaded but not available yet - setTimeout "); 353 setTimeout(() => { 354 this.processEventsForListener(listenerId); 355 }, 250); 356 return; 357 } 358 359 this.events.forEach(eventData => { 360 if (eventData.fired[listenerId]) { 361 return; 362 } 363 if (eventData.logged) { 364 this.logEventToServer(eventData.event, [listenerId]); 365 } 366 /** 367 * @type {MonitoringHub.Event} 368 */ 369 let event = eventData.event; 370 if (event.name && listener[event.name]) { 371 try { 372 this.log("ð " + listener.id + ': ' + event.name); 373 listener[event.name](event); 374 } catch(e) { 375 this.log("ð¨ ERROR " + listener.id + ': ' + event.name, event, e); 376 } 377 } else { 378 this.log("â ï¸ " + listener.id + ': ' + event.name + ' not implemented'); 379 } 380 eventData.fired[listenerId] = true; 381 }); 382 } 383 384 getCookie(name) { 385 let match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); 386 return match ? match[2] : null; 387 } 388 389 setCookie(name, value, days = 90) { 390 const expires = new Date(Date.now() + days * 864e5).toUTCString(); 391 const domain = location.hostname.startsWith('www.') 392 ? location.hostname.replace('www.', '.') 393 : '.' + location.hostname; 394 395 396 document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; expires=${expires}; path=/; domain=${domain}; SameSite=Lax`; 397 } 398 399 generateEventId() { 400 return this.uuid(); 401 } 402 403 /** 404 * 405 * @param {MonitoringHub.Listener} listener 406 */ 407 addListener(listener) { 408 this.listeners[listener.id] = { 409 'listener': listener, 410 'loaded': false,
411 'enabled': this.getStorageData()?.enabled[listener.id] || false 412 }; 413 } 414 415 enable(id) { 416 let listener = this.listeners[id]; 417 if (listener) { 418 listener.enabled = true; 419 } 420 this.getStorageData({ 'enabled': {} }); 421 this.storageData.enabled[id] = true; 422 this.setStorageData(); 423 this.processEventsForListener(id); 424 } 425 426 disable(id) { 427 let listener = this.listeners[id]; 428 if (listener) { 429 listener.enabled = false; 430 } 431 this.getStorageData({ 'enabled': {} }); 432 delete this.storageData.enabled[id]; 433 this.setStorageData(); 434 } 435 436 init() { 437 const params = new URLSearchParams(window.location.search) 438 let cookie_data = this.getStorageData().cookie_data || {}; 439 440 for(let listener of Object.values(this.listeners)) { 441 const listener_url_data = {}; 442 (listener.listener.params || []).forEach(param => { 443 const value = params.get(param); 444 if (value) { 445 listener_url_data[param] = value; 446 } 447 }); 448 449 const listener_cookie_data = {}; 450 (listener.listener.cookies || []).forEach(cookie => { 451 const value = this.getCookie(cookie); 452 if (value) { 453 listener_cookie_data[cookie] = value 454 } 455 }); 456 457 const listener_localstorage_data = {}; 458 (listener.listener.localstorage || []).forEach(item => { 459 const value = localStorage.getItem(item); 460 if (value) { 461 listener_localstorage_data[item] = value 462 } 463 }); 464 465 let listener_processed_data = {}; 466 if (listener.listener.processParams) { 467 listener_processed_data = listener.listener.processParams(listener_url_data, listener_cookie_data, listener_localstorage_data); 468 } 469 470 this.log("ð MonitoringHub: Params für " + listener.listener.id + " initialisiert", { listener_url_data, listener_cookie_data, listener_localstorage_data, listener_processed_data}); 471 cookie_data = {...cookie_data, ...listener_url_data, ...listener_cookie_data, ...listener_localstorage_data, ...listener_processed_data}; 472 } 473 474 this.log("ð MonitoringHub: Params gesetzt", cookie_data ); 475 this.setStorageData({ cookie_data }); 476 } 477 478 loadScript(src, callback=null) { 479 const s = document.createElement('script'); 480 s.src = src; 481 s.async = true; // lädt parallel, blockiert nichts 482 if (callback) { 483 s.onload = callback; 484 } 485 document.head.appendChild(s); 486 } 487 488 489 initConsentMode() { 490 if (!window['gtag']) { 491 this.log("ð¨ MonitoringHub: gtag nicht gefunden!"); 492 return; 493 } 494 495 var enabled = this.getStorageData({ 'enabled': {} }).enabled; 496 var consentmodes = this.config.set_only_required_consents ? {} : { 497 'ad_storage': 'denied', 498 'ad_user_data': 'denied', 499 'ad_personalization': 'denied', 500 'analytics_storage': 'denied', 501 'personalization_storage': 'denied', 502 'functionality_storage': 'granted', 503 }; 504 505 Object.keys(this.listeners).forEach(listenerId => { 506 if (!enabled[listenerId]) return; 507 508 const listener = this.listeners[listenerId].listener; 509 (listener.consentmodes || []).forEach(mode => { 510 consentmodes[mode] = 'granted'; 511 }); 512 }); 513 514 if (Object.keys(consentmodes).length === 0) { 515 this.log("ð MonitoringHub: Keine Consent-Modi für Listener gefunden!") 516 517 } else if (!this.consentModeInitialized) {
518 const initConsent = { 'wait_for_update': 250, ...consentmodes}; 519 this.log("ð MonitoringHub: Consent-Modus initialisiert", initConsent); 520 window['gtag']('consent', 'default', initConsent); 521 522 this.consentModeInitialized = true; 523 } else { 524 this.log("ð MonitoringHub: Consent-Modus updated", consentmodes); 525 window['gtag']('consent', 'update', consentmodes); 526 527 } 528 } 529 530 pageView() { 531 /** @type {MonitoringHub.PageViewEvent} */ 532 let event = { 533 name: "pageView", 534 page: window.location.href 535 }; 536 this.logEvent(event); 537 } 538 539 viewItem({id=null, name=null, value=0, currency="EUR", type="product", category="", gtin= "", mpn="", brand=""} = {}) { 540 /** @type {MonitoringHub.ViewItemEvent} */ 541 let event = { 542 name: "viewItem", 543 item: { 544 id: id, 545 name: name, 546 value: value, 547 currency: currency, 548 type: type, 549 quantity: 1, 550 category: category, 551 gtin: gtin, 552 mpn: mpn, 553 brand: brand 554 } 555 }; 556 this.logEvent(event); 557 } 558 559 addToCart({id=null, name=null, value=0, quantity=1, currency="EUR", type="product", category="", gtin="", mpn="", brand=""} = {}) { 560 /** @type {MonitoringHub.AddToCartEvent} */ 561 let event = { 562 name: "addToCart", 563 item: { 564 id: id, 565 name: name, 566 value: value, 567 currency: currency, 568 type: type, 569 quantity: quantity, 570 category: category, 571 gtin: gtin, 572 mpn: mpn, 573 brand: brand 574 } 575 }; 576 this.logEvent(event); 577 } 578 579 initiateCheckout({ items=[{id: null, name: null, value: 0, quantity: 1, currency: "EUR", type: "product", category: "", gtin: "", mpn: "", brand: ""}]} = {}) { 580 // Validate items 581 if (!Array.isArray(items) || items.length === 0) { 582 this.log("ð¨ MonitoringHub: Invalid items array for initiateCheckout event."); 583 return; 584 } 585 586 for (let item of items) { 587 if (!item.id) item.id = "unknown"; 588 if (!item.name) item.name = "unknown"; 589 if (typeof item.value !== 'number') item.value = 0; 590 if (typeof item.quantity !== 'number') item.quantity = 1; 591 592 if (!item.gtin) item.gtin = ""; 593 if (!item.mpn) item.mpn = ""; 594 if (!item.brand) item.brand = ""; 595 596 } 597 598 /** @type {MonitoringHub.InitiateCheckoutEvent} */ 599 let event = { 600 name: "initiateCheckout", 601 items: items 602 }; 603 this.logEvent(event); 604 } 605 606 607 addPaymentInfo({ items=[{id: null, name: null, value: 0, quantity: 1, currency: "EUR", type: "product", category: "", gtin: "", mpn: "", brand: ""}]} = {}) { 608 // Validate items 609 if (!Array.isArray(items) || items.length === 0) { 610 this.log("ð¨ MonitoringHub: Invalid items array for addPaymentInfo event."); 611 return; 612 } 613 614 for (let item of items) { 615 if (!item.id) item.id = "unknown"; 616 if (!item.name) item.name = "unknown"; 617 if (typeof item.value !== 'number') item.value = 0; 618 if (typeof item.quantity !== 'number') item.quantity = 1; 619 620 if (!item.gtin) item.gtin = ""; 621 if (!item.mpn) item.mpn = ""; 622 if (!item.brand) item.brand = ""; 623 624 } 625 626 /** @type {MonitoringHub.InitiateCheckoutEvent} */ 627 let event = { 628 name: "initiateCheckout", 629 items: items 630 }; 631 this.logEvent(event); 632 } 633 634 purchase({ 635 transaction=null, 636 items=[{id: null, name: null, value: 0, quantity: 1, currency: "EUR", type: "product", category: "", gtin: "", mpn: "", brand: ""}], 637 delivery_country=null, 638 customer_email=null, 639 estimated_delivery_date=null, 640 } = {}) { 641 // Validate items 642 if (!Array.isArray(items) || items.length === 0) { 643 this.log("ð¨ MonitoringHub: Invalid items array for purchase event."); 644 return; 645 } 646 647 for (let item of items) { 648 if (!item.id) item.id = "unknown"; 649 if (!item.name) item.name = "unknown"; 650 if (typeof item.value !== 'number') item.value = 0; 651 if (typeof item.quantity !== 'number') item.quantity = 1; 652 653 if (!item.gtin) item.gtin = ""; 654 if (!item.mpn) item.mpn = ""; 655 if (!item.brand) item.brand = ""; 656 657 } 658 659 /** @type {MonitoringHub.PurchaseEvent} */ 660 let event = { 661 name: "purchase", 662 transaction_id: transaction, 663 delivery_country: delivery_country, 664 customer_email: customer_email, 665 estimated_delivery_date: estimated_delivery_date, 666 items: items 667 }; 668 this.logEvent(event); 669 } 670 671 lead({subject="", value=0, currency="EUR"}={}) { 672 /** @type {MonitoringHub.LeadEvent} */ 673 let event = { 674 name: "lead", 675 subject: subject, 676 value: value, 677 currency: currency 678 }; 679 this.logEvent(event); 680 } 681 682 search(event={}) { 683 this.log("ð¨ MonitoringHub: not implemented ", event.name); 684 } 685 686 schedule(event={}) { 687 this.log("ð¨ MonitoringHub: not implemented ", event.name); 688 } 689 690 startTrial(event={}) { 691 this.log("ð¨ MonitoringHub: not implemented ", event.name); 692 } 693 694 submitApplication(event={}) { 695 this.log("ð¨ MonitoringHub: not implemented ", event.name); 696 } 697 698 subscribe(event={}) { 699 this.log("ð¨ MonitoringHub: not implemented ", event.name); 700 } 701 702 customizeProduct(event={}) { 703 this.log("ð¨ MonitoringHub: not implemented ", event.name); 704 } 705 706 viewItemList(event={}) { 707 this.log("ð¨ MonitoringHub: not implemented ", event.name); 708 } 709 } 710 711 let monitoringHubEventMonitor = new MonitoringHubEventMonitor(); 712 // **Globale Instanz bereitstellen** 713 window['monitoringHubEventMonitor'] = monitoringHubEventMonitor; 714 715 if (!window['monitoringhub_event_config']) { 716 monitoringHubEventMonitor.log("ð¨ MonitoringHub: Event-Codes nicht gefunden!"); 717 } else { 718 monitoringHubEventMonitor.log("â MonitoringHub: Event Codes geladen!", monitoringHubEventMonitor.config); 719 720 if (monitoringHubEventMonitor.config.ga) { 721 monitoringHubEventMonitor.addListener({ 722 id: 'ga', 723 name: 'Google Analytics', 724 cookies: ['_ga'], 725 localstorage: [], 726 consentmodes: ['analytics_storage'], 727 isAvailable: function () { 728 return window['gtag'] && window['gtag'] instanceof Function; 729 }, 730 baseEventProperty: function(event) { 731 const ret = { 732 'send_to': monitoringHubEventMonitor.config.ga, 733 'anonymize_ip': true,
734 'event_id': event.id, 735 'user_id': event.monitor 736 }; 737 if (event.item) { 738 ret['value'] = event.item?.value * event.item?.quantity; 739 ret['currency'] = event.item?.currency; 740 ret['items'] = [{ 741 'item_id': event.item?.id, 742 'item_name': event.item?.name, 743 'item_category': event.item?.category, 744 'quantity': event.item?.quantity, 745 'price': event.item?.value 746 }]; 747 }; 748 if (event.items) { 749 ret['value'] = event.items?.reduce((acc, item) => (acc + item.value * item.quantity), 0); 750 ret['currency'] = event.items ? event.items[0].currency : 'EUR'; 751 ret['items'] = event.items.map((item, index) => ({ 752 'item_id': item.id, 753 'item_name': item.name, 754 'item_category': item.category, 755 'quantity': item.quantity, 756 'price': item.value 757 })); 758 }; 759 return ret; 760 }, 761 init: function () { 762 monitoringHubEventMonitor.log("ð GA init " + monitoringHubEventMonitor.config.ga); 763 monitoringHubEventMonitor.loadScript("https://www.googletagmanager.com/gtag/js?id=" + monitoringHubEventMonitor.config.ga); 764 monitoringHubEventMonitor.log("ð GA config"); 765 gtag('config', monitoringHubEventMonitor.config.ga, { 766 'send_page_view': false, 767 'anonymize_ip': true, 768 }); 769 }, 770 pageView: function (event) { 771 gtag('event', 'page_view', { 772 ...this.baseEventProperty(event) 773 }); 774 }, 775 viewItem: function (event) { 776 gtag('event', 'view_item', { 777 ...this.baseEventProperty(event) 778 }); 779 }, 780 addToCart: function (event) { 781 gtag('event', 'add_to_cart', { 782 ...this.baseEventProperty(event) 783 }); 784 }, 785 initiateCheckout: function (event) { 786 gtag('event', 'begin_checkout', { 787 ...this.baseEventProperty(event) 788 }); 789 }, 790 addPaymentInfo: function (event) { 791 gtag('event', 'add_payment_info', { 792 ...this.baseEventProperty(event) 793 }); 794 }, 795 purchase: function (event) { 796 gtag('event', 'purchase', { 797 ...this.baseEventProperty(event), 798 'transaction_id': event.transaction_id, 799 }); 800 }, 801 lead: function (event) { 802 gtag('event', 'generate_lead', { 803 ...this.baseEventProperty(event) 804 }); 805 }, 806 search: function (event) { 807 gtag('event', 'search', { 808 ...this.baseEventProperty(event) 809 }); 810 }, 811 schedule: function (event) { 812 gtag('event', 'schedule', { 813 ...this.baseEventProperty(event) 814 }); 815 }, 816 startTrial: function (event) { 817 gtag('event', 'start_trial', { 818 ...this.baseEventProperty(event) 819 }); 820 }, 821 submitApplication: function (event) { 822 gtag('event', 'submit_application', { 823 ...this.baseEventProperty(event) 824 }); 825 }, 826 subscribe: function (event) { 827 gtag('event', 'subscribe', { 828 ...this.baseEventProperty(event) 829 }); 830 }, 831 customizeProduct: function (event) { 832 gtag('event', 'customize_product', { 833 ...this.baseEventProperty(event) 834 }); 835 }, 836 viewItemList: function (event) { 837 gtag('event', 'view_item_list', { 838 ...this.baseEventProperty(event) 839 }); 840 } 841 }); 842 } 843 844 845 if (monitoringHubEventMonitor.config.meta) { 846 monitoringHubEventMonitor.addListener({ 847 id: 'meta', 848 name: 'Facebook / Meta', 849 params: ['fbclid'], 850 cookies: ['_fbp', '_fbc', 'fr', 'datr', 'xs', 'c_user', 'sb', 'wd', 'usida'], 851 localstorage: [], 852 consentmodes: [], 853 processParams: function (url_data, cookie_data, localstorage_data) { 854 const ret = {}; 855 if (url_data['fbclid']) { 856 const timestamp = Math.floor(Date.now()); 857 ret['_fbc'] = `fb.1.${timestamp}.${url_data['fbclid']}`;
858 /* das find ich eher blöd hier, aber egal momentan */ 859 monitoringHubEventMonitor.setCookie('_fbc', ret['_fbc'], 90); 860 } else { 861 const fbcCleanup = monitoringHubEventMonitor.getCookie('_fbc'); 862 if(fbcCleanup){ 863 const match = fbcCleanup.match(/fb\.[0-9]\.(\d+)\.(.*)/); 864 let ts = parseInt(match[1]); 865 if(ts < 9999999999){ // nur 10 Stellen = Sekunden 866 ret['_fbc'] = fbcCleanup.replace('.' + match[1] + '.', "." + Date.now() + "."); 867 monitoringHubEventMonitor.log("ð META Cookie _fbc gefunden, aber nicht mehr gültig - " + fbcCleanup + ' - ' + ret['_fbc']); 868 monitoringHubEventMonitor.setCookie('_fbc', ret['_fbc'], 90); 869 } 870 } 871 } 872 return ret; 873 }, 874 isAvailable: function () { 875 return window['fbq'] && window['fbq'] instanceof Function; 876 }, 877 _sha256: async function(str) { 878 const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); 879 return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join(''); 880 }, 881 _track: async function(eventname, event, params) { 882 const external_id = await this._sha256(event.monitor) 883 const ret = { 884 external_id 885 }; 886 if (event.item) { 887 ret['content_ids'] = [ event.item.id ]; 888 ret['content_name'] = [ event.item.name ]; 889 ret['content_type'] = event.item.type; 890 ret['num_items'] = 1; 891 ret['value'] = event.item.value * event.item.quantity; 892 ret['currency'] = event.item.currency; 893 }; 894 if (event.items) { 895 ret['content_ids'] = event.items.map((item, index) => item.id); 896 ret['content_name'] = event.items.map((item, index) => item.id).join(', '); 897 ret['num_items'] = event.items?.length || 0, 898 ret['value'] = event.items?.reduce((acc, item) => (acc + item.value * item.quantity), 0); 899 ret['currency'] = event.items ? event.items[0].currency : 'EUR'; 900 ret['items'] = event.items.map((item, index) => ({ 901 'id': item.id, 902 'name': item.name, 903 'category': item.category, 904 'quantity': item.quantity, 905 'price': item.value, 906 'value': item.value * item.quantity 907 })); 908 }; 909 const eventId = event.transaction_id || event.id; 910 fbq('trackSingle', monitoringHubEventMonitor.config.meta, eventname, { 911 ...ret, 912 ...params 913 }, { eventID: eventId }); 914 915 monitoringHubEventMonitor.log("ð META data", ['trackSingle', monitoringHubEventMonitor.config.meta, eventname, { 916 ...ret, 917 ...params 918 }, { eventID: eventId }]); 919 }, 920 init: function () { 921 monitoringHubEventMonitor.log("ð init META script " + monitoringHubEventMonitor.config.meta); 922 923 // @ts-ignore 924 !function(f,b,e,v,n,t,s) 925 {if(f.fbq)return;n=f.fbq=function(){n.callMethod? 926 n.callMethod.apply(n,arguments):n.queue.push(arguments)}; 927 if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; 928 n.queue=[];t=b.createElement(e);t.async=!0; 929 t.src=v;s=b.getElementsByTagName(e)[0]; 930 s.parentNode.insertBefore(t,s)}(window, document,'script', 931 'https://connect.facebook.net/en_US/fbevents.js'); 932 fbq('init', monitoringHubEventMonitor.config.meta); 933 934 935 }, 936 pageView: function (event) { 937 this._track('PageView', event, { 938 }); 939 }, 940 viewItem: function (event) { 941 this._track('ViewContent', event, { 942 }); 943 }, 944 addToCart: function (event) { 945 this._track('AddToCart', event, { 946 }); 947 }, 948 initiateCheckout: function (event) { 949 this._track('InitiateCheckout', event, { 950 }); 951 }, 952 addPaymentInfo: function (event) { 953 this._track('AddPaymentInfo', event, { 954 }); 955 }, 956 purchase: function (event) { 957 this._track('Purchase', event, { 958 }); 959 }, 960 lead: function (event) { 961 this._track('Lead', event, { 962 }); 963 }, 964 search: function (event) { 965 this._track('Search', event, { 966 }); 967 }, 968 schedule: function (event) { 969 this._track('Schedule', event, { 970 }); 971 }, 972 startTrial: function (event) { 973 this._track('StartTrial', event, { 974 }); 975 }, 976 submitApplication: function (event) { 977 this._track('SubmitApplication', event, { 978 }); 979 }, 980 subscribe: function (event) { 981 this._track('Subscribe', event, { 982 }); 983 }, 984 customizeProduct: function (event) { 985 this._track('CustomizeProduct', event, { 986 }); 987 }, 988 viewItemList: function (event) { 989 this._track('ViewItemList', event, { 990 }); 991 } 992 }); 993 } 994 995 if (monitoringHubEventMonitor.config.aw && monitoringHubEventMonitor.config.aw.account) { 996 monitoringHubEventMonitor.addListener({ 997 id: 'aw', 998 name: 'Google Ads', 999 params: ['srsltid', 'gclid', 'gbraid', 'wbraid' ], 1000 cookies: ['_gcl_au', '_gcl_aw', '_gcl_dc', 'gclid' ], 1001 localstorage: [], 1002 consentmodes: [ 'analytics_storage', 'ad_storage', 'ad_user_data', 'ad_personalization' ], 1003 baseEventProperty: function(event) { 1004 const ret = { 1005 'send_to': monitoringHubEventMonitor.config.aw.account, 1006 'anonymize_ip': true,
1007 'event_id': event.id, 1008 'user_id': event.monitor 1009 }; 1010 if (event.item) { 1011 ret['value'] = event.item?.value * event.item?.quantity; 1012 ret['currency'] = event.item?.currency; 1013 ret['items'] = [{ 1014 'item_id': event.item?.id, 1015 'item_name': event.item?.name, 1016 'item_category': event.item?.category, 1017 'quantity': event.item?.quantity, 1018 'price': event.item?.value 1019 }]; 1020 }; 1021 if (event.items) { 1022 ret['value'] = event.items?.reduce((acc, item) => (acc + (item.value * item.quantity)), 0); 1023 ret['currency'] = event.items ? event.items[0].currency : 'EUR'; 1024 ret['items'] = event.items.map((item, index) => ({ 1025 'item_id': item.id, 1026 'item_name': item.name, 1027 'item_category': item.category, 1028 'quantity': item.quantity, 1029 'price': item.value 1030 })) 1031 }; 1032 return ret; 1033 }, 1034 _conversion(label, event) { 1035 if (!monitoringHubEventMonitor.config.aw.labels[label]) return; 1036 const send_to = monitoringHubEventMonitor.config.aw.labels[label].replace(/AW-\w+\//, ''); 1037 1038 const conversion = { 1039 'send_to': monitoringHubEventMonitor.config.aw.account + '/' + send_to, 1040 'anonymize_ip': true, 1041 'event_id': event.id, 1042 'user_id': event.monitor, 1043 'transaction_id': event.transaction_id || event.monitor + '_' + event.name + '_' + (new Date()).toDateString(), 1044 }; 1045 if (event.item) { 1046 conversion['value'] = event.item?.value * event.item?.quantity; 1047 conversion['currency'] = event.item?.currency; 1048 }; 1049 if (event.items) { 1050 conversion['value'] = event.items?.reduce((acc, item) => (acc + item.value * item.quantity), 0); 1051 conversion['currency'] = event.items ? event.items[0].currency : 'EUR'; 1052 } 1053 gtag('event', 'conversion', conversion); 1054 1055 }, 1056 isAvailable: function () { 1057 return window['gtag'] && window['gtag'] instanceof Function; 1058 }, 1059 init: function () { 1060 monitoringHubEventMonitor.log("ð AW init " + monitoringHubEventMonitor.config.aw.account); 1061 monitoringHubEventMonitor.loadScript("https://www.googletagmanager.com/gtag/js?id=" + monitoringHubEventMonitor.config.aw.account); 1062 monitoringHubEventMonitor.log("ð AW config"); 1063 gtag('config', monitoringHubEventMonitor.config.aw.account, { 1064 'send_page_view': false, 1065 'anonymize_ip': true, 1066 }); 1067 }, 1068 pageView: function (event) { 1069 this._conversion('page_view', event); 1070 gtag('event', 'page_view', { 1071 ...this.baseEventProperty(event) 1072 }); 1073 }, 1074 viewItem: function (event) { 1075 this._conversion('view_item', event); 1076 gtag('event', 'view_item', { 1077 ...this.baseEventProperty(event) 1078 }); 1079 }, 1080 addToCart: function (event) { 1081 this._conversion('add_to_cart', event); 1082 gtag('event', 'add_to_cart', { 1083 ...this.baseEventProperty(event) 1084 }); 1085 }, 1086 initiateCheckout: function (event) { 1087 this._conversion('initiate_checkout', event); 1088 gtag('event', 'begin_checkout', { 1089 ...this.baseEventProperty(event) 1090 }); 1091 }, 1092 addPaymentInfo: function (event) { 1093 gtag('event', 'add_payment_info', { 1094 ...this.baseEventProperty(event) 1095 }); 1096 }, 1097 purchase: function (event) { 1098 this._conversion('purchase', event); 1099 gtag('event', 'purchase', { 1100 ...this.baseEventProperty(event), 1101 'transaction_id': event.transaction_id, 1102 }); 1103 1104 }, 1105 lead: function (event) { 1106 this._conversion('lead', event); 1107 gtag('event', 'generate_lead', { 1108 ...this.baseEventProperty(event) 1109 }); 1110 }, 1111 search: function (event) { 1112 gtag('event', 'search', { 1113 ...this.baseEventProperty(event) 1114 }); 1115 }, 1116 schedule: function (event) {
1117 gtag('event', 'schedule', { 1118 ...this.baseEventProperty(event) 1119 }); 1120 }, 1121 startTrial: function (event) { 1122 gtag('event', 'start_trial', { 1123 ...this.baseEventProperty(event) 1124 }); 1125 }, 1126 submitApplication: function (event) { 1127 gtag('event', 'submit_application', { 1128 ...this.baseEventProperty(event) 1129 }); 1130 }, 1131 subscribe: function (event) { 1132 gtag('event', 'subscribe', { 1133 ...this.baseEventProperty(event) 1134 }); 1135 }, 1136 customizeProduct: function (event) { 1137 gtag('event', 'customize_product', { 1138 ...this.baseEventProperty(event) 1139 }); 1140 }, 1141 viewItemList: function (event) { 1142 gtag('event', 'view_item_list', { 1143 ...this.baseEventProperty(event) 1144 }); 1145 } 1146 }); 1147 } 1148 1149 if (monitoringHubEventMonitor.config.linkedin && monitoringHubEventMonitor.config.linkedin.account) { 1150 monitoringHubEventMonitor.addListener({ 1151 id: 'li', 1152 name: 'LinkedIn', 1153 params: [], 1154 cookies: ['li_fat_id', 'li_sugr', 'UserMatchHistory', 'bcookie', 'lidc'], 1155 localstorage: [], 1156 consentmodes: [], 1157 isAvailable: function () { 1158 return typeof window['lintrk'] === 'function'; 1159 }, 1160 init: function () { 1161 monitoringHubEventMonitor.log("ð init LinkedIn Insight Tag"); 1162 1163 // Insight Tag (Standard Snippet) 1164 const partnerId = monitoringHubEventMonitor.config.linkedin.account; 1165 window._linkedin_partner_id = partnerId; 1166 window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || []; 1167 window._linkedin_data_partner_ids.push(partnerId); 1168 1169 const script = document.createElement("script"); 1170 script.type = "text/javascript"; 1171 script.async = true; 1172 script.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js"; 1173 document.head.appendChild(script); 1174 }, 1175 1176 _track(label, event) { 1177 if (!monitoringHubEventMonitor.config.linkedin.labels[label]) return; 1178 lintrk('track', { 1179 conversion_id: monitoringHubEventMonitor.config.linkedin.labels[label], 1180 event_id: event.id // optional 1181 }); 1182 }, 1183 pageView: function (event) { 1184 this._track('pageView', event); 1185 }, 1186 purchase: function (event) { 1187 this._track('purchase', event); 1188 }, 1189 lead: function (event) { 1190 this._track('lead', event); 1191 } 1192 }); 1193 } 1194 1195 if (monitoringHubEventMonitor.config.tiktok) { 1196 monitoringHubEventMonitor.addListener({ 1197 id: 'tt', 1198 name: 'TikTok', 1199 params: ['ttclid'], 1200 cookies: ['_ttp'], 1201 localstorage: [], 1202 consentmodes: [], 1203 isAvailable() { 1204 return typeof window['ttq'] === 'object'; 1205 }, 1206 init() { 1207 monitoringHubEventMonitor.log("ð init TikTok Pixel"); 1208 1209 const tagId = monitoringHubEventMonitor.config.tiktok; 1210 1211 // @ts-ignore 1212 !function (w, d, t) { 1213 w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for( 1214 var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js",o=n&&n.partner;ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=r,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};n=document.createElement("script") 1215 ;n.type="text/javascript",n.async=!0,n.src=r+"?sdkid="+e+"&lib="+t;e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(n,e)}; 1216 ttq.load(tagId); 1217 }(window, document, 'ttq'); 1218 1219 }, 1220 _track(eventname, event, params = {}) { 1221 const data = { 1222 external_id: event.monitor, 1223 }; 1224 1225 if (event.items) { 1226 data['content_id'] = event.items.map(i => i.id).join(','); 1227 data['quantity'] = event.items.length; 1228 data['value'] = event.items.reduce((acc, i) => (acc + i.value * i.quantity), 0); 1229 data['currency'] = event.items[0]?.currency || 'EUR'; 1230 data['contents'] = event.items.map(i => ({ 1231 content_id: i.id, 1232 content_type: i.type || 'product', 1233 content_category: i.category || 'Unknown', 1234 quantity: i.quantity, 1235 price: i.value, 1236 value: i.value * i.quantity 1237 })); 1238 } 1239 1240 if (event.item) { 1241 data['content_id'] = event.item.id; 1242 data['value'] = event.item.value * event.item.quantity; 1243 data['currency'] = event.item.currency; 1244 data['quantity'] = 1; 1245 data['contents'] = [{ 1246 content_id: event.item.id, 1247 content_type: event.item.type || 'product', 1248 content_category: event.item.category || 'Unknown', 1249 quantity: event.item.quantity, 1250 price: event.item.value, 1251 value: event.item.value * event.item.quantity 1252 }]; 1253 } 1254 1255 const eventId = event.transaction_id || event.id; 1256 1257 ttq.track(eventname, { 1258 ...data, 1259 ...params, 1260 }, { event_id: eventId }); 1261 1262 }, 1263 pageView(event) { 1264 this._track('PageView', event); 1265 }, 1266 viewItem(event) { 1267 this._track('ViewContent', event); 1268 }, 1269 addToCart(event) { 1270 this._track('AddToCart', event); 1271 }, 1272 initiateCheckout(event) { 1273 this._track('InitiateCheckout', event); 1274 }, 1275 purchase(event) { 1276 this._track('Purchase', event); 1277 }, 1278 lead(event) { 1279 this._track('Lead', event); 1280 } 1281 }); 1282 } 1283 1284 1285 if (monitoringHubEventMonitor.config.mc) { 1286 monitoringHubEventMonitor.addListener({ 1287 id: 'mc', 1288 name: 'MerchantCenter', 1289 params: [], 1290 cookies: [], 1291 localstorage: [], 1292 consentmodes: [], 1293 isAvailable: function () { 1294 return true; 1295 }, 1296 pageView: function (event) {}, 1297 viewItem: function (event) {}, 1298 addToCart: function (event) {}, 1299 initiateCheckout: function (event) {}, 1300 addPaymentInfo: function (event) {}, 1301 lead: function (event) {}, 1302 search: function (event) {}, 1303 schedule: function (event) {}, 1304 startTrial: function (event) {}, 1305 submitApplication: function (event) {}, 1306 subscribe: function (event) {}, 1307 customizeProduct: function (event) {}, 1308 viewItemList: function (event) {}, 1309 purchase: function (event) { 1310 1311 const products = event.items.map((item) => { 1312 return { 1313 gtin: item.gtin, 1314 id: item.id, 1315 }; 1316 }).filter((item) => { 1317 if (item.gtin) return true; 1318 return false;
1319 }); 1320 1321 window.merchantCenterRenderOptIn = function() { 1322 window.gapi.load('surveyoptin', function() { 1323 window.gapi.surveyoptin.render({ 1324 // REQUIRED FIELDS 1325 "merchant_id": monitoringHubEventMonitor.config.mc, 1326 "order_id": event.transaction_id, 1327 "email": event.customer_email, 1328 "delivery_country": event.delivery_country, 1329 "estimated_delivery_date": event.estimated_delivery_date, 1330 // OPTIONAL FIELDS 1331 "products": products 1332 }); 1333 }); 1334 1335 } 1336 1337 const script = document.createElement("script"); 1338 script.type = "text/javascript"; 1339 script.async = true; 1340 script.defer = true; 1341 script.src = "https://apis.google.com/js/platform.js?onload=merchantCenterRenderOptIn"; 1342 document.head.appendChild(script); 1343 } 1344 }); 1345 } 1346 } 1347 monitoringHubEventMonitor.init(); 1348 1349 document.addEventListener('DOMContentLoaded', function() { 1350 monitoringHubEventMonitor.pageView(); 1351 }); 1352 1353})(); 1354 1355 1356 1357
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.