UNPKG

thrivestack-analytics

Version:

ThriveStack Analytics - Privacy-first web analytics for Node.js and browsers

1 lines 20.9 kB
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ThriveStack=t():e.ThriveStack=t()}(this,()=>(()=>{"use strict";var e={417:function(e,t){var i=this&&this.__awaiter||function(e,t,i,o){return new(i||(i=Promise))(function(n,s){function r(e){try{c(o.next(e))}catch(e){s(e)}}function a(e){try{c(o.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?n(e.value):(t=e.value,t instanceof i?t:new i(function(e){e(t)})).then(r,a)}c((o=o.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.ThriveStack=void 0;t.ThriveStack=class{constructor(e){this.ipAddress=null,this.locationInfo=null,this.eventQueue=[],this.queueTimer=null,this.interactionHistory=[],this.maxHistoryLength=20,this.userId="",this.groupId="",this.deviceId=null,this.deviceIdReady=!1,this.sessionUpdateTimer=null,this.debugMode=!1,"string"==typeof e&&(e={apiKey:e}),this.apiKey=e.apiKey,this.apiEndpoint=e.apiEndpoint||"https://api.app.thrivestack.ai/api",this.respectDoNotTrack=!1!==e.respectDoNotTrack,this.trackClicks=!0===e.trackClicks,this.trackForms=!0===e.trackForms,this.enableConsent=!0===e.enableConsent,this.source=e.source||"",this.geoIpServiceUrl=e.geoIpServiceUrl||"https://ipinfo.io/json",this.batchSize=e.batchSize||10,this.batchInterval=e.batchInterval||2e3,this.sessionTimeout=e.sessionTimeout||18e5,this.debounceDelay=e.debounceDelay||2e3,this.consentCategories={functional:!0,analytics:!0===e.defaultConsent,marketing:!0===e.defaultConsent},this.initializeDeviceId(),this.fetchIpAndLocationInfo(),this.setupSessionTracking(),this.shouldTrack()&&(this.autoCapturePageVisit(),this.trackClicks&&this.autoCaptureClickEvents(),this.trackForms&&this.autoCaptureFormEvents())}initializeDeviceId(){return i(this,void 0,void 0,function*(){try{const e=this.getDeviceIdFromCookie();if(e)return this.deviceId=e,this.deviceIdReady=!0,console.debug("Using existing device ID from cookie:",this.deviceId),void this.processQueueIfReady();this.deviceId=this.generateRandomDeviceId(),this.deviceIdReady=!0,this.setDeviceIdCookie(this.deviceId),console.debug("Generated device ID:",this.deviceId),this.processQueueIfReady()}catch(e){console.warn("Failed to initialize device ID:",e),this.deviceId=this.generateRandomDeviceId(),this.deviceIdReady=!0,this.setDeviceIdCookie(this.deviceId),this.processQueueIfReady()}})}generateRandomDeviceId(){return"device_"+Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}setDeviceIdCookie(e){if(!e)return;const t=new Date;t.setTime(t.getTime()+63072e6);const i=`thrivestack_device_id=${e};expires=${t.toUTCString()};path=/;SameSite=Lax`;try{document.cookie=i}catch(e){console.warn("Could not store device ID in cookie:",e)}}getDeviceIdFromCookie(){const e="thrivestack_device_id",t=document.cookie.split(";");for(let i=0;i<t.length;i++){const o=t[i].trim();if(0===o.indexOf(e+"="))return o.substring(22)}return null}fetchIpAndLocationInfo(){return i(this,void 0,void 0,function*(){try{const e=this.getLocationInfoFromCookie();if(e)return this.ipAddress=e.ip||null,this.locationInfo={city:e.city||null,region:e.region||null,country:e.country||null,postal:e.postal||null,loc:e.loc||null,timezone:e.timezone||null},void console.debug("Using cached IP and location info from cookie");console.debug("Fetching IP and location info from API...");const t=yield fetch(this.geoIpServiceUrl);if(!t.ok)throw new Error(`HTTP error ${t.status}`);const i=yield t.json();this.ipAddress=i.ip||null,this.locationInfo={city:i.city||null,region:i.region||null,country:i.country||null,postal:i.postal||null,loc:i.loc||null,timezone:i.timezone||null},this.setLocationInfoCookie(i),console.debug("IP and location info fetched successfully")}catch(e){console.warn("Failed to fetch IP and location info:",e),this.ipAddress=null,this.locationInfo=null}})}setLocationInfoCookie(e){if(!e)return;try{const t=btoa(JSON.stringify(e)),i=new Date;i.setTime(i.getTime()+864e5);const o=`thrivestack_location_info=${t};expires=${i.toUTCString()};path=/;SameSite=Lax`;document.cookie=o,console.debug("Location info cached in cookie")}catch(e){console.warn("Could not store location info in cookie:",e)}}getLocationInfoFromCookie(){const e="thrivestack_location_info";try{const t=document.cookie.split(";");for(let i=0;i<t.length;i++){const o=t[i].trim();if(0===o.indexOf(e+"=")){const e=o.substring(26),t=atob(e);return JSON.parse(t)}}}catch(e){console.warn("Could not read location info from cookie:",e)}return null}init(){return i(this,arguments,void 0,function*(e="",t=""){try{e&&this.setUserId(e),t&&(this.source=t),console.debug("ThriveStack initialized successfully")}catch(e){throw console.error("Failed to initialize ThriveStack:",e),e}})}shouldTrack(){return!this.respectDoNotTrack||"1"!==navigator.doNotTrack&&"yes"!==navigator.doNotTrack&&"1"!==window.doNotTrack||(console.warn("User has enabled Do Not Track. Tracking is disabled."),!1)}isTrackingAllowed(e){return!!this.shouldTrack()&&(!this.enableConsent||!0===this.consentCategories[e])}setConsent(e,t){this.consentCategories.hasOwnProperty(e)&&(this.consentCategories[e]=t)}setUserId(e){this.userId=e,this.setUserIdCookie(e)}setGroupId(e){this.groupId=e,this.setGroupIdCookie(e)}setSource(e){this.source=e}setUserIdCookie(e){if(!e)return;const t=new Date;t.setTime(t.getTime()+31536e6);const i=`thrivestack_user_id=${encodeURIComponent(e)};expires=${t.toUTCString()};path=/;SameSite=Lax`;try{document.cookie=i}catch(e){console.warn("Could not store user ID in cookie:",e)}}getUserIdFromCookie(){const e="thrivestack_user_id",t=document.cookie.split(";");for(let i=0;i<t.length;i++){const o=t[i].trim();if(0===o.indexOf(e+"=")){const e=o.substring(20);return decodeURIComponent(e)}}return null}setGroupIdCookie(e){if(!e)return;const t=new Date;t.setTime(t.getTime()+31536e6);const i=`thrivestack_group_id=${encodeURIComponent(e)};expires=${t.toUTCString()};path=/;SameSite=Lax`;try{document.cookie=i}catch(e){console.warn("Could not store group ID in cookie:",e)}}getGroupIdFromCookie(){const e="thrivestack_group_id",t=document.cookie.split(";");for(let i=0;i<t.length;i++){const o=t[i].trim();if(0===o.indexOf(e+"=")){const e=o.substring(21);return decodeURIComponent(e)}}return null}queueEvent(e){Array.isArray(e)||(e=[e]),this.eventQueue.push(...e),this.deviceIdReady?this.processQueueIfReady():console.debug("Device ID not ready, keeping events in queue")}processQueueIfReady(){this.deviceIdReady&&0!==this.eventQueue.length&&(this.eventQueue.length>=this.batchSize?this.processQueue():this.queueTimer||(this.queueTimer=window.setTimeout(()=>this.processQueue(),this.batchInterval)))}processQueue(){return i(this,void 0,void 0,function*(){if(0===this.eventQueue.length||!this.deviceIdReady)return;const e=[...this.eventQueue],t=e.map(e=>Object.assign(Object.assign({},e),{context:Object.assign(Object.assign({},e.context),{device_id:this.deviceId})}));this.eventQueue=[],this.queueTimer&&(clearTimeout(this.queueTimer),this.queueTimer=null);try{yield this.track(t)}catch(t){console.error("Failed to send batch events:",t),this.eventQueue.unshift(...e)}})}track(e){return i(this,void 0,void 0,function*(){if(!this.apiKey)throw new Error("Initialize the ThriveStack instance before sending telemetry data.");const t=e.map(e=>this.cleanPIIFromEventData(e));let i=3;for(;i>0;)try{const e=yield fetch(`${this.apiEndpoint}/track`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":`${this.apiKey}`},body:JSON.stringify(t)});if(!e.ok)throw new Error(`HTTP error ${e.status}: ${yield e.text()}`);return yield e.json()}catch(e){if(i--,0===i)throw console.error("Failed to send telemetry after multiple attempts:",e),e;yield new Promise(e=>setTimeout(e,1e3*(3-i)))}})}identify(e){return i(this,void 0,void 0,function*(){if(!this.apiKey)throw new Error("Initialize the ThriveStack instance before sending telemetry data.");try{let t="";if(Array.isArray(e)&&e.length>0){t=e[e.length-1].user_id||""}else t=e.user_id||"";t&&this.setUserId(t);const i=yield fetch(`${this.apiEndpoint}/identify`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":`${this.apiKey}`},body:JSON.stringify(e)});if(!i.ok)throw new Error(`HTTP error ${i.status}: ${yield i.text()}`);return yield i.json()}catch(e){throw console.error("Failed to send identification data:",e),e}})}group(e){return i(this,void 0,void 0,function*(){if(!this.apiKey)throw new Error("Initialize the ThriveStack instance before sending telemetry data.");try{let t="";if(Array.isArray(e)&&e.length>0){t=e[e.length-1].group_id||""}else t=e.group_id||"";t&&this.setGroupId(t);const i=yield fetch(`${this.apiEndpoint}/group`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":`${this.apiKey}`},body:JSON.stringify(e)});if(!i.ok)throw new Error(`HTTP error ${i.status}: ${yield i.text()}`);return yield i.json()}catch(e){throw console.error("Failed to send group data:",e),e}})}getDeviceId(){return this.deviceIdReady&&this.deviceId?this.deviceId:null}getSessionId(){const e="thrivestack_session";try{const t=document.cookie.split(";");let i=null;for(let o=0;o<t.length;o++){const n=t[o].trim();if(0===n.indexOf(e+"=")){i=n.substring(20);break}}if(!i)return this.createNewSession();try{const e=JSON.parse(atob(i));if(e.sessionId&&e.lastActivity){const t=new Date(e.lastActivity),i=new Date;return i.getTime()-t.getTime()<this.sessionTimeout?e.sessionId:(console.debug("Session expired, creating new session"),this.createNewSession())}return this.createNewSession()}catch(e){return console.debug("Migrating old session format to new format"),this.migrateOldSession(i)}}catch(e){return console.warn("Error getting session ID:",e),this.createNewSession()}}createNewSession(){const e="session_"+Math.random().toString(36).substring(2,15),t=(new Date).toISOString(),i={sessionId:e,startTime:t,lastActivity:t};return this.setSessionCookie(i),e}migrateOldSession(e){const t=(new Date).toISOString(),i={sessionId:e,startTime:t,lastActivity:t};return this.setSessionCookie(i),e}setSessionCookie(e){try{const t=`thrivestack_session=${btoa(JSON.stringify(e))};path=/;SameSite=Lax`;document.cookie=t}catch(e){console.warn("Could not store session in cookie:",e)}}updateSessionActivity(){this.sessionUpdateTimer&&clearTimeout(this.sessionUpdateTimer),this.sessionUpdateTimer=window.setTimeout(()=>{this.updateSessionActivityImmediate()},this.debounceDelay)}updateSessionActivityImmediate(){const e="thrivestack_session";try{const t=document.cookie.split(";");let i=null;for(let o=0;o<t.length;o++){const n=t[o].trim();if(0===n.indexOf(e+"=")){i=n.substring(20);break}}if(i)try{const e=JSON.parse(atob(i));e.lastActivity=(new Date).toISOString(),this.setSessionCookie(e)}catch(e){this.createNewSession()}else this.createNewSession()}catch(e){console.warn("Could not update session activity:",e)}}setupSessionTracking(){}capturePageVisit(){return i(this,void 0,void 0,function*(){var e,t,i,o,n,s;if(!this.isTrackingAllowed("functional"))return;const r=this.getDeviceId();r||console.debug("Device ID not ready, page visit will be queued");const a=this.isTrackingAllowed("marketing")?this.getUtmParameters():{},c=this.getSessionId();this.updateSessionActivity();const l=this.userId||this.getUserIdFromCookie()||"",d=this.groupId||this.getGroupIdFromCookie()||"",u=[{event_name:"page_visit",properties:Object.assign({page_title:document.title,page_url:window.location.href,page_path:window.location.pathname,page_referrer:document.referrer||null,language:navigator.language||null,ip_address:this.ipAddress,city:(null===(e=this.locationInfo)||void 0===e?void 0:e.city)||null,region:(null===(t=this.locationInfo)||void 0===t?void 0:t.region)||null,country:(null===(i=this.locationInfo)||void 0===i?void 0:i.country)||null,postal:(null===(o=this.locationInfo)||void 0===o?void 0:o.postal)||null,loc:(null===(n=this.locationInfo)||void 0===n?void 0:n.loc)||null,timezone:(null===(s=this.locationInfo)||void 0===s?void 0:s.timezone)||null},a),user_id:l,context:{group_id:d,device_id:r,session_id:c,source:this.source},timestamp:(new Date).toISOString()}];this.queueEvent(u),this.addToInteractionHistory("page_visit",u[0].properties)})}captureEvent(e){return i(this,arguments,void 0,function*(e,t={}){var i,o,n,s,r,a;if(!this.isTrackingAllowed("analytics"))return;const c=this.getDeviceId();c||console.debug("Device ID not ready, event will be queued");const l=this.getSessionId();this.updateSessionActivity();const d=this.userId||this.getUserIdFromCookie()||"",u=this.groupId||this.getGroupIdFromCookie()||"",h=[{event_name:e,properties:Object.assign(Object.assign({},t),{page_title:document.title,page_url:window.location.href,page_path:window.location.pathname,page_referrer:document.referrer||null,language:navigator.language||null,ip_address:this.ipAddress,city:(null===(i=this.locationInfo)||void 0===i?void 0:i.city)||null,region:(null===(o=this.locationInfo)||void 0===o?void 0:o.region)||null,country:(null===(n=this.locationInfo)||void 0===n?void 0:n.country)||null,postal:(null===(s=this.locationInfo)||void 0===s?void 0:s.postal)||null,loc:(null===(r=this.locationInfo)||void 0===r?void 0:r.loc)||null,timezone:(null===(a=this.locationInfo)||void 0===a?void 0:a.timezone)||null}),user_id:d,context:{group_id:u,device_id:c,session_id:l,source:this.source},timestamp:(new Date).toISOString()}];this.queueEvent(h),this.addToInteractionHistory(e,h[0].properties)})}addToInteractionHistory(e,t){const i={type:e,details:t,timestamp:(new Date).toISOString(),sequence:this.interactionHistory.length+1};this.interactionHistory.push(i),this.interactionHistory.length>this.maxHistoryLength&&this.interactionHistory.shift()}cleanPIIFromEventData(e){return JSON.parse(JSON.stringify(e))}setUser(e,t){return i(this,arguments,void 0,function*(e,t,i={}){if(!e)return console.warn("setUser: userId is required"),null;this.setUserId(e);try{const o=[{user_id:e,traits:Object.assign({user_email:t,user_name:t},i),timestamp:(new Date).toISOString()}];console.debug("Making identify API call for user:",e);const n=yield this.identify(o);return console.debug("Identify API call successful"),n}catch(e){throw console.error("Failed to make identify API call:",e),e}})}setGroup(e,t,o){return i(this,arguments,void 0,function*(e,t,i,o={}){if(!e)return console.warn("setGroup: groupId is required"),null;this.setGroupId(e);try{const n=[{group_id:e,user_id:this.userId,traits:Object.assign({group_type:"Account",account_domain:t,account_name:i},o),timestamp:(new Date).toISOString()}];console.debug("Making group API call for group:",e);const s=yield this.group(n);return console.debug("Group API call successful"),s}catch(e){throw console.error("Failed to make group API call:",e),e}})}enableDebugMode(){this.debugMode=!0;const e=this.track.bind(this);this.track=function(t){return i(this,void 0,void 0,function*(){return console.group("ThriveStack Debug: Sending Events"),console.log("Events:",JSON.parse(JSON.stringify(t))),console.groupEnd(),e(t)})},console.log("ThriveStack debug mode enabled")}getInteractionHistory(){return[...this.interactionHistory]}getLocationInfo(){return this.locationInfo}getIpAddress(){return this.ipAddress}getUtmParameters(){const e=new URLSearchParams(window.location.search);return{utm_campaign:e.get("utm_campaign")||null,utm_medium:e.get("utm_medium")||null,utm_source:e.get("utm_source")||null,utm_term:e.get("utm_term")||null,utm_content:e.get("utm_content")||null}}autoCapturePageVisit(){window.addEventListener("load",()=>this.capturePageVisit()),window.addEventListener("popstate",()=>this.capturePageVisit());const e=history.pushState;history.pushState=(...t)=>{e.apply(history,t),this.capturePageVisit()};const t=history.replaceState;history.replaceState=(...e)=>{t.apply(history,e),this.capturePageVisit()}}autoCaptureClickEvents(){document.addEventListener("click",e=>this.captureClickEvent(e))}captureClickEvent(e){var t;if(!this.isTrackingAllowed("analytics"))return;const i=Date.now();if(this.lastClickTime&&i-this.lastClickTime<300)return;this.lastClickTime=i;const o=e.target,n=o.getBoundingClientRect(),s=this.getDeviceId();s||console.debug("Device ID not ready, click event will be queued");const r=this.isTrackingAllowed("marketing")?this.getUtmParameters():{},a=this.getSessionId();this.updateSessionActivity();const c=this.userId||this.getUserIdFromCookie()||"",l=this.groupId||this.getGroupIdFromCookie()||"",d=[{event_name:"element_click",properties:Object.assign({page_title:document.title,page_url:window.location.href,element_text:(null===(t=o.textContent)||void 0===t?void 0:t.trim())||null,element_tag:o.tagName||null,element_id:o.id||null,element_href:o.getAttribute("href")||null,element_aria_label:o.getAttribute("aria-label")||null,element_class:o.className||null,element_hierarchy:this.getElementHierarchy(o),element_position_left:n.left||null,element_position_top:n.top||null,element_selector:this.getElementSelector(o),viewport_height:window.innerHeight,viewport_width:window.innerWidth,referrer:document.referrer||null},r),user_id:c,context:{group_id:l,device_id:s,session_id:a,source:this.source},timestamp:(new Date).toISOString()}];this.queueEvent(d),this.addToInteractionHistory("element_click",d[0].properties)}getElementHierarchy(e){if(this._hierarchyCache||(this._hierarchyCache=new WeakMap),this._hierarchyCache.has(e))return this._hierarchyCache.get(e);let t=[],i=e;for(;i&&i.parentElement;){let e=i.tagName,o=i.id?`#${i.id}`:"",n=i.className&&"string"==typeof i.className?`.${i.className.trim().split(/\s+/).join(".")}`:"";t.unshift(`${e}${o}${n}`),i=i.parentElement}const o=t.join(" > ");return this._hierarchyCache.set(e,o),o}getElementSelector(e){let t=e.id?`#${e.id}`:"",i=e.className&&"string"==typeof e.className?`.${e.className.trim().split(/\s+/).join(".")}`:"";return`${e.tagName}${t}${i}`}autoCaptureFormEvents(){document.addEventListener("submit",e=>{this.captureFormEvent(e,"submit")}),document.addEventListener("input",e=>{if(e.target.form){const t=e.target.form;t._trackingData||(t._trackingData={startTime:Date.now(),filledFields:new Set});const i=e.target;""!==i.value.trim()?t._trackingData.filledFields.add(i.name||i.id):t._trackingData.filledFields.delete(i.name||i.id)}}),document.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&document.querySelectorAll("form").forEach(e=>{if(e._trackingData&&e._trackingData.filledFields.size>0){const t={target:e};this.captureFormEvent(t,"abandoned")}})})}captureFormEvent(e,t){if(!this.isTrackingAllowed("analytics"))return;const i=e.target,o=this.getDeviceId();o||console.debug("Device ID not ready, form event will be queued");const n=this.getSessionId();this.updateSessionActivity();const s=this.userId||this.getUserIdFromCookie()||"",r=this.groupId||this.getGroupIdFromCookie()||"";let a=i._trackingData||{filledFields:new Set};const c=Array.from(i.elements).filter(e=>!["submit","button","reset"].includes(e.type)).length,l=Math.round(a.filledFields.size/Math.max(c,1)*100),d=[{event_name:`form_${t}`,properties:{page_title:document.title,page_url:window.location.href,form_id:i.id||null,form_name:i.name||null,form_action:i.action||null,form_fields:c,form_completion:l,interaction_time:a.startTime?Date.now()-a.startTime:null},user_id:s,context:{group_id:r,device_id:o,session_id:n,source:this.source},timestamp:(new Date).toISOString()}];this.queueEvent(d),this.addToInteractionHistory(`form_${t}`,d[0].properties)}}}},t={};function i(o){var n=t[o];if(void 0!==n)return n.exports;var s=t[o]={exports:{}};return e[o].call(s.exports,s,s.exports,i),s.exports}var o={};return(()=>{var e=o;Object.defineProperty(e,"__esModule",{value:!0}),e.ThriveStack=void 0;var t=i(417);Object.defineProperty(e,"ThriveStack",{enumerable:!0,get:function(){return t.ThriveStack}}),"undefined"!=typeof window&&function(){let e=document.currentScript||Array.from(document.getElementsByTagName("script")).pop(),t=(null==e?void 0:e.getAttribute("data-api-key"))||(null==e?void 0:e.getAttribute("api-key")),o=(null==e?void 0:e.getAttribute("data-source"))||(null==e?void 0:e.getAttribute("source"));if(t&&o){const{ThriveStack:n}=i(417);let s=new n({apiKey:t,trackClicks:"true"===(null==e?void 0:e.getAttribute("data-track-clicks"))||"true"===(null==e?void 0:e.getAttribute("track-clicks")),trackForms:"true"===(null==e?void 0:e.getAttribute("data-track-forms"))||"true"===(null==e?void 0:e.getAttribute("track-forms")),respectDoNotTrack:"false"!==(null==e?void 0:e.getAttribute("data-respect-dnt"))&&"false"!==(null==e?void 0:e.getAttribute("respect-dnt")),source:o});s.init().catch(e=>{console.error("Failed to initialize ThriveStack:",e)}),window.thriveStack=s}else t||console.error("Missing required API key for ThriveStack initialization. Use data-api-key or api-key attribute."),o||console.error("Missing required source for ThriveStack initialization. Use data-source or source attribute.")}()})(),o})());