/** * meta_tracking.js * A standalone module to capture and persist Meta attribution signals (fbclid, _fbp) in cookies. * * Logic adapted for legacy environment (no React hooks). * - Checks URL for `fbclid` and sets `_fbc` cookie. * - Checks for `_fbp` cookie; if missing, generates and sets it. */ (function (window, document) { 'use strict'; var MetaTracking = { init: function () { var location = window.location; this.handleFbc(location.search); this.handleFbp(); this.handleUtm(location.search); }, // 1. Parsing and storing _fbc (Click ID) handleFbc: function (searchParams) { var fbclid = this.getQueryParam('fbclid', searchParams); if (fbclid) { var version = 'fb'; var subdomainIndex = 1; // 1 = example.com var creationTime = new Date().getTime(); // Unix timestamp in ms // Format: fb.1.timestamp.id var fbcValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + fbclid; this.setCookie('_fbc', fbcValue, 90); } }, handleUtm: function (searchParams) { var self = this; if (!searchParams) return; // Logically, we want to capture all utm_ parameters. // We can either iterate a list or dynamic regex. // Given the requirement to be robust, let's look for "utm_" var query = searchParams.substring(1); // remove '?' var vars = query.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (pair.length === 2) { var key = decodeURIComponent(pair[0]); var value = decodeURIComponent(pair[1]); if (key.indexOf('utm_') === 0) { self.setCookie(key, value, 90); } } } }, // 2. Handling _fbp (Browser ID) handleFbp: function () { if (!this.getCookie('_fbp')) { var version = 'fb'; var subdomainIndex = 1; var creationTime = new Date().getTime(); var randomInt = Math.floor(Math.random() * 10000000000); // 10-digit random number // Format: fb.1.timestamp.randomDigits var fbpValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + randomInt; this.setCookie('_fbp', fbpValue, 90); } }, // Helper: Get query param by name getQueryParam: function (name, search) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var results = regex.exec(search); return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); }, // Helper: Set cookie setCookie: function (name, value, days) { var expires = ""; if (days) { var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = "; expires=" + date.toUTCString(); } // Ensure path is root and domain is included if needed (defaults to current host) document.cookie = name + "=" + (value || "") + expires + "; path=/"; }, // Helper: Get cookie getCookie: function (name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); } return null; } }; // Initialize on ready if (document.readyState === 'complete' || document.readyState === 'interactive') { MetaTracking.init(); } else { // IE9+ support for DOMContentLoaded document.addEventListener('DOMContentLoaded', function () { MetaTracking.init(); }); } })(window, document);