@tinytapanalytics/sdk
Version:
Behavioral psychology platform that detects visitor frustration, predicts abandonment, and helps you save at-risk conversions in real-time
1 lines • 4.87 kB
JavaScript
var t={d:function(e,s){for(var a in s)t.o(s,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:s[a]})},o:function(t,e){return Object.prototype.hasOwnProperty.call(t,e)}},e={};t.d(e,{M:function(){return s}});class s{constructor(t,e){this.activeTests=new Map,this.userAssignments=new Map,this.testResults=new Map,this.storageKey="tinytapanalytics_ab_tests",this.config=t,this.sdk=e,this.loadStoredAssignments()}async init(){try{await this.loadActiveTests(),this.processActiveTests(),this.config.debug}catch(t){this.config.debug}}createTest(t){const e=this.generateTestId(),s={...t,id:e,status:"draft"};return this.activeTests.set(e,s),this.config.debug,e}startTest(t){const e=this.activeTests.get(t);return!!e&&(e.status="running",this.processTest(e),this.sdk.track("ab_test_started",{testId:e.id,testName:e.name,variants:e.variants.length}),this.config.debug,!0)}stopTest(t){const e=this.activeTests.get(t);return!!e&&(e.status="completed",this.sdk.track("ab_test_stopped",{testId:e.id,testName:e.name}),this.config.debug,!0)}getVariant(t){const e=this.activeTests.get(t);if(!e||"running"!==e.status)return null;const s=this.userAssignments.get(t);if(s)return s;if(e.targetingRules&&!this.matchesTargeting(e.targetingRules))return null;const a=this.assignUserToVariant(e);return a&&(this.userAssignments.set(t,a),this.storeAssignments(),this.sdk.track("ab_test_assignment",{testId:e.id,testName:e.name,variantId:a,variantName:e.variants.find(t=>t.id===a)?.name}),this.testResults.set(t,{testId:t,variantId:a,userId:this.sdk.userId||"anonymous",sessionId:this.sdk.sessionId,assignedAt:Date.now(),conversions:[]})),a}trackConversion(t,e,s){const a=this.testResults.get(t);a&&(a.conversions.push({goal:e,timestamp:Date.now(),value:s}),this.sdk.track("ab_test_conversion",{testId:t,variantId:a.variantId,goal:e,value:s,assignedAt:a.assignedAt,convertedAt:Date.now(),timeToConvert:Date.now()-a.assignedAt}),this.config.debug)}applyVariant(t,e){const s=this.activeTests.get(t);if(!s)return;const a=s.variants.find(t=>t.id===e);a&&!a.control&&(a.changes.forEach(t=>{this.applyChange(t)}),this.config.debug)}getTestResults(t){return this.testResults.get(t)||null}getActiveTests(){return Array.from(this.activeTests.values()).filter(t=>"running"===t.status)}async loadActiveTests(){try{const t=await fetch(`${this.config.endpoint}/api/v1/ab-tests`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(t.ok){(await t.json()).forEach(t=>{this.activeTests.set(t.id,t)})}}catch(t){this.config.debug}}processActiveTests(){this.activeTests.forEach(t=>{"running"===t.status&&this.processTest(t)})}processTest(t){const e=this.getVariant(t.id);e&&this.applyVariant(t.id,e)}matchesTargeting(t){return t.every(t=>{switch(t.type){case"url":return this.matchesUrlRule(t);case"device":return this.matchesDeviceRule(t);case"traffic":return this.matchesTrafficRule(t);default:return!0}})}matchesUrlRule(t){const e=window.location.href,s=t.value;switch(t.operator){case"equals":return e===s;case"contains":return e.includes(s);case"matches":return new RegExp(s).test(e);default:return!1}}matchesDeviceRule(t){const e=navigator.userAgent.toLowerCase(),s=t.value.toLowerCase();switch(t.operator){case"equals":case"contains":return e.includes(s);case"matches":return new RegExp(s).test(e);default:return!1}}matchesTrafficRule(t){const e=t.value,s=100*Math.random();switch(t.operator){case"less":return s<e;case"greater":return s>e;default:return!1}}assignUserToVariant(t){const e=this.sdk.userId||this.generateAnonymousId(),s=this.hashString(e+t.id)%100/100;let a=0;for(const n of t.variants)if(a+=n.traffic/100,s<=a)return n.id;return null}applyChange(t){switch(t.type){case"css":this.applyCSSChange(t);break;case"html":this.applyHTMLChange(t);break;case"javascript":this.applyJavaScriptChange(t);break;case"redirect":this.applyRedirect(t)}}applyCSSChange(t){if(!t.selector||!t.property)return;document.querySelectorAll(t.selector).forEach(e=>{e.style.setProperty(t.property,t.value)})}applyHTMLChange(t){if(!t.selector)return;document.querySelectorAll(t.selector).forEach(e=>{e.innerHTML=t.value})}applyJavaScriptChange(t){try{new Function(t.value)()}catch(e){this.config.debug}}applyRedirect(t){window.location.href=t.value}generateTestId(){return`test_${Date.now()}_${Math.random().toString(36).substring(2,11)}`}generateAnonymousId(){return`anon_${Date.now()}_${Math.random().toString(36).substring(2,11)}`}hashString(t){let e=0;for(let s=0;s<t.length;s++){e=(e<<5)-e+t.charCodeAt(s),e&=e}return Math.abs(e)}storeAssignments(){try{const t=Object.fromEntries(this.userAssignments);localStorage.setItem(this.storageKey,JSON.stringify(t))}catch(t){this.config.debug}}loadStoredAssignments(){try{const t=localStorage.getItem(this.storageKey);if(t){const e=JSON.parse(t);this.userAssignments=new Map(Object.entries(e))}}catch(t){this.config.debug}}}var a=e.M;export{a as ABTesting};