1(function () { 2 function setCookie(name, value, days) { 3 var d = new Date(); d.setTime(d.getTime() + days * 864e5); 4 document.cookie = name + "=" + encodeURIComponent(value) + "; expires=" + d.toUTCString() + "; path=/; SameSite=Lax"; 5 } 6 function getCookie(name) { 7 var m = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); 8 return m ? decodeURIComponent(m[2]) : ""; 9 } 10 function getParam(name) { 11 return (new URL(location.href)).searchParams.get(name) || ""; 12 } 13 14 function getOrCreateUserId() { 15 var k = "id_user_id"; 16 var v = localStorage.getItem(k); 17 if (!v) { v = uuidv4(); localStorage.setItem(k, v); } 18 return v; 19 } 20 21 // Save first-touch landing and referrer 22 if (!localStorage.getItem("first_landing_url")) localStorage.setItem("first_landing_url", location.href); 23 if (!localStorage.getItem("first_referrer")) localStorage.setItem("first_referrer", document.referrer || ""); 24 25 // Capture click IDs from URL into cookies 26 var clickParams = [ 27 "fbclid", "gclid", "gclsrc", "wbraid", "gbraid", "msclkid", "ttclid", "twclid", "li_fat_id", "sccid", "epik" 28 ]; 29 clickParams.forEach(function (p) { 30 var v = getParam(p); 31 if (v) setCookie(p, v, 90); 32 }); 33 34 // Read Google Ads click IDs from gtag.js cookies as fallback. 35 // gtag writes _gcl_aw / _gcl_dc / _gcl_gb on EVERY ad click (even when 36 // URL params are stripped by GTM, conversion linker, parallel tracking 37 // redirects, etc.) â so reading these recovers gclids we'd otherwise miss. 38 // Format: "GCL.<timestamp>.<click_id>" â click_id is everything after the 39 // second dot (it can itself contain dots). 40 function readGclCookie(name) { 41 var raw = getCookie(name); 42 if (!raw) return ""; 43 var parts = raw.split("."); 44 if (parts.length < 3) return ""; 45 return parts.slice(2).join("."); 46 } 47 48 function resolveGclid() { 49 return getCookie("gclid") || readGclCookie("_gcl_aw") || ""; 50 } 51 function resolveWbraid() { 52 return getCookie("wbraid") || ""; 53 } 54 function resolveGbraid() { 55 return getCookie("gbraid") || readGclCookie("_gcl_gb") || ""; 56 } 57 function resolveDclid() { 58 return readGclCookie("_gcl_dc") || ""; 59 } 60 61 var fbclidParam = getParam("fbclid"); 62 63 // Persist UTM params to cookies so they survive page navigation 64 ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"].forEach(function (p) { 65 var v = getParam(p); 66 if (v) setCookie(p, v, 90); 67 }); 68 69 // Ensure _fbc from fbclid if missing 70 if (!getCookie("_fbc")) { 71 var fbclid = fbclidParam || getCookie("fbclid"); 72 if (fbclid) setCookie("_fbc", "fb.1." + Date.now() + "." + fbclid, 90); 73 } 74 75 function getGaClientId() { 76 var ga = getCookie("_ga"); 77 if (!ga) return ""; 78 var parts = ga.split("."); 79 if (parts.length < 4) return ""; 80 return parts[2] + "." + parts[3]; 81 } 82 83 function getGaSessionInfo() { 84 var cookies = document.cookie.split(";").map(c => c.trim()); 85 var ga4 = cookies.find(c => c.startsWith("_ga_")); 86 if (!ga4) return { ga_session_id: "", ga_session_number: "" }; 87 var val = decodeURIComponent(ga4.split("=").slice(1).join("=")); 88 var parts = val.split("."); 89 return { 90 ga_session_id: parts[2] || "", 91 ga_session_number: parts[3] || "" 92 }; 93 } 94 95 function uuidv4() { 96 if (crypto && crypto.randomUUID) return crypto.randomUUID(); 97 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 98 var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); 99 }); 100 } 101 102 // Cap a string to N chars (URLs / UAs can blow past FastSpring's tag limit) 103 function clip(s, n) { 104 if (!s) return ""; 105 s = String(s); 106 return s.length > n ? s.substring(0, n) : s; 107 } 108 109 // Strip query string from a URL â saves bytes and avoids leaking utm/click 110 // params twice (we already capture them as discrete fields when relevant). 111 function stripQuery(u) { 112 if (!u) return ""; 113 var i = u.indexOf("?"); 114 return i === -1 ? u : u.substring(0, i); 115 } 116 117 window.buildTrackingPayload = function (extra) { 118 var sess = getGaSessionInfo(); 119 120 var payload = { 121 event_id: uuidv4(), 122 user_id: getOrCreateUserId(), 123 124 // URLs 125 page_url: clip(stripQuery(location.href), 200), 126 page_path: location.pathname, 127 first_landing_url: localStorage.getItem("first_landing_url") || "", 128 first_referrer: localStorage.getItem("first_referrer") || "", 129 referrer: document.referrer || "", 130 131 // UTM (read from cookies so they persist across pages) 132 utm_source: getCookie("utm_source") || getParam("utm_source") || "", 133 utm_medium: getCookie("utm_medium") || getParam("utm_medium") || "", 134 utm_campaign: getCookie("utm_campaign") || getParam("utm_campaign") || "", 135 utm_term: getCookie("utm_term") || getParam("utm_term") || "",
136 utm_content: getCookie("utm_content") || getParam("utm_content") || "", 137 138 // Meta CAPI matching 139 fbp: getCookie("_fbp"), 140 fbc: getCookie("_fbc"), 141 fbclid: getCookie("fbclid"), 142 143 // Google Ads click identifiers (with gtag.js cookie fallback) 144 gclid: resolveGclid(), 145 gclsrc: getCookie("gclsrc"), 146 wbraid: resolveWbraid(), 147 gbraid: resolveGbraid(), 148 dclid: resolveDclid(), 149 msclkid: getCookie("msclkid"), 150 ttclid: getCookie("ttclid"), 151 twclid: getCookie("twclid"), 152 li_fat_id: getCookie("li_fat_id"), 153 sccid: getCookie("sccid"), 154 epik: getCookie("epik"), 155 156 // GA identifiers 157 ga_client_id: getGaClientId(), 158 ga_session_id: sess.ga_session_id, 159 ga_session_number: sess.ga_session_number, 160 161 // Device (truncated to avoid blowing tag limits) 162 user_agent: clip(navigator.userAgent, 240), 163 language: navigator.language || "", 164 ipAddress: window.__client_ip || "" 165 }; 166 167 // Drop empty fields to keep the payload small. 168 Object.keys(payload).forEach(function (k) { 169 if (payload[k] === "" || payload[k] == null) delete payload[k]; 170 }); 171 172 if (extra && typeof extra === "object") { 173 Object.keys(extra).forEach(function (k) { payload[k] = extra[k]; }); 174 } 175 176 return payload; 177 }; 178})();
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.