UNPKG

@datalyr/web

Version:

Datalyr Web SDK - Modern attribution tracking for web applications

3 lines (2 loc) 40.9 kB
function t(t,e,i,s){return new(i||(i=Promise))(function(n,o){function r(t){try{c(s.next(t))}catch(t){o(t)}}function a(t){try{c(s.throw(t))}catch(t){o(t)}}function c(t){var e;t.done?n(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(r,a)}c((s=s.apply(t,e||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;class e{constructor(t){this.memory=new Map,this.prefix="__dl_";try{const e="__dl_test__"+Math.random();t.setItem(e,"1"),t.removeItem(e),this.storage=t}catch(t){this.storage=null,console.warn("[Datalyr] Storage not available, using memory fallback")}}get(t,e=null){const i=this.prefix+t;try{if(this.storage){const t=this.storage.getItem(i);if(null===t)return e;try{return JSON.parse(t)}catch(e){return t}}else{const t=this.memory.get(i);if(void 0===t)return e;try{return JSON.parse(t)}catch(e){return t}}}catch(t){return e}}set(t,e){const i=this.prefix+t,s="string"==typeof e?e:JSON.stringify(e);try{return this.storage?(this.storage.setItem(i,s),!0):(this.memory.set(i,s),!0)}catch(e){return console.warn("[Datalyr] Failed to store:",t,e),this.memory.set(i,s),!1}}remove(t){const e=this.prefix+t;try{return this.storage?(this.storage.removeItem(e),!0):(this.memory.delete(e),!0)}catch(t){return!1}}keys(){try{if(this.storage){const t=[];for(let e=0;e<this.storage.length;e++){const i=this.storage.key(e);i&&i.startsWith(this.prefix)&&t.push(i.slice(this.prefix.length))}return t}return Array.from(this.memory.keys()).filter(t=>t.startsWith(this.prefix)).map(t=>t.slice(this.prefix.length))}catch(t){return[]}}}class i{constructor(t={}){this.domain=t.domain||"auto",this.maxAge=t.maxAge||365,this.sameSite=t.sameSite||"Lax",this.secure=t.secure||"auto"}get(t){var e;const i=`; ${document.cookie}`.split(`; ${t}=`);if(2===i.length){const t=(null===(e=i.pop())||void 0===e?void 0:e.split(";").shift())||null;if(t)try{return decodeURIComponent(t)}catch(e){return t}}return null}set(t,e,i){try{const s=86400*(i||this.maxAge),n="auto"===this.secure?"https:"===location.protocol:this.secure;let o="";"auto"===this.domain?o=this.getAutoDomain():this.domain&&(o=`;domain=${this.domain}`);const r=[`${t}=${encodeURIComponent(e)}`,`max-age=${s}`,"path=/",`SameSite=${this.sameSite}`,n?"Secure":"",o].filter(Boolean).join(";");return document.cookie=r,!0}catch(e){return console.warn("[Datalyr] Failed to set cookie:",t,e),!1}}remove(t){try{const e=["",location.hostname],i=location.hostname.split(".");return i.length>2&&(e.push(`.${i.slice(-2).join(".")}`),e.push(`.${location.hostname}`)),e.forEach(e=>{const i=e?`;domain=${e}`:"";document.cookie=`${t}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/${i}`}),!0}catch(t){return!1}}getAutoDomain(){const t=location.hostname;if("localhost"===t||/^[\d.]+$/.test(t)||/^\[[\d:]+\]$/.test(t))return"";const e=t.split(".");for(let t=e.length-2;t>=0;t--){const i="."+e.slice(t).join("."),s="__dl_test_"+Math.random();if(document.cookie=`${s}=1;domain=${i};path=/`,-1!==document.cookie.indexOf(s))return document.cookie=`${s}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;domain=${i};path=/`,`;domain=${i}`}return""}}const s=new e(window.localStorage);new e(window.sessionStorage);const n=new i;function o(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)})}function r(t=window.location.search){const e={};try{if("URLSearchParams"in window){return new URLSearchParams(t).forEach((t,i)=>{e[i]=t}),e}}catch(t){}const i=(t||"").replace(/^\?/,"").split("&");for(const t of i){const[i,s=""]=t.split("=");try{const t=decodeURIComponent((i||"").replace(/\+/g," ")),n=decodeURIComponent((s||"").replace(/\+/g," "));t&&(e[t]=n)}catch(t){}}return e}function a(t,e=5,i=0){if(i>=e)return"[Max depth reached]";if(null==t)return t;if("undefined"!=typeof Element&&t instanceof Element||"undefined"!=typeof Document&&t instanceof Document||"function"==typeof t)return"[Removed]";if(Array.isArray(t))return t.map(t=>a(t,e,i+1));if("object"==typeof t){const s={},n=/pass|pwd|token|secret|auth|bearer|session|cookie|signature|api[-_]?key|private[-_]?key|access[-_]?token|refresh[-_]?token/i;for(const o in t)if(Object.prototype.hasOwnProperty.call(t,o)){if(n.test(o))continue;s[o]=a(t[o],e,i+1)}return s}return"string"==typeof t?t.length>1e3?t.slice(0,1e3)+"...[truncated]":t.match(/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/)||t.match(/^[a-f0-9]{32,}$/i)?"[Redacted]":t:t}function c(t,...e){if(!e.length)return t;const i=e.shift();if(l(t)&&l(i))for(const e in i)l(i[e])?(t[e]||Object.assign(t,{[e]:{}}),c(t[e],i[e])):Object.assign(t,{[e]:i[e]});return c(t,...e)}function l(t){return t&&"object"==typeof t&&!Array.isArray(t)}function d(t){const e={google:["google.com","google."],facebook:["facebook.com","fb.com"],twitter:["twitter.com","t.co","x.com"],linkedin:["linkedin.com","lnkd.in"],instagram:["instagram.com"],youtube:["youtube.com","youtu.be"],tiktok:["tiktok.com"],reddit:["reddit.com"],pinterest:["pinterest.com"],bing:["bing.com"],yahoo:["yahoo.com"],duckduckgo:["duckduckgo.com"],baidu:["baidu.com"]};for(const[i,s]of Object.entries(e))if(s.some(e=>t.includes(e)))return i;return"other"}class u{constructor(){this.userId=null,this.sessionId=null,this.anonymousId=this.getOrCreateAnonymousId(),this.userId=this.getStoredUserId()}getOrCreateAnonymousId(){let t=n.get("__dl_visitor_id");return t?(s.set("dl_anonymous_id",t),t):(t=s.get("dl_anonymous_id"),t?(this.setRootDomainCookie("__dl_visitor_id",t),t):(t=`anon_${o()}`,this.setRootDomainCookie("__dl_visitor_id",t),s.set("dl_anonymous_id",t),t))}setRootDomainCookie(t,e){try{const i=function(){const t=window.location.hostname;if("localhost"===t||t.match(/^[0-9]{1,3}\./)||t.match(/^\[?[0-9a-fA-F:]+\]?$/))return t;const e=t.split(".");if(e.length>=2){const t=e[e.length-1],i=`${e[e.length-2]}.${t}`;return["co.uk","com.au","co.nz","co.jp","co.in","co.za"].includes(i)&&e.length>=3?"."+e.slice(-3).join("."):"."+e.slice(-2).join(".")}return t}(),s="https:"===location.protocol?"; Secure":"",o=encodeURIComponent(e);document.cookie=`${t}=${o}; domain=${i}; path=/; max-age=31536000; SameSite=Lax${s}`;n.get(t)===e?console.log(`[Datalyr] Set root domain cookie: ${t} on domain: ${i}`):(document.cookie=`${t}=${o}; path=/; max-age=31536000; SameSite=Lax${s}`,console.log(`[Datalyr] Set cookie without domain (fallback): ${t}`))}catch(i){console.error("[Datalyr] Error setting root domain cookie:",i);try{const i="https:"===location.protocol?"; Secure":"",s=encodeURIComponent(e);document.cookie=`${t}=${s}; path=/; max-age=31536000; SameSite=Lax${i}`}catch(t){console.error("[Datalyr] Failed to set cookie even without domain:",t)}}}getStoredUserId(){return s.get("dl_user_id")}getAnonymousId(){return this.anonymousId}getUserId(){return this.userId}getDistinctId(){return this.userId||this.anonymousId}getCanonicalId(){return this.getDistinctId()}setSessionId(t){this.sessionId=t}getSessionId(){return this.sessionId}identify(t,e={}){if(!t)return console.warn("[Datalyr] identify() called without userId"),{};const i=this.userId;return this.userId=t,s.set("dl_user_id",t),{anonymous_id:this.anonymousId,user_id:t,previous_id:i,traits:e,identified_at:(new Date).toISOString(),resolution_method:"identify_call"}}alias(t,e){const i={userId:t,previousId:e||this.anonymousId,aliased_at:(new Date).toISOString()};return e&&e!==this.anonymousId||(this.userId=t,s.set("dl_user_id",t)),i}reset(){this.userId=null,s.remove("dl_user_id"),s.remove("dl_user_traits"),this.anonymousId=`anon_${o()}`,s.set("dl_anonymous_id",this.anonymousId),this.setRootDomainCookie("__dl_visitor_id",this.anonymousId)}getIdentityFields(){return{distinct_id:this.getDistinctId(),anonymous_id:this.anonymousId,user_id:this.userId,visitor_id:this.anonymousId,visitorId:this.anonymousId,canonical_id:this.getCanonicalId(),session_id:this.sessionId,sessionId:this.sessionId,resolution_method:"browser_sdk",resolution_confidence:1}}}class h{constructor(t=18e5){this.sessionId=null,this.sessionData=null,this.lastActivity=Date.now(),this.SESSION_KEY="dl_session_data",this.activityCheckInterval=null,this.activityListeners=[],this.sessionTimeout=t,this.initSession(),this.setupActivityMonitor()}initSession(){const t=s.get(this.SESSION_KEY),e=Date.now();t&&this.isSessionValid(t,e)?(this.sessionData=t,this.sessionId=t.id,this.lastActivity=e):this.createNewSession()}isSessionValid(t,e){return e-t.lastActivity<this.sessionTimeout&&t.isActive}createNewSession(){const t=Date.now();return this.sessionId=`sess_${o()}`,this.sessionData={id:this.sessionId,startTime:t,lastActivity:t,pageViews:0,events:0,duration:0,isActive:!0},this.incrementSessionCount(),this.saveSession(),this.sessionId}getSessionId(){return this.sessionId&&this.isSessionActive()||this.createNewSession(),this.sessionId}getSessionData(){return this.sessionData}updateActivity(t){const e=Date.now();this.sessionData&&this.isSessionValid(this.sessionData,e)?(this.lastActivity=e,this.sessionData.lastActivity=e,this.sessionData.duration=e-this.sessionData.startTime,"pageview"!==t&&"page_view"!==t||this.sessionData.pageViews++,this.sessionData.events++,this.saveSession()):this.createNewSession()}isSessionActive(){if(!this.sessionData)return!1;const t=Date.now();return this.isSessionValid(this.sessionData,t)}endSession(){this.sessionData&&(this.sessionData.isActive=!1,this.saveSession()),this.sessionId=null,this.sessionData=null}saveSession(){this.sessionData&&s.set(this.SESSION_KEY,this.sessionData)}getTimeout(){return this.sessionTimeout}setTimeout(t){this.sessionTimeout=t}storeAttribution(t){const e=`dl_session_${this.sessionId}_attribution`;s.set(e,Object.assign(Object.assign({},t),{sessionId:this.sessionId,timestamp:Date.now()}))}getAttribution(){if(!this.sessionId)return null;const t=`dl_session_${this.sessionId}_attribution`;return s.get(t)}getMetrics(){return this.sessionData?{session_id:this.sessionId,session_duration:this.sessionData.duration,session_page_views:this.sessionData.pageViews,session_events:this.sessionData.events,session_start:this.sessionData.startTime,time_since_session_start:Date.now()-this.sessionData.startTime}:{}}setupActivityMonitor(){const t=()=>{const t=Date.now();this.sessionData&&t-this.lastActivity>1e3&&this.updateActivity()};["mousedown","keydown","scroll","touchstart"].forEach(e=>{window.addEventListener(e,t,{passive:!0,capture:!0}),this.activityListeners.push({event:e,handler:t})}),this.activityCheckInterval=setInterval(()=>{this.sessionData&&!this.isSessionActive()&&this.createNewSession()},6e4)}destroy(){this.activityListeners.forEach(({event:t,handler:e})=>{window.removeEventListener(t,e)}),this.activityListeners=[],this.activityCheckInterval&&(clearInterval(this.activityCheckInterval),this.activityCheckInterval=null)}getSessionNumber(){return s.get("dl_session_count",0)+1}incrementSessionCount(){const t=s.get("dl_session_count",0);s.set("dl_session_count",t+1)}}class g{constructor(t={}){this.UTM_PARAMS=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],this.CLICK_IDS=["fbclid","gclid","gbraid","wbraid","ttclid","msclkid","twclid","li_fat_id","sclid","dclid","epik","rdt_cid","obclid","irclid","ko_click_id"],this.DEFAULT_TRACKED_PARAMS=["lyr","ref","source","campaign","medium","gad_source"],this.attributionWindow=t.attributionWindow||2592e6,this.trackedParams=[...this.DEFAULT_TRACKED_PARAMS,...t.trackedParams||[]]}captureAttribution(){const t=r(),e={timestamp:Date.now()};for(const i of this.UTM_PARAMS){const s=t[i];if(s){e[i.replace("utm_","")]=s}}for(const i of this.CLICK_IDS){const s=t[i];if(s){e.clickId=s,e.clickIdType=i;break}}for(const i of this.trackedParams){const s=t[i];s&&(e[i]=s)}return document.referrer&&(e.referrer=document.referrer,e.referrerHost=this.extractHostname(document.referrer)),e.landingPage=window.location.href,e.landingPath=window.location.pathname,e.source||(e.source=this.determineSource(e)),e.medium||(e.medium=this.determineMedium(e)),e}storeFirstTouch(t){s.get("dl_first_touch")||s.set("dl_first_touch",Object.assign(Object.assign({},t),{timestamp:Date.now()}))}getFirstTouch(){return s.get("dl_first_touch")}storeLastTouch(t){s.set("dl_last_touch",Object.assign(Object.assign({},t),{timestamp:Date.now()}))}getLastTouch(){return s.get("dl_last_touch")}addTouchpoint(t,e){const i=this.getJourney(),n={timestamp:Date.now(),sessionId:t,source:e.source||void 0,medium:e.medium||void 0,campaign:e.campaign||void 0};i.push(n),i.length>30&&i.shift(),s.set("dl_journey",i)}getJourney(){return s.get("dl_journey",[])}captureAdCookies(){const t={};if(t._fbp=n.get("_fbp"),t._fbc=n.get("_fbc"),t._gcl_aw=n.get("_gcl_aw"),t._gcl_dc=n.get("_gcl_dc"),t._gcl_gb=n.get("_gcl_gb"),t._gcl_ha=n.get("_gcl_ha"),t._gac=n.get("_gac"),t._ga=n.get("_ga"),t._gid=n.get("_gid"),t._ttp=n.get("_ttp"),t._ttc=n.get("_ttc"),!t._fbp&&(this.hasClickId("fbclid")||t._fbc)){const e=Date.now(),i=Math.random().toString(36).substring(2,15);t._fbp=`fb.1.${e}.${i}`,n.set("_fbp",t._fbp,90)}const e=this.getCurrentFbclid();if(e&&!t._fbc){const i=Math.floor(Date.now()/1e3);t._fbc=`fb.1.${i}.${e}`,n.set("_fbc",t._fbc,90)}return Object.fromEntries(Object.entries(t).filter(([t,e])=>null!==e))}hasClickId(t){return!!r()[t]}getCurrentFbclid(){return r().fbclid||null}getAttributionData(){const t=this.getFirstTouch(),e=this.getLastTouch(),i=this.getJourney(),s=this.captureAttribution(),n=this.captureAdCookies();return!t&&Object.keys(s).length>1&&this.storeFirstTouch(s),Object.keys(s).length>1&&this.storeLastTouch(s),Object.assign(Object.assign(Object.assign({},s),n),{first_touch_source:null==t?void 0:t.source,first_touch_medium:null==t?void 0:t.medium,first_touch_campaign:null==t?void 0:t.campaign,first_touch_timestamp:null==t?void 0:t.timestamp,firstTouchSource:null==t?void 0:t.source,firstTouchMedium:null==t?void 0:t.medium,firstTouchCampaign:null==t?void 0:t.campaign,last_touch_source:null==e?void 0:e.source,last_touch_medium:null==e?void 0:e.medium,last_touch_campaign:null==e?void 0:e.campaign,last_touch_timestamp:null==e?void 0:e.timestamp,lastTouchSource:null==e?void 0:e.source,lastTouchMedium:null==e?void 0:e.medium,lastTouchCampaign:null==e?void 0:e.campaign,touchpoint_count:i.length,touchpointCount:i.length,days_since_first_touch:(null==t?void 0:t.timestamp)?Math.floor((Date.now()-t.timestamp)/864e5):0,daysSinceFirstTouch:(null==t?void 0:t.timestamp)?Math.floor((Date.now()-t.timestamp)/864e5):0})}determineSource(t){if(t.clickIdType){return{fbclid:"facebook",gclid:"google",ttclid:"tiktok",msclkid:"bing",twclid:"twitter",li_fat_id:"linkedin",sclid:"snapchat",dclid:"doubleclick",epik:"pinterest"}[t.clickIdType]||"paid"}if(t.referrerHost){const e=t.referrerHost.toLowerCase();return e.includes("facebook.com")||e.includes("fb.com")?"facebook":e.includes("twitter.com")||e.includes("t.co")||e.includes("x.com")?"twitter":e.includes("linkedin.com")||e.includes("lnkd.in")?"linkedin":e.includes("instagram.com")?"instagram":e.includes("youtube.com")||e.includes("youtu.be")?"youtube":e.includes("tiktok.com")?"tiktok":e.includes("reddit.com")?"reddit":e.includes("pinterest.com")?"pinterest":e.includes("google.")?"google":e.includes("bing.com")?"bing":e.includes("yahoo.com")?"yahoo":e.includes("duckduckgo.com")?"duckduckgo":e.includes("baidu.com")?"baidu":"referral"}return"direct"}determineMedium(t){if(t.clickId)return"cpc";const e=t.source;if(!e||"direct"===e)return"none";if(["facebook","twitter","linkedin","instagram","youtube","tiktok","reddit","pinterest"].includes(e))return"social";return["google","bing","yahoo","duckduckgo","baidu"].includes(e)?"organic":"referral"}extractHostname(t){try{return new URL(t).hostname}catch(t){return""}}isAttributionExpired(t){return!t.timestamp||Date.now()-t.timestamp>this.attributionWindow}clearExpiredAttribution(){const t=this.getFirstTouch(),e=this.getLastTouch();t&&this.isAttributionExpired(t)&&s.remove("dl_first_touch"),e&&this.isAttributionExpired(e)&&s.remove("dl_last_touch")}}const p=["purchase","signup","subscribe","lead","conversion"],f=["add_to_cart","begin_checkout","view_item","search"];class m{constructor(t){this.queue=[],this.offlineQueue=[],this.batchTimer=null,this.periodicFlushInterval=null,this.flushPromise=null,this.recentEventIds=new Set,this.MAX_RECENT_EVENT_IDS=1e3,this.OFFLINE_QUEUE_KEY="dl_offline_queue",this.config={batchSize:t.batchSize||10,flushInterval:t.flushInterval||5e3,maxRetries:t.maxRetries||5,retryDelay:t.retryDelay||1e3,endpoint:t.endpoint||"https://ingest.datalyr.com",fallbackEndpoints:t.fallbackEndpoints||[],workspaceId:t.workspaceId,debug:t.debug||!1,criticalEvents:t.criticalEvents||p,highPriorityEvents:t.highPriorityEvents||f,maxOfflineQueueSize:t.maxOfflineQueueSize||100},this.networkStatus={isOnline:!1!==navigator.onLine,lastOfflineAt:null,lastOnlineAt:null},this.loadOfflineQueue(),this.setupNetworkListeners(),this.startPeriodicFlush()}enqueue(t){const e=t.eventName;if(this.isDuplicateEvent(t))this.log("Duplicate event suppressed:",e);else{if(this.config.criticalEvents.includes(e))return this.log("Critical event, sending immediately:",e),void this.sendBatch([t]);this.queue.push(t),this.log("Event queued:",e),this.shouldFlush(e)&&this.flush()}}isDuplicateEvent(t){const e=t.eventId;if(this.recentEventIds.has(e))return!0;if(this.recentEventIds.add(e),this.recentEventIds.size>this.MAX_RECENT_EVENT_IDS){const t=this.recentEventIds.size-this.MAX_RECENT_EVENT_IDS,e=this.recentEventIds.values();for(let i=0;i<t;i++){const t=e.next();t.done||this.recentEventIds.delete(t.value)}}return!1}shouldFlush(t){return this.queue.length>=this.config.batchSize||(t&&this.config.highPriorityEvents.includes(t)?(this.batchTimer&&clearTimeout(this.batchTimer),this.batchTimer=setTimeout(()=>this.flush(),1e3),!1):(this.batchTimer||(this.batchTimer=setTimeout(()=>this.flush(),this.config.flushInterval)),!1))}flush(){return t(this,void 0,void 0,function*(){if(this.flushPromise)return this.flushPromise;this.flushPromise=this._flush(),yield this.flushPromise,this.flushPromise=null})}_flush(){return t(this,void 0,void 0,function*(){if(this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),0===this.queue.length)return;if(!this.networkStatus.isOnline)return this.log("Network offline, queuing events"),void this.moveToOfflineQueue();const t=this.queue.splice(0,this.config.batchSize);try{yield this.sendBatch(t)}catch(e){this.log("Failed to send batch:",e),this.offlineQueue.push(...t),this.saveOfflineQueue()}})}sendBatch(e){return t(this,arguments,void 0,function*(t,e=0,i=0){const s={events:t,batchId:o(),timestamp:(new Date).toISOString()},n=[this.config.endpoint,...this.config.fallbackEndpoints],r=n[i]||this.config.endpoint;try{const e=yield fetch(r,{method:"POST",headers:{"Content-Type":"application/json","X-Batch-Size":t.length.toString()},body:JSON.stringify(s),keepalive:!0});if(!e.ok){if(429===e.status){const i=parseInt(e.headers.get("Retry-After")||"60");return this.log(`Rate limited, retrying after ${i}s`),void setTimeout(()=>{this.queue.unshift(...t)},1e3*i)}throw new Error(`HTTP ${e.status}: ${e.statusText}`)}this.log(`Batch sent successfully to ${r}: ${t.length} events`)}catch(s){if(i<n.length-1)return this.log(`Failed on ${r}, trying fallback ${i+1}`),this.sendBatch(t,0,i+1);if(e<this.config.maxRetries){const s=function(t,e=1e3){const i=.1*Math.random();return Math.min(e*Math.pow(2,t)*(1+i),3e4)}(e,this.config.retryDelay);return this.log(`Retrying batch in ${s}ms (attempt ${e+1}/${this.config.maxRetries})`),yield new Promise(t=>setTimeout(t,s)),this.sendBatch(t,e+1,i)}throw s}})}setupNetworkListeners(){window.addEventListener("online",()=>{this.networkStatus.isOnline=!0,this.networkStatus.lastOnlineAt=Date.now(),this.log("Network connection restored"),setTimeout(()=>this.processOfflineQueue(),1e3)}),window.addEventListener("offline",()=>{this.networkStatus.isOnline=!1,this.networkStatus.lastOfflineAt=Date.now(),this.log("Network connection lost")})}startPeriodicFlush(){this.periodicFlushInterval=setInterval(()=>{this.queue.length>0&&this.flush()},this.config.flushInterval)}stopPeriodicFlush(){this.periodicFlushInterval&&(clearInterval(this.periodicFlushInterval),this.periodicFlushInterval=null)}moveToOfflineQueue(){this.offlineQueue.push(...this.queue),this.queue=[],this.saveOfflineQueue()}loadOfflineQueue(){const t=s.get(this.OFFLINE_QUEUE_KEY,[]);Array.isArray(t)&&(this.offlineQueue=t,this.log(`Loaded ${this.offlineQueue.length} offline events`))}saveOfflineQueue(){const t=this.offlineQueue.slice(-this.config.maxOfflineQueueSize);s.set(this.OFFLINE_QUEUE_KEY,t)}processOfflineQueue(){return t(this,void 0,void 0,function*(){if(0!==this.offlineQueue.length){for(this.log(`Processing ${this.offlineQueue.length} offline events`);this.offlineQueue.length>0;){const t=this.offlineQueue.splice(0,this.config.batchSize);try{yield this.sendBatch(t),this.saveOfflineQueue()}catch(e){this.log("Failed to send offline batch:",e),this.offlineQueue.unshift(...t),this.saveOfflineQueue();break}}0===this.offlineQueue.length&&s.remove(this.OFFLINE_QUEUE_KEY)}})}getQueueSize(){return this.queue.length}getOfflineQueueSize(){return this.offlineQueue.length}getNetworkStatus(){return Object.assign({},this.networkStatus)}forceFlush(){return t(this,void 0,void 0,function*(){if(navigator.sendBeacon&&this.queue.length>0){const t={events:this.queue,batchId:o(),timestamp:(new Date).toISOString()},e=new Blob([JSON.stringify(t)],{type:"application/json"});if(navigator.sendBeacon(this.config.endpoint,e))return this.log("Events sent via sendBeacon"),void(this.queue=[])}yield this.flush()})}clear(){this.queue=[],this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null)}log(...t){this.config.debug&&console.log("[Datalyr Queue]",...t)}destroy(){this.stopPeriodicFlush(),this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),this.queue.length>0&&this.moveToOfflineQueue()}}class y{constructor(t={}){this.heavyFingerprintDone=!1,this.fingerprintCache={},this.privacyMode=t.privacyMode||"standard",this.enableFingerprinting=!1!==t.enableFingerprinting}collect(){return"strict"!==this.privacyMode&&this.enableFingerprinting?this.collectStandard():this.collectMinimal()}collectMinimal(){const t={timezone:this.getTimezone(),language:navigator.language||null,screen_bucket:this.getScreenBucket(),dnt:"1"===navigator.doNotTrack||!0===window.globalPrivacyControl||null,userAgent:navigator.userAgent||null};if("userAgentData"in navigator){const e=navigator.userAgentData;t.userAgentData={brands:e.brands||[],mobile:e.mobile||!1,platform:e.platform||null}}return t}collectStandard(){const t={};try{if(t.timezone=this.getTimezone(),t.language=navigator.language||null,t.screen_bucket=this.getScreenBucket(),t.dnt="1"===navigator.doNotTrack||!0===window.globalPrivacyControl||null,t.userAgent=navigator.userAgent||null,"userAgentData"in navigator){const e=navigator.userAgentData;t.userAgentData={brands:e.brands||[],mobile:e.mobile||!1,platform:e.platform||null}}}catch(t){console.warn("[Datalyr] Error collecting fingerprint:",t)}return t}getTimezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||null}catch(t){return null}}getScreenBucket(){try{if(!window.screen)return null;const t=100*Math.round(screen.width/100);return`${t}x${100*Math.round(screen.height/100)}`}catch(t){return null}}generateHash(e){return t(this,void 0,void 0,function*(){try{const t=Object.keys(e).sort().reduce((t,i)=>(t[i]=e[i],t),{}),i=JSON.stringify(t);if(window.crypto&&window.crypto.subtle){const t=(new TextEncoder).encode(i),e=yield crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(e)).map(t=>t.toString(16).padStart(2,"0")).join("")}let s=0;for(let t=0;t<i.length;t++){s=(s<<5)-s+i.charCodeAt(t),s&=s}return Math.abs(s).toString(16)}catch(t){return""}})}}class _{constructor(t){this.scripts=[],this.loadedScripts=new Set,this.sessionLoadedScripts=new Set,this.pixels=null,this.initialized=!1,this.workspaceId=t.workspaceId,this.endpoint=t.endpoint||"https://ingest.datalyr.com",this.debug=t.debug||!1;const e=s.get("dl_session_scripts",[]);this.sessionLoadedScripts=new Set(e)}init(){return t(this,void 0,void 0,function*(){if(!this.initialized)try{const t=yield fetch(`${this.endpoint}/container-scripts`,{method:"POST",headers:{"Content-Type":"application/json","X-Container-Version":"1.0"},body:JSON.stringify({workspaceId:this.workspaceId})});if(!t.ok)throw new Error(`Failed to fetch container scripts: ${t.status}`);const e=yield t.json();this.scripts=e.scripts||[],this.pixels=e.pixels||null,this.pixels&&this.initializePixels(),this.loadScriptsByTrigger("page_load"),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{this.loadScriptsByTrigger("dom_ready")}):this.loadScriptsByTrigger("dom_ready"),window.addEventListener("load",()=>{this.loadScriptsByTrigger("window_load")}),this.initialized=!0,this.log("Container manager initialized with",this.scripts.length,"scripts")}catch(t){this.log("Error initializing container:",t)}})}loadScriptsByTrigger(t){this.scripts.filter(e=>e.enabled&&e.trigger===t&&this.shouldLoadScript(e)).forEach(t=>this.loadScript(t))}shouldLoadScript(t){return("once_per_page"!==t.frequency||!this.loadedScripts.has(t.id))&&(("once_per_session"!==t.frequency||!this.sessionLoadedScripts.has(t.id))&&(!(t.conditions&&t.conditions.length>0)||this.evaluateConditions(t.conditions)))}evaluateConditions(t){return t.every(t=>{try{const{type:e,operator:i,value:s}=t;switch(e){case"url_path":return this.evaluateStringCondition(window.location.pathname,i,s);case"url_host":return this.evaluateStringCondition(window.location.hostname,i,s);case"url_parameter":const e=new URLSearchParams(window.location.search);return this.evaluateStringCondition(e.get(t.parameter)||"",i,s);case"referrer":return this.evaluateStringCondition(document.referrer,i,s);case"device_type":const n=/Mobile|Android|iPhone|iPad/i.test(navigator.userAgent);return this.evaluateStringCondition(n?"mobile":"desktop",i,s);default:return!0}}catch(t){return!1}})}evaluateStringCondition(t,e,i){switch(e){case"equals":return t===i;case"not_equals":return t!==i;case"contains":return t.includes(i);case"not_contains":return!t.includes(i);case"starts_with":return t.startsWith(i);case"ends_with":return t.endsWith(i);case"matches_regex":try{return new RegExp(i).test(t)}catch(t){return!1}default:return!1}}loadScript(t){try{switch(t.type){case"inline":this.loadInlineScript(t);break;case"external":this.loadExternalScript(t);break;case"pixel":this.loadPixel(t)}this.loadedScripts.add(t.id),"once_per_session"===t.frequency&&(this.sessionLoadedScripts.add(t.id),s.set("dl_session_scripts",Array.from(this.sessionLoadedScripts))),this.log("Loaded script:",t.name)}catch(e){this.log("Error loading script:",t.name,e)}}loadInlineScript(t){if(this.containsMaliciousPatterns(t.content))return void this.log("Blocked potentially malicious inline script:",t.id);const e=document.createElement("script");e.textContent=t.content,e.dataset.datalyrScript=t.id,e.setAttribute("data-nonce",this.generateNonce()),document.head.appendChild(e)}loadExternalScript(t){if(!this.isValidScriptUrl(t.content))return void this.log("Blocked invalid script URL:",t.content);const e=document.createElement("script");e.src=t.content,e.dataset.datalyrScript=t.id,t.settings?(!1!==t.settings.async&&(e.async=!0),t.settings.defer&&(e.defer=!0),t.settings.integrity&&(e.integrity=t.settings.integrity),t.settings.crossorigin&&(e.crossOrigin=t.settings.crossorigin)):e.async=!0,document.head.appendChild(e)}loadPixel(t){const e=new Image;e.src=t.content,e.style.display="none",e.dataset.datalyrPixel=t.id,document.body.appendChild(e)}initializePixels(){var t,e,i;this.pixels&&((null===(t=this.pixels.meta)||void 0===t?void 0:t.enabled)&&this.pixels.meta.pixel_id&&this.initializeMetaPixel(this.pixels.meta),(null===(e=this.pixels.google)||void 0===e?void 0:e.enabled)&&this.pixels.google.tag_id&&this.initializeGoogleTag(this.pixels.google),(null===(i=this.pixels.tiktok)||void 0===i?void 0:i.enabled)&&this.pixels.tiktok.pixel_id&&this.initializeTikTokPixel(this.pixels.tiktok))}initializeMetaPixel(t){try{e=window,i=document,s="script",e.fbq||(n=e.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)},e._fbq||(e._fbq=n),n.push=n,n.loaded=!0,n.version="2.0",n.queue=[],(o=i.createElement(s)).async=!0,o.src="https://connect.facebook.net/en_US/fbevents.js",(r=i.getElementsByTagName(s)[0]).parentNode.insertBefore(o,r)),window.fbq("init",t.pixel_id),window.fbq("track","PageView"),this.log("Meta Pixel initialized:",t.pixel_id)}catch(t){this.log("Error initializing Meta Pixel:",t)}var e,i,s,n,o,r}initializeGoogleTag(t){try{const e=document.createElement("script");function i(...t){window.dataLayer.push(t)}e.async=!0,e.src=`https://www.googletagmanager.com/gtag/js?id=${t.tag_id}`,document.head.appendChild(e),window.dataLayer=window.dataLayer||[],window.gtag=i,i("js",new Date),i("config",t.tag_id,{allow_enhanced_conversions:!1!==t.enhanced_conversions}),this.log("Google Tag initialized:",t.tag_id)}catch(s){this.log("Error initializing Google Tag:",s)}}initializeTikTokPixel(t){try{!function(t,e,i){t.TiktokAnalyticsObject=i;var s=t[i]=t[i]||[];s.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie"],s.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var n=0;n<s.methods.length;n++)s.setAndDefer(s,s.methods[n]);s.instance=function(t){for(var e=s._i[t]||[],i=0;i<s.methods.length;i++)s.setAndDefer(e,s.methods[i]);return e},s.load=function(t,e){var n;s._i=s._i||{},s._i[t]=[],s._o=s._o||{},s._o[t]=e||{};var o=document.createElement("script");o.type="text/javascript",o.async=!0,o.src="https://analytics.tiktok.com/i18n/pixel/events.js?sdkid="+t+"&lib="+i;var r=document.getElementsByTagName("script")[0];null===(n=r.parentNode)||void 0===n||n.insertBefore(o,r)}}(window,document,"ttq"),window.ttq.load(t.pixel_id),window.ttq.page(),this.log("TikTok Pixel initialized:",t.pixel_id)}catch(t){this.log("Error initializing TikTok Pixel:",t)}}trackToPixels(t,e={}){var i,s,n,o,r,a;if((null===(s=null===(i=this.pixels)||void 0===i?void 0:i.meta)||void 0===s?void 0:s.enabled)&&window.fbq)try{window.fbq("track",t,e)}catch(t){this.log("Error tracking Meta Pixel event:",t)}if((null===(o=null===(n=this.pixels)||void 0===n?void 0:n.google)||void 0===o?void 0:o.enabled)&&window.gtag)try{window.gtag("event",t,e)}catch(t){this.log("Error tracking Google Tag event:",t)}if((null===(a=null===(r=this.pixels)||void 0===r?void 0:r.tiktok)||void 0===a?void 0:a.enabled)&&window.ttq)try{const i={Purchase:"CompletePayment",AddToCart:"AddToCart",InitiateCheckout:"InitiateCheckout",ViewContent:"ViewContent",Search:"Search",Lead:"SubmitForm"}[t]||t;window.ttq.track(i,e)}catch(t){this.log("Error tracking TikTok Pixel event:",t)}}triggerCustomScript(t){const e=this.scripts.find(e=>e.id===t&&"custom"===e.trigger);e&&this.shouldLoadScript(e)&&this.loadScript(e)}getLoadedScripts(){return Array.from(this.loadedScripts)}extractAppEndpoint(t){if(!t)return"https://app.datalyr.com";if(t.includes("app.datalyr.com"))return t;if(t.includes("ingest.datalyr.com"))return"https://app.datalyr.com";if(t.includes("localhost")||t.includes("127.0.0.1"))return t.replace(":3001",":3000").replace("/ingest","");try{const e=new URL(t);return`${e.protocol}//${e.hostname}${e.port?":"+e.port:""}`}catch(t){return"https://app.datalyr.com"}}containsMaliciousPatterns(t){return[/<script[^>]*>/gi,/document\.cookie/gi,/eval\s*\(/gi,/Function\s*\(/gi,/innerHTML\s*=/gi,/document\.write/gi].some(e=>e.test(t))}isValidScriptUrl(t){try{const e=new URL(t);return!("https:"!==e.protocol&&!e.hostname.includes("localhost"))&&!["data:","javascript:","file:"].includes(e.protocol)}catch(t){return!1}}generateNonce(){const t=new Uint8Array(16);return crypto.getRandomValues(t),btoa(String.fromCharCode(...t))}log(...t){this.debug&&console.log("[Datalyr Container]",...t)}}const v=new class{constructor(){this.superProperties={},this.userProperties={},this.optedOut=!1,this.initialized=!1,this.errors=[],this.MAX_ERRORS=50,this.heavyFingerprintCollected=!1,this.optedOut="true"===n.get("__dl_opt_out")}init(t){if(this.initialized)return void console.warn("[Datalyr] SDK already initialized");if(!t.workspaceId)throw new Error("[Datalyr] workspaceId is required");this.config=Object.assign({endpoint:"https://ingest.datalyr.com",debug:!1,batchSize:10,flushInterval:5e3,flushAt:10,criticalEvents:void 0,highPriorityEvents:void 0,sessionTimeout:18e5,trackSessions:!0,attributionWindow:2592e6,trackedParams:[],respectDoNotTrack:!1,respectGlobalPrivacyControl:!0,privacyMode:"standard",cookieDomain:"auto",cookieExpires:365,secureCookie:"auto",sameSite:"Lax",cookiePrefix:"__dl_",enablePerformanceTracking:!0,enableFingerprinting:!0,maxRetries:5,retryDelay:1e3,maxOfflineQueueSize:100,trackSPA:!0,trackPageViews:!0,fallbackEndpoints:[],plugins:[]},t),this.cookies=new i({domain:this.config.cookieDomain,maxAge:this.config.cookieExpires,sameSite:this.config.sameSite,secure:this.config.secureCookie}),this.identity=new u,this.session=new h(this.config.sessionTimeout),this.attribution=new g({attributionWindow:this.config.attributionWindow,trackedParams:this.config.trackedParams}),this.queue=new m(this.config),this.fingerprint=new y({privacyMode:this.config.privacyMode,enableFingerprinting:this.config.enableFingerprinting});const e=this.session.getSessionId();if(this.identity.setSessionId(e),this.userProperties=s.get("dl_user_traits",{}),this.config.trackSPA&&this.setupSPATracking(),!1!==this.config.enableContainer&&(this.container=new _({workspaceId:this.config.workspaceId,endpoint:this.config.endpoint,debug:this.config.debug}),this.container.init().catch(t=>{this.log("Container initialization failed:",t)})),this.config.trackPageViews&&this.page(),this.setupUnloadHandler(),this.config.plugins)for(const t of this.config.plugins)try{t.initialize(this),this.log(`Plugin initialized: ${t.name}`)}catch(e){this.trackError(e,{plugin:t.name})}this.initialized=!0,this.log("SDK initialized")}track(t,e={}){if(this.shouldTrack())try{this.session.updateActivity(t);const i=this.createEventPayload(t,e);if(this.queue.enqueue(i),this.container&&this.container.trackToPixels(t,e),this.config.plugins)for(const i of this.config.plugins)if(i.track)try{i.track(t,e)}catch(e){this.trackError(e,{plugin:i.name,event:t})}this.log("Event tracked:",t)}catch(e){this.trackError(e,{event:t})}}identify(t,e={}){if(this.shouldTrack())if(t)try{const i=this.identity.identify(t,e);if(this.userProperties=Object.assign(Object.assign({},this.userProperties),e),s.set("dl_user_traits",this.userProperties),this.track("$identify",Object.assign(Object.assign({},i),{traits:e})),this.config.plugins)for(const i of this.config.plugins)if(i.identify)try{i.identify(t,e)}catch(t){this.trackError(t,{plugin:i.name})}this.log("User identified:",t)}catch(e){this.trackError(e,{userId:t})}else console.warn("[Datalyr] identify() called without userId")}page(t={}){if(!this.shouldTrack())return;const e=Object.assign({title:document.title,url:window.location.href,path:window.location.pathname,search:window.location.search,referrer:document.referrer},t),i=function(){const t=document.referrer;if(!t)return{};try{const e=new URL(t);return{referrer:t,referrer_host:e.hostname,referrer_path:e.pathname,referrer_search:e.search,referrer_source:d(e.hostname)}}catch(e){return{referrer:t}}}();if(Object.assign(e,i),this.config.enablePerformanceTracking){const t=this.getPerformanceMetrics();t&&(e.performance=t)}if(this.track("pageview",e),this.config.plugins)for(const t of this.config.plugins)if(t.page)try{t.page(e)}catch(e){this.trackError(e,{plugin:t.name})}}screen(t,e={}){this.track("screen_view",Object.assign({screen_name:t},e))}group(t,e={}){this.track("$group",{group_id:t,traits:e})}alias(t,e){const i=this.identity.alias(t,e);this.track("$alias",i)}reset(){this.identity.reset(),this.userProperties={},s.remove("dl_user_traits"),this.session.createNewSession(),this.log("User reset")}getAnonymousId(){return this.identity.getAnonymousId()}getUserId(){return this.identity.getUserId()}getDistinctId(){return this.identity.getDistinctId()}getSessionId(){return this.session.getSessionId()}startNewSession(){const t=this.session.createNewSession();return this.identity.setSessionId(t),t}getSessionData(){return this.session.getSessionData()}getAttribution(){return this.attribution.captureAttribution()}getJourney(){return this.attribution.getJourney()}setAttribution(t){const e=this.attribution.captureAttribution(),i=Object.assign(Object.assign({},e),t);this.session.storeAttribution(i)}optOut(){this.optedOut=!0,n.set("__dl_opt_out","true",this.config.cookieExpires),this.queue.clear(),this.log("User opted out")}optIn(){this.optedOut=!1,n.set("__dl_opt_out","false",this.config.cookieExpires),this.log("User opted in")}isOptedOut(){return this.optedOut}setConsent(t){s.set("dl_consent",t),this.log("Consent updated:",t)}flush(){return t(this,void 0,void 0,function*(){yield this.queue.flush()})}setSuperProperties(t){this.superProperties=Object.assign(Object.assign({},this.superProperties),t),this.log("Super properties set:",t)}unsetSuperProperty(t){delete this.superProperties[t],this.log("Super property unset:",t)}getSuperProperties(){return Object.assign({},this.superProperties)}createEventPayload(t,e){const i=a(e),s=c({},this.superProperties,i),n=this.attribution.getAttributionData();Object.assign(s,n);const r=this.session.getMetrics();if(Object.assign(s,r),this.config.enableFingerprinting){const t=this.fingerprint.collect();Object.assign(s,{fingerprint:t,device_fingerprint:t})}Object.assign(s,{url:window.location.href,path:window.location.pathname,referrer:document.referrer,title:document.title,screen_width:screen.width,screen_height:screen.height,viewport_width:window.innerWidth,viewport_height:window.innerHeight});const l=this.identity.getIdentityFields(),d=o(),u=l.distinct_id,h=l.anonymous_id,g=l.visitor_id||h,p=l.session_id;return{workspaceId:this.config.workspaceId,workspace_id:this.config.workspaceId,eventId:d,event_id:d,eventName:t,event_name:t,eventData:s,event_data:s,source:"web",timestamp:(new Date).toISOString(),distinct_id:u,anonymous_id:h,visitor_id:g,visitorId:g,user_id:l.user_id,canonical_id:l.canonical_id,sessionId:p,session_id:p,resolution_method:"browser_sdk",resolution_confidence:1,sdk_version:"1.0.0",sdk_name:"datalyr-web-sdk"}}shouldTrack(){return!this.optedOut&&((!this.config.respectDoNotTrack||"1"!==navigator.doNotTrack&&"1"!==window.doNotTrack&&"yes"!==navigator.doNotTrack)&&(!this.config.respectGlobalPrivacyControl||!0!==navigator.globalPrivacyControl&&!0!==window.globalPrivacyControl))}setupSPATracking(){const t=history.pushState,e=history.replaceState,i=this;history.pushState=function(...e){t.apply(history,e),setTimeout(()=>{i.page()},0)},history.replaceState=function(...t){e.apply(history,t),setTimeout(()=>{i.page()},0)},window.addEventListener("popstate",()=>{setTimeout(()=>{this.page()},0)}),window.addEventListener("hashchange",()=>{this.page()})}setupUnloadHandler(){const t=()=>{this.queue.forceFlush()};window.addEventListener("beforeunload",t),window.addEventListener("pagehide",t),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&t()})}getPerformanceMetrics(){if(!this.config.enablePerformanceTracking)return null;const t={};try{if(performance&&"function"==typeof performance.getEntriesByType){const e=performance.getEntriesByType("navigation"),i=e&&e[0];i&&(t.pageLoadTime=Math.round(i.loadEventEnd),t.domReadyTime=Math.round(i.domContentLoadedEventEnd),t.firstByteTime=Math.round(i.responseStart),t.dnsTime=Math.round(i.domainLookupEnd-i.domainLookupStart),t.tcpTime=Math.round(i.connectEnd-i.connectStart),t.requestTime=Math.round(i.responseEnd-i.requestStart),t.timeOnPage=Math.round(performance.now()))}}catch(t){this.trackError(t,{context:"performance_metrics"})}return Object.keys(t).length>0?t:null}trackError(t,e){const i={message:t.message||String(t),stack:t.stack,context:e,timestamp:(new Date).toISOString(),url:window.location.href};this.errors.push(i),this.errors.length>this.MAX_ERRORS&&(this.errors=this.errors.slice(-this.MAX_ERRORS)),this.config.debug&&console.error("[Datalyr Error]",i)}getErrors(){return[...this.errors]}getNetworkStatus(){return this.queue.getNetworkStatus()}loadScript(t){this.container&&this.container.triggerCustomScript(t)}getLoadedScripts(){return this.container?this.container.getLoadedScripts():[]}log(...t){this.config.debug&&console.log("[Datalyr]",...t)}destroy(){this.queue&&this.queue.destroy(),this.session&&this.session.destroy(),this.superProperties={},this.userProperties={},this.errors=[],this.initialized=!1,this.log("SDK destroyed")}};"undefined"!=typeof window&&(window.datalyr=v);export{v as default}; //# sourceMappingURL=datalyr.esm.min.js.map