1(function () { 2 if (window.__everythingTracker) return; 3 4 var KEY = ""; 5 var HOST = "https://everything.thetool.company"; 6 var COOKIE = '_ev_vid'; 7 var COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 2; // 2 years 8 var SESSION_KEY = '_ev_sid'; 9 // Google Ads click id, kept in its own cookie so it survives the whole 10 // consideration window: the click lands on a pricing page, the signup 11 // happens days later, and the conversion still has to name the click. 12 // 90 days matches Google's conversion import cutoff â an id older than 13 // that is rejected on upload, so there's no point keeping it longer. 14 var CLICK_COOKIE = '_ev_gclid'; 15 var CLICK_COOKIE_MAX_AGE = 60 * 60 * 24 * 90; // 90 days 16 17 // Honor Do Not Track / Global Privacy Control. We never send beacons in 18 // these cases â visitors get a no-op tracker. Opt-in override per 19 // workspace can come later via a settings toggle if needed. 20 var dnt = navigator.doNotTrack === '1' || window.doNotTrack === '1' || 21 navigator.msDoNotTrack === '1' || navigator.globalPrivacyControl === true; 22 if (dnt) { 23 window.everything = { identify: function(){}, track: function(){}, pageview: function(){}, visitorId: function(){ return null; } }; 24 window.__everythingTracker = true; 25 return; 26 } 27 28 // ââ Cookie helpers (first-party on customer domain) âââââââââââââââââââ 29 30 function getCookie(name) { 31 var match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)')); 32 return match ? decodeURIComponent(match[1]) : null; 33 } 34 35 function setCookie(name, value, maxAge) { 36 var parts = [name + '=' + encodeURIComponent(value), 'path=/', 'max-age=' + maxAge, 'SameSite=Lax']; 37 if (location.protocol === 'https:') parts.push('Secure'); 38 document.cookie = parts.join('; '); 39 } 40 41 function uuid() { 42 if (window.crypto && crypto.randomUUID) return crypto.randomUUID(); 43 var hex = 'abcdef0123456789'; 44 var s = ''; 45 for (var i = 0; i < 36; i++) { 46 if (i === 8 || i === 13 || i === 18 || i === 23) s += '-'; 47 else if (i === 14) s += '4'; 48 else if (i === 19) s += hex[(Math.random() * 4) | 8]; 49 else s += hex[(Math.random() * 16) | 0]; 50 } 51 return s; 52 } 53 54 // ââ Visitor identity ââââââââââââââââââââââââââââââââââââââââââââââââââ 55 56 var vid = getCookie(COOKIE); 57 if (!vid) { 58 try { vid = localStorage.getItem(COOKIE); } catch (e) {} 59 } 60 if (!vid) vid = uuid(); 61 setCookie(COOKIE, vid, COOKIE_MAX_AGE); 62 try { localStorage.setItem(COOKIE, vid); } catch (e) {} 63 64 // Per-tab session id, reset when the tab is closed. The server still 65 // owns session boundaries (30min inactivity), this is just for grouping 66 // beacons sent in quick succession. 67 var sid = null; 68 try { sid = sessionStorage.getItem(SESSION_KEY); } catch (e) {} 69 if (!sid) { 70 sid = uuid(); 71 try { sessionStorage.setItem(SESSION_KEY, sid); } catch (e) {} 72 } 73 74 // ââ UTM + referrer (captured once per session) ââââââââââââââââââââââââ 75 76 function parseQuery(qs) { 77 var out = {}; 78 if (!qs) return out; 79 qs.replace(/^\?/, '').split('&').forEach(function (pair) { 80 if (!pair) return; 81 var eq = pair.indexOf('='); 82 var k = eq >= 0 ? pair.slice(0, eq) : pair; 83 var v = eq >= 0 ? pair.slice(eq + 1) : ''; 84 try { out[decodeURIComponent(k)] = decodeURIComponent(v); } catch (e) { out[k] = v; } 85 }); 86 return out; 87 } 88 89 function utmParams() { 90 var q = parseQuery(location.search); 91 return { 92 utm_source: q.utm_source || null, 93 utm_medium: q.utm_medium || null, 94 utm_campaign: q.utm_campaign || null, 95 utm_term: q.utm_term || null, 96 utm_content: q.utm_content || null, 97 }; 98 } 99 100 // ââ Google Ads click ids ââââââââââââââââââââââââââââââââââââââââââââââ 101 // Exactly one of gclid / gbraid / wbraid rides on a paid click, depending 102 // on the privacy context (wbraid/gbraid appear on iOS where gclid is
103 // withheld). Whichever we see is written to a cookie on first touch and 104 // replayed on every later beacon, so a signup that happens three pages or 105 // three days after the click still carries the id that paid for it. 106 // 107 // First-touch wins: overwriting on a later organic visit would be a no-op 108 // (no id in the URL), but a second *paid* click legitimately replaces it â 109 // Google attributes to the most recent click. 110 111 function readStoredClick() { 112 var raw = getCookie(CLICK_COOKIE); 113 if (!raw) { 114 try { raw = localStorage.getItem(CLICK_COOKIE); } catch (e) {} 115 } 116 if (!raw) return null; 117 try { 118 var parsed = JSON.parse(raw); 119 if (parsed && (parsed.gclid || parsed.gbraid || parsed.wbraid)) return parsed; 120 } catch (e) {} 121 return null; 122 } 123 124 function clickIds() { 125 var q = parseQuery(location.search); 126 var fresh = q.gclid || q.gbraid || q.wbraid; 127 128 if (fresh) { 129 var record = { 130 gclid: q.gclid || null, 131 gbraid: q.gbraid || null, 132 wbraid: q.wbraid || null, 133 at: new Date().toISOString(), 134 }; 135 var json = JSON.stringify(record); 136 setCookie(CLICK_COOKIE, json, CLICK_COOKIE_MAX_AGE); 137 try { localStorage.setItem(CLICK_COOKIE, json); } catch (e) {} 138 return record; 139 } 140 141 // No id in this URL â replay whatever the original click stored. 142 var stored = readStoredClick(); 143 if (!stored) return { gclid: null, gbraid: null, wbraid: null, at: null }; 144 return { 145 gclid: stored.gclid || null, 146 gbraid: stored.gbraid || null, 147 wbraid: stored.wbraid || null, 148 at: stored.at || null, 149 }; 150 } 151 152 // ââ Beacon ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 153 154 function send(type, body) { 155 var payload = Object.assign({ 156 type: type, 157 key: KEY, 158 vid: vid, 159 sid: sid, 160 }, body || {}); 161 var json = JSON.stringify(payload); 162 var url = HOST + '/api/track/web'; 163 try { 164 if (navigator.sendBeacon) { 165 var blob = new Blob([json], { type: 'application/json' }); 166 if (navigator.sendBeacon(url, blob)) return; 167 } 168 } catch (e) {} 169 // Fallback fetch (keepalive so it survives unload). 170 try { 171 fetch(url, { 172 method: 'POST', 173 headers: { 'Content-Type': 'application/json' }, 174 body: json, 175 // 'include' so the Everything-domain _evd cookie (identity network) 176 // rides along; sendBeacon above already sends cookies by default. 177 credentials: 'include', 178 keepalive: true, 179 }).catch(function () {}); 180 } catch (e) {} 181 } 182 183 // ââ Pageview tracking âââââââââââââââââââââââââââââââââââââââââââââââââ 184 185 var lastPath = null; 186 var pageStartedAt = Date.now(); 187 188 function pageviewBody() { 189 var q = parseQuery(location.search); 190 return { 191 url: location.href, 192 path: location.pathname, 193 title: document.title || null, 194 referrer: document.referrer || null, 195 lang: navigator.language || null, 196 screen_w: window.screen ? window.screen.width : null, 197 screen_h: window.screen ? window.screen.height : null, 198 utm: utmParams(), 199 click: clickIds(), 200 // _evid lets us auto-stitch when a visitor clicks an outbound email 201 // link tracked by /api/track/click â the redirect appends _evid. 202 identify_contact_id: q._evid || null, 203 }; 204 } 205 206 function pageview() { 207 if (lastPath !== null) { 208 // Send duration of the previous page before recording the new one. 209 var dur = Math.round((Date.now() - pageStartedAt) / 1000); 210 if (dur > 0) send('page_unload', { path: lastPath, duration_seconds: dur }); 211 } 212 lastPath = location.pathname + location.search; 213 pageStartedAt = Date.now(); 214 send('pageview', pageviewBody()); 215 } 216 217 // SPA navigation: hook history methods + popstate. 218 function patchHistory(name) { 219 var orig = history[name]; 220 if (typeof orig !== 'function') return; 221 history[name] = function () { 222 var ret = orig.apply(this, arguments); 223 setTimeout(pageview, 0); 224 return ret; 225 }; 226 } 227 patchHistory('pushState'); 228 patchHistory('replaceState'); 229 window.addEventListener('popstate', function () { setTimeout(pageview, 0); }); 230 231 // Send unload duration on tab close / blur (so server-side time-on-page is accurate). 232 function flushUnload() {
233 if (lastPath === null) return; 234 var dur = Math.round((Date.now() - pageStartedAt) / 1000); 235 if (dur > 0) send('page_unload', { path: lastPath, duration_seconds: dur }); 236 } 237 window.addEventListener('pagehide', flushUnload); 238 window.addEventListener('beforeunload', flushUnload); 239 240 // ââ Public API: window.everything âââââââââââââââââââââââââââââââââââââ 241 242 var api = { 243 visitorId: function () { return vid; }, 244 // Lets our own signup page read the click id that paid for this visitor 245 // and attach it to the account, so the eventual paid conversion can be 246 // imported back into Google Ads against the right click. 247 clickIds: clickIds, 248 pageview: pageview, 249 track: function (name, properties) { 250 if (!name) return; 251 send('event', { 252 name: String(name), 253 properties: properties || {}, 254 url: location.href, 255 path: location.pathname, 256 click: clickIds(), 257 }); 258 }, 259 identify: function (email, name, traits) { 260 if (!email) return; 261 send('identify', { 262 email: String(email).trim().toLowerCase(), 263 name: name ? String(name) : null, 264 traits: traits || {}, 265 url: location.href, 266 path: location.pathname, 267 click: clickIds(), 268 }); 269 }, 270 }; 271 272 // Replay queued calls made before the script loaded: 273 // window.everything = window.everything || function(){(everything.q=everything.q||[]).push(arguments)}; 274 var existing = window.everything; 275 window.everything = api; 276 if (existing && existing.q && existing.q.length) { 277 for (var i = 0; i < existing.q.length; i++) { 278 try { 279 var call = existing.q[i]; 280 var method = call[0]; 281 if (api[method]) api[method].apply(null, Array.prototype.slice.call(call, 1)); 282 } catch (e) {} 283 } 284 } 285 286 // ââ Auto-identify on form submit ââââââââââââââââââââââââââââââââââââââ 287 // Scan submitted forms for any email-shaped input and call identify() so 288 // customers get visitor stitching without any manual code. 289 document.addEventListener('submit', function (ev) { 290 try { 291 var form = ev.target; 292 if (!form || form.tagName !== 'FORM') return; 293 var inputs = form.querySelectorAll('input, textarea'); 294 var email = null; 295 var name = null; 296 for (var i = 0; i < inputs.length; i++) { 297 var el = inputs[i]; 298 var type = (el.getAttribute('type') || '').toLowerCase(); 299 var nm = (el.getAttribute('name') || el.getAttribute('id') || el.getAttribute('autocomplete') || '').toLowerCase(); 300 var val = (el.value || '').trim(); 301 if (!val) continue; 302 if (!email && (type === 'email' || /email|e-mail/.test(nm)) && /.+@.+\..+/.test(val)) email = val; 303 if (!name && /^(name|full[-_]?name|fname|firstname)/.test(nm)) name = val; 304 } 305 if (email) api.identify(email, name); 306 } catch (e) {} 307 }, true); 308 309 window.__everythingTracker = true; 310 311 // First pageview. 312 pageview(); 313})();
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.