@behindthescenes/analytics 0.0.12 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- var J=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],g=new Set(J),u=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),v={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function m(S){return g.has(S)}function X(S){let A=S.trim();if(A.length===0)return{eventName:A,canonicalEventName:A,isStandard:!1};let f=A.toLowerCase(),c=v[f];if(c)return{eventName:c,canonicalEventName:c,aliasOf:c,isStandard:!0};return{eventName:A,canonicalEventName:A,isStandard:m(A)}}function Z(S,A){if(A)return A;if(S==="page_view")return"page_view";if(S==="identify")return"identify";if(u.has(S))return"conversion";return"custom"}function C(){return[...J]}var j="bts_analytics_vid",G="bts_analytics_sid",M="bts_analytics_jt",O="bts_analytics_jid",U="bts_analytics_attr",b="bts_site",h="bts_jt",l=300,s="https://api.bts.it.com/v2/website/analytics",d={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},Q=["q","query","search"],p=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],a=["_fbp","_fbc"];function N(){return typeof window>"u"?null:window}function D(){return typeof document>"u"?null:document}function L(){return N()?.localStorage??null}function V(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}function q(S){return S!==null&&typeof S==="object"&&!Array.isArray(S)}function n(S){if(!S)return null;try{let A=JSON.parse(S);if(!q(A))return null;let f=q(A.utm)?Object.fromEntries(Object.entries(A.utm).filter((B)=>typeof B[1]==="string")):{},c=q(A.clickIds)?Object.fromEntries(Object.entries(A.clickIds).filter((B)=>typeof B[1]==="string")):{};return{utm:f,clickIds:c,landingUrl:typeof A.landingUrl==="string"?A.landingUrl:void 0,lastSeenAt:typeof A.lastSeenAt==="string"?A.lastSeenAt:new Date().toISOString(),referrer:typeof A.referrer==="string"?A.referrer:void 0}}catch{return null}}function K(){let S=L();return n(S?.getItem(U)??null)}function o(S){let A=L();if(!A)return;A.setItem(U,JSON.stringify(S))}function F(){let S=N();if(!S)return;return`${S.location.pathname}${S.location.search}`}function H(){return N()?.location.href}function R(){return N()?.location.origin??"https://behindthescenes.com"}function P(){return D()?.referrer||void 0}function z(S){let A=D();if(!A?.cookie)return;let f=`${S}=`,c=A.cookie.split(";").map((E)=>E.trim()).find((E)=>E.startsWith(f));if(!c)return;let B=c.slice(f.length);if(B==="")return;try{return decodeURIComponent(B)}catch{return B}}function r(){let S=z("_ga");if(!S)return;let A=S.split(".");if(A.length>=4&&/^GA\d+$/i.test(A[0]??""))return A.slice(-2).join(".");return _(S)}function t(){let A=D()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),f=A&&"src"in A&&typeof A.src==="string"?A.src:void 0;if(!f)return;try{return _(new URL(f).searchParams.get("id"))}catch{return}}function i(){let S=N(),A=r(),f=t(),c=typeof S?.gtag==="function"||!!f||!!A;if(!c&&!A&&!f)return;return{tagInstalled:c,clientId:A,measurementId:f}}function k(S){if(!S.googleAnalytics||typeof S.googleAnalytics==="boolean")return;return _(S.googleAnalytics.measurementId)}function e(S){if(!S.googleAnalytics)return!1;if(S.googleAnalytics===!0)return!1;return S.googleAnalytics.loadTag!==!1&&!!k(S)}function SS(S){let A=N(),f=D();if(!A||!f)return;A.dataLayer=Array.isArray(A.dataLayer)?A.dataLayer:[],A.gtag??=(...B)=>{A.dataLayer?.push(B)};let c=`script[src*="googletagmanager.com/gtag/js?id=${S}"]`;if(!f.querySelector?.(c)){let B=f.createElement("script");B.async=!0,B.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(S)}`,B.setAttribute("data-bts-ga-proxy","true"),(f.head??f.documentElement).appendChild(B)}A.gtag("js",new Date),A.gtag("config",S,{send_page_view:!1})}function AS(){let S=N();if(!S)return;let A=typeof Intl<"u"?_(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,f=S.navigator,c=_(f?.language),B=Array.isArray(f?.languages)?f.languages.filter((y)=>typeof y==="string").slice(0,10):[],E=_(f?.userAgent),T={timezone:A,language:c,languages:B.length>0?B:void 0,userAgent:E};return Object.values(T).some((y)=>y!==void 0)?T:void 0}function Y(S){let A=$(),f=i();return{event_id:S,ga_client_id:typeof f?.clientId==="string"?f.clientId:void 0,ga_tag_installed:typeof f?.tagInstalled==="boolean"?f.tagInstalled:void 0,attribution:A?{utm:A.utm,clickIds:A.clickIds,...A.clickIds,landingUrl:A.landingUrl,referrer:A.referrer}:void 0,client:AS(),googleAnalytics:f,page:{title:D()?.title,url:H()}}}function $(){let S=N();if(!S)return K();let A=new URLSearchParams(S.location.search),f={utm:{},clickIds:{},landingUrl:S.location.href,lastSeenAt:new Date().toISOString(),referrer:P()};for(let E of p){let T=A.get(E);if(!T)continue;if(E.startsWith("utm_")){f.utm[E]=T;continue}f.clickIds[E]=T}for(let E of a){let T=z(E);if(T)f.clickIds[E.replace(/^_/,"")]=T}let c=K(),B={utm:{...c?.utm??{},...f.utm},clickIds:{...c?.clickIds??{},...f.clickIds},landingUrl:f.landingUrl??c?.landingUrl,lastSeenAt:f.lastSeenAt,referrer:f.referrer??c?.referrer};return o(B),B}function _(S){let A=S?.trim();return A?A.slice(0,512):void 0}function fS(S){if(!S)return{};if(S instanceof Headers){let A={};return S.forEach((f,c)=>{A[c]=f}),A}if(Array.isArray(S))return Object.fromEntries(S.map(([A,f])=>[A,String(f)]));return Object.fromEntries(Object.entries(S).map(([A,f])=>[A,String(f)]))}function cS(S){let A={...d};if(S.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(S.autoTrack&&typeof S.autoTrack==="object")return{pageviews:S.autoTrack.pageviews??A.pageviews,history:S.autoTrack.pageviews===!1?!1:S.autoTrack.history??A.history,outboundLinks:S.autoTrack.outboundLinks??A.outboundLinks,buttonClicks:S.autoTrack.buttonClicks??A.buttonClicks,formSubmissions:S.autoTrack.formSubmissions??A.formSubmissions,search:S.autoTrack.search??A.search,viewContent:S.autoTrack.viewContent??A.viewContent};if(S.autoPageviews===!1)return{...A,pageviews:!1,history:!1};if(S.autoPageviews===!0)return{...A,pageviews:!0};return A}class W{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanPending=!1;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(S){if(this.siteKey=S.siteKey,this.endpoint=(S.endpoint??s).replace(/\/$/,""),this.debug=S.debug??!1,this.flushIntervalMs=S.flushIntervalMs??l,this.autoTrack=cS(S),this.requestHeaders=S.requestHeaders,e(S)){let A=k(S);if(A)SS(A)}if($(),N())this.installAutoTracking()}static init(S){return new W(S)}getVisitorId(){let S=L(),A=S?.getItem(j);if(A)return A;let f=V();return S?.setItem(j,f),f}getSessionId(){let S=L(),A=S?.getItem(G);if(A)return A;let f=V();return S?.setItem(G,f),f}getPersistedJourneyId(){return L()?.getItem(O)??null}log(...S){if(this.debug)console.log("[@bts/analytics]",...S)}installAutoTracking(){let S=N(),A=D();if(!S||!A)return;if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(S),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},S.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=(f)=>{this.handleAutoClick(f)},this.submitHandler=(f)=>{this.handleAutoSubmit(f)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)A.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)A.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(A);S.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((S,A)=>{for(let f of S){if(!f.isIntersecting||!(f.target instanceof Element))continue;this.trackViewContentElement(f.target),A.unobserve(f.target)}}),this.viewContentObserver}observeViewContentElements(S){if(this.viewContentListenersTornDown||this.destroyed)return;let A=this.getOrCreateViewContentIntersectionObserver();if(!A)return;for(let f of Array.from(S.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has(f))continue;this.observedViewContentElements.add(f),A.observe(f)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanPending)return;this.viewContentRescanPending=!0,queueMicrotask(()=>{if(this.viewContentRescanPending=!1,this.viewContentListenersTornDown||this.destroyed)return;let S=D();if(S)this.observeViewContentElements(S)})}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let S=D();if(S)this.observeViewContentElements(S)}installViewContentTracking(S){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(S),typeof MutationObserver>"u")return;let A=S.body??S.documentElement;if(!A)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(A,{childList:!0,subtree:!0})}trackViewContentElement(S){if(this.trackedViewContentElements.has(S))return;this.trackedViewContentElements.add(S);let A=_(S.getAttribute("data-bts-view-content")||S.getAttribute("data-bts-content-id")||S.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:A,contentTitle:_(S.getAttribute("data-bts-content-title")||S.textContent),contentType:_(S.getAttribute("data-bts-content-type")),elementId:_(S.id)})}patchHistory(S){let A=S.history,f=A.pushState.bind(A),c=A.replaceState.bind(A),B=()=>{$(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return A.pushState=(...E)=>{f(...E),B()},A.replaceState=(...E)=>{c(...E),B()},()=>{A.pushState=f,A.replaceState=c}}handleAutoClick(S){if(S.defaultPrevented)return;let A=S.target;if(!(A instanceof Element))return;if(this.autoTrack.outboundLinks){let c=A.closest("a[href]");if(c instanceof HTMLAnchorElement){let B=_(c.href);if(!B)return;let E=new URL(B,R());if(E.origin!==R()){this.trackStandard("outbound_click",{elementHref:B,elementId:_(c.id),elementText:_(c.textContent),linkHost:E.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let f=A.closest("button,[role='button'],[data-bts-track-click]");if(!(f instanceof Element))return;this.trackStandard("button_click",{elementId:_(f.id),elementName:_(f.getAttribute("name")),elementRole:_(f.getAttribute("role")),elementText:_(f.textContent)})}handleAutoSubmit(S){if(S.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let A=S.target;if(!(A instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(A);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:_(A.action),formId:_(A.id),formMethod:_(A.method),formName:_(A.getAttribute("name"))})}trackSearchForm(S){if((S.method||"get").toLowerCase()!=="get")return;let f=this.extractSearchQuery(S);if(!f)return;this.trackStandard("search",{autoCaptured:!0,formAction:_(S.action),formId:_(S.id),formName:_(S.getAttribute("name")),queryKey:f.key,searchQuery:f.value})}extractSearchQuery(S){try{let f=new FormData(S);for(let c of Q){let B=f.get(c);if(typeof B==="string"){let E=_(B);if(E)return{key:c,value:E}}}}catch{}let A=S.elements;for(let f of Q){let c=A?.namedItem?.(f),B=c&&"value"in c?c.value:void 0;if(typeof B==="string"){let E=_(B);if(E)return{key:f,value:E}}}return null}buildEvent(S,A,f,c){let B=c?.path??F(),E=P(),T=V(),y=Y(T);return{eventName:S,eventType:A,path:B,referrer:E,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...f??{},...y,event_id:f?.event_id??f?.eventId??T}}}queueEvent(S,A,f){let c=X(S),B=Z(c.canonicalEventName,f),E={...A??{}};if(c.aliasOf)E.originalEventName=S;if(this.queue.push(this.buildEvent(c.eventName,B,E)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(S,A){let f=`${this.endpoint}${S}`;this.log("POST",f,A);let c=JSON.stringify(A),B=await this.resolveRequestHeaders(S,f,A,c,this.endpoint);return fetch(f,{method:"POST",headers:B,body:c})}async postWebsiteJson(S,A){let f=this.endpoint.replace(/\/analytics$/,""),c=`${f}${S}`;this.log("POST",c,A);let B=JSON.stringify(A),E=await this.resolveRequestHeaders(S,c,A,B,f);return fetch(c,{method:"POST",headers:E,body:B})}async postJsonKeepalive(S,A){let f=`${this.endpoint}${S}`;this.log("POST keepalive",f,A);let c=JSON.stringify(A),B=await this.resolveRequestHeaders(S,f,A,c,this.endpoint);return fetch(f,{method:"POST",headers:B,body:c,keepalive:!0})}async resolveRequestHeaders(S,A,f,c,B=this.endpoint){let E={"Content-Type":"application/json"};if(!this.requestHeaders)return E;let T=typeof this.requestHeaders==="function"?await this.requestHeaders({body:f,bodyText:c,endpoint:B,headers:{...E},path:S,siteKey:this.siteKey,url:A}):this.requestHeaders;return{...E,...fS(T)}}async flushBatch(S,A=!1){try{let f=A?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:S}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:S});if(!f.ok)return this.log("flush failed",f.status),!1;return!0}catch(f){return this.log("flush error",f),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let T=[...this.queue];this.queue=[],this.flushBatch(T,!0).then((y)=>{if(!y&&!this.destroyed)this.queue.unshift(...T),this.scheduleFlush()});return}let S=N(),A=S?.navigator?.sendBeacon?.bind(S.navigator);if(!A)return;let f=[...this.queue];this.queue=[];let c=`${this.endpoint}/ingest/batch`,B=JSON.stringify({siteKey:this.siteKey,events:f}),E=new Blob([B],{type:"application/json"});A(c,E)}async flushNow(){if(this.queue.length===0)return;let S=[...this.queue];if(this.queue=[],!await this.flushBatch(S)&&!this.destroyed)this.queue.unshift(...S),this.scheduleFlush()}recordPageView(S){let A=S??F(),f=H()??A??"/";if(f===this.lastTrackedUrl)return;this.lastTrackedUrl=f,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:A})),this.scheduleFlush()}page(S){this.lastTrackedUrl=null,this.recordPageView(S)}track(S,A){this.queueEvent(S,A)}trackStandard(S,A){this.queueEvent(S,A)}identify(S,A){this.queue.push(this.buildEvent("identify","identify",{traits:A??{},userId:S})),this.scheduleFlush()}listStandardEvents(){return C()}async submitContactForm(S){let A=V(),f=Y(A),c=await this.postWebsiteJson("/ghl/leads",{siteKey:this.siteKey,locationId:S.locationId,email:S.email,phone:S.phone,subject:S.subject,body:S.body,name:S.name,firstName:S.firstName,lastName:S.lastName,source:S.source,tags:S.tags,customFields:S.customFields,metadata:{...S.metadata??{},...f}});if(!c.ok)throw Error(`contact form submit failed: ${c.status}`);return await c.json()}async startFunnel(S){let A=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:S??F()});if(!A.ok)throw Error(`journey/start failed: ${A.status}`);let f=await A.json();return L()?.setItem(M,f.journeyToken),L()?.setItem(O,f.journeyId),f}getPersistedJourneyToken(){return L()?.getItem(M)??null}decorateUrl(S,A){let f=A??this.getPersistedJourneyToken(),c=new URL(S,R());if(c.searchParams.set(b,this.siteKey),f)c.searchParams.set(h,f);return c.toString()}async notifyHandoff(S,A){let f=await this.postJson("/journey/handoff",{journeyToken:S,context:A});if(!f.ok)throw Error(`journey/handoff failed: ${f.status}`)}destroy(){this.destroyed=!0,this.viewContentListenersTornDown=!0;let S=N(),A=D();if(A&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))A.removeEventListener("click",this.clickHandler,!0);if(A&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))A.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,S&&this.popstateHandler)S.removeEventListener("popstate",this.popstateHandler);if(S&&this.pagehideHandler)S.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon()}}function w(S){return W.init(S)}function I(S){return typeof S==="object"&&S!==null&&!Array.isArray(S)}function BS(S){return Array.from(S)}function x(S){let A=typeof window>"u"?null:window;if(!A)return;let[f,c,B]=S;if(typeof f!=="string")return;if(f==="js")return;if(f==="config"){if(typeof c!=="string"||c.trim().length===0)return;let y=I(B)?B:{};A.btsAnalytics=w({...y,siteKey:c});return}let E=A.btsAnalytics;if(!E)return;let T=I(B)?B:void 0;if(f==="event"&&typeof c==="string"){E.track(c,T);return}if(f==="identify"&&typeof c==="string"){E.identify(c,T);return}if(f==="page"){E.page(typeof c==="string"?c:void 0);return}if(f==="flush")E.flushNow()}if(typeof window<"u"){let S=Array.isArray(window.btsDataLayer)?[...window.btsDataLayer]:[];window.btsDataLayer=Array.isArray(window.btsDataLayer)?window.btsDataLayer:[],window.BTSAnalytics={BTSAnalytics:W,createBTSAnalytics:w,listStandardWebEvents:C},window.createBTSAnalytics=w;for(let A of S)x(BS(A));window.bts=(...A)=>{window.btsDataLayer?.push(A),x(A)}}export{C as listStandardWebEvents,w as createBTSAnalytics,W as BTSAnalytics};
1
+ var M=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],R="bts_analytics_vid",w="bts_analytics_sid",g="bts_analytics_jt",O="bts_analytics_jid",W="bts_analytics_attr",b="bts_site",T="bts_jt",o=64,s=300,r="https://api.bts.it.com/v2/website/analytics",v={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},U=["q","query","search"],x=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],I=["_fbp","_fbc"],l=7776000;var nf=new Set(M),Vf=new Set(M.map((f)=>f.toLowerCase())),zf=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),Qf={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function i(f){let j=f.trim();if(j.length===0)return{eventName:j,canonicalEventName:j,isStandard:!1};let B=j.toLowerCase(),$=Qf[B];if($)return{eventName:$,canonicalEventName:$,aliasOf:$,isStandard:!0};if(Vf.has(B)){let F=B;return{eventName:F,canonicalEventName:F,isStandard:!0}}return{eventName:j,canonicalEventName:j,isStandard:!1}}function t(f,j){if(j)return j;if(f==="page_view")return"page_view";if(f==="identify")return"identify";if(zf.has(f))return"conversion";return"custom"}function S(){return[...M]}function Z(){return typeof window>"u"?null:window}function y(){return typeof document>"u"?null:document}function z(){return Z()?.localStorage??null}function Q(f){let j=y();if(!j?.cookie)return;let B=`${f}=`,$=j.cookie.split(";").map((q)=>q.trim()).find((q)=>q.startsWith(B));if(!$)return;let F=$.slice(B.length);if(F==="")return;try{return decodeURIComponent(F)}catch{return F}}function m(f,j){let B=y();if(!B)return;let $=Z()?.location.protocol==="https:"?"; Secure":"";B.cookie=`${f}=${encodeURIComponent(j)}; Max-Age=${l}; Path=/; SameSite=Lax${$}`}function cf(){let f=new Uint32Array(1);if(typeof crypto<"u"&&typeof crypto.getRandomValues==="function")return crypto.getRandomValues(f),String(f[0]);return String(Math.floor(Math.random()*10000000000))}function Gf(f=Date.now()){return`fb.1.${f}.${cf()}`}function Pf(f,j=Date.now()){return`fb.1.${j}.${f}`}function a(){let f=Z();if(!f)return;if(!Q("_fbp"))m("_fbp",Gf());let j=new URLSearchParams(f.location.search).get("fbclid");if(j&&!Q("_fbc"))m("_fbc",Pf(j))}function k(){let f=Z();if(!f)return;return`${f.location.pathname}${f.location.search}`}function K(){return Z()?.location.href}function Y(){return Z()?.location.origin??"https://behindthescenes.com"}function C(){return y()?.referrer||void 0}function J(f){let j=f?.trim();return j?j.slice(0,512):void 0}function N(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function Df(f){if(!f)return null;try{let j=JSON.parse(f);if(!N(j))return null;let B=N(j.utm)?Object.fromEntries(Object.entries(j.utm).filter((F)=>typeof F[1]==="string")):{},$=N(j.clickIds)?Object.fromEntries(Object.entries(j.clickIds).filter((F)=>typeof F[1]==="string")):{};return{utm:B,clickIds:$,landingUrl:typeof j.landingUrl==="string"?j.landingUrl:void 0,lastSeenAt:typeof j.lastSeenAt==="string"?j.lastSeenAt:new Date().toISOString(),referrer:typeof j.referrer==="string"?j.referrer:void 0}}catch{return null}}function e(){let f=z();return Df(f?.getItem(W)??null)}function Mf(f){let j=z();if(!j)return;let B=JSON.stringify(f);if(j.getItem(W)===B)return;j.setItem(W,B)}var h=null,u=null;function ff(){h=null,u=null}function Wf(f){let j=new URLSearchParams(f.location.search),B=x.map((F)=>`${F}=${j.get(F)??""}`).join("&"),$=I.map((F)=>`${F}=${Q(F)??""}`).join("&");return`${f.location.href} ${B} ${$}`}function n(){let f=Z();if(!f)return e();let j=Wf(f);if(j===h&&u)return u;let B=new URLSearchParams(f.location.search),$={utm:{},clickIds:{},landingUrl:f.location.href,lastSeenAt:new Date().toISOString(),referrer:C()};for(let X of x){let L=B.get(X);if(!L)continue;if(X.startsWith("utm_")){$.utm[X]=L;continue}$.clickIds[X]=L}for(let X of I){let L=Q(X);if(L)$.clickIds[X.replace(/^_/,"")]=L}let F=e(),q={utm:{...F?.utm??{},...$.utm},clickIds:{...F?.clickIds??{},...$.clickIds},landingUrl:$.landingUrl??F?.landingUrl,lastSeenAt:$.lastSeenAt,referrer:$.referrer??F?.referrer};return Mf(q),h=j,u=q,q}function c(){return a(),n()}function jf(f){let j={...v};if(f.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(f.autoTrack&&typeof f.autoTrack==="object")return{pageviews:f.autoTrack.pageviews??j.pageviews,history:f.autoTrack.pageviews===!1?!1:f.autoTrack.history??j.history,outboundLinks:f.autoTrack.outboundLinks??j.outboundLinks,buttonClicks:f.autoTrack.buttonClicks??j.buttonClicks,formSubmissions:f.autoTrack.formSubmissions??j.formSubmissions,search:f.autoTrack.search??j.search,viewContent:f.autoTrack.viewContent??j.viewContent};if(f.autoPageviews===!1)return{...j,pageviews:!1,history:!1};if(f.autoPageviews===!0)return{...j,pageviews:!0};return j}function Sf(){let f=Q("_ga");if(!f)return;let j=f.split(".");if(j.length>=4&&/^GA\d+$/i.test(j[0]??""))return j.slice(-2).join(".");return J(f)}function kf(){let j=y()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),B=j&&"src"in j&&typeof j.src==="string"?j.src:void 0;if(!B)return;try{return J(new URL(B).searchParams.get("id"))}catch{return}}function Bf(){let f=Z(),j=Sf(),B=kf(),$=typeof f?.gtag==="function"||!!B||!!j;if(!$&&!j&&!B)return;return{tagInstalled:$,clientId:j,measurementId:B}}function _(f){if(!f.googleAnalytics||typeof f.googleAnalytics==="boolean")return;return J(f.googleAnalytics.measurementId)}function $f(f){if(!f.googleAnalytics)return!1;if(f.googleAnalytics===!0)return!1;return f.googleAnalytics.loadTag!==!1&&!!_(f)}function Ff(f){let j=Z(),B=y();if(!j||!B)return;j.dataLayer=Array.isArray(j.dataLayer)?j.dataLayer:[],j.gtag??=(...F)=>{j.dataLayer?.push(F)};let $=`script[src*="googletagmanager.com/gtag/js?id=${f}"]`;if(!B.querySelector?.($)){let F=B.createElement("script");F.async=!0,F.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(f)}`,F.setAttribute("data-bts-ga-proxy","true"),(B.head??B.documentElement).appendChild(F)}j.gtag("js",new Date),j.gtag("config",f,{send_page_view:!1})}function Kf(){let f=Z();if(!f)return;let j=typeof Intl<"u"?J(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,B=f.navigator,$=J(B?.language),F=Array.isArray(B?.languages)?B.languages.filter((L)=>typeof L==="string").slice(0,10):[],q=J(B?.userAgent),X={timezone:j,language:$,languages:F.length>0?F:void 0,userAgent:q};return Object.values(X).some((L)=>L!==void 0)?X:void 0}function p(f){let j=c(),B=Bf();return{event_id:f,ga_client_id:typeof B?.clientId==="string"?B.clientId:void 0,ga_tag_installed:typeof B?.tagInstalled==="boolean"?B.tagInstalled:void 0,attribution:j?{utm:j.utm,clickIds:j.clickIds,...j.clickIds,landingUrl:j.landingUrl,referrer:j.referrer}:void 0,client:Kf(),googleAnalytics:B,page:{title:y()?.title,url:K()}}}function qf(f){if(!f)return{};if(f instanceof Headers){let j={};return f.forEach((B,$)=>{j[$]=B}),j}if(Array.isArray(f))return Object.fromEntries(f.map(([j,B])=>[j,String(B)]));return Object.fromEntries(Object.entries(f).map(([j,B])=>[j,String(B)]))}function Jf(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function Yf(f,j){if(typeof j==="bigint")return j.toString();if(typeof j==="function"||typeof j==="symbol")return;if(j instanceof Date)return j.toISOString();if(ArrayBuffer.isView(j))return;return j}function G(f){try{return JSON.stringify(f,Yf)}catch(j){let B=j instanceof Error?j.message:"unknown";throw Error(`Failed to serialize request body: ${B}`)}}function H(f){let j=f?.trim();return j&&j.length>0?j:void 0}function E(f,j=0){if(j>8)return;if(f===null||f===void 0)return;if(typeof f==="string"||typeof f==="number"||typeof f==="boolean")return f;if(typeof f==="bigint")return f.toString();if(f instanceof Date)return f.toISOString();if(ArrayBuffer.isView(f)||typeof f==="function"||typeof f==="symbol")return;if(Array.isArray(f)){let $=f.map((F)=>E(F,j+1)).filter((F)=>F!==void 0);return $.length>0?$:void 0}if(!Jf(f))return;let B={};for(let[$,F]of Object.entries(f)){let q=E(F,j+1);if(q!==void 0)B[$]=q}return Object.keys(B).length>0?B:void 0}function Xf(f){if(!f)return;let j=E(f);return Jf(j)?j:void 0}function V(f,j,B){if(B===void 0)return;f[j]=B}function Zf(f,j,B){let $={siteKey:f,locationId:j.locationId};if(V($,"email",H(j.email)),V($,"phone",H(j.phone)),V($,"subject",H(j.subject)),V($,"body",H(j.body)),V($,"message",H(j.message)),V($,"name",H(j.name)),V($,"firstName",H(j.firstName)),V($,"lastName",H(j.lastName)),V($,"source",H(j.source)),j.tags&&j.tags.length>0)$.tags=j.tags;if(j.customFields&&Object.keys(j.customFields).length>0)$.customFields=j.customFields;let F=H(j.pipelineId),q=H(j.pipelineStageId);if(F&&q){if($.pipelineId=F,$.pipelineStageId=q,V($,"opportunityName",H(j.opportunityName)),typeof j.monetaryValue==="number"&&Number.isFinite(j.monetaryValue))$.monetaryValue=j.monetaryValue}let X=Xf({...j.metadata??{},...B});if(X)$.metadata=X;return $}function P(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}class D{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanTimer=null;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(f){if(this.siteKey=f.siteKey,this.endpoint=(f.endpoint??r).replace(/\/$/,""),this.debug=f.debug??!1,this.flushIntervalMs=f.flushIntervalMs??s,this.autoTrack=jf(f),this.requestHeaders=f.requestHeaders,$f(f)){let j=_(f);if(j)Ff(j)}if(Z())this.installAutoTracking()}static init(f){return new D(f)}getVisitorId(){let f=z(),j=f?.getItem(R);if(j)return j;let B=P();return f?.setItem(R,B),B}getSessionId(){let f=z(),j=f?.getItem(w);if(j)return j;let B=P();return f?.setItem(w,B),B}getPersistedJourneyId(){return z()?.getItem(O)??null}log(...f){if(this.debug)console.log("[@bts/analytics]",...f)}installAutoTracking(){let f=Z(),j=y();if(!f||!j)return;if(Object.values(this.autoTrack).some(Boolean))c();if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(f),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},f.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=(B)=>{this.handleAutoClick(B)},this.submitHandler=(B)=>{this.handleAutoSubmit(B)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)j.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)j.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(j);f.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((f,j)=>{for(let B of f){if(!B.isIntersecting||!(B.target instanceof Element))continue;this.trackViewContentElement(B.target),j.unobserve(B.target)}}),this.viewContentObserver}observeViewContentElements(f){if(this.viewContentListenersTornDown||this.destroyed)return;let j=this.getOrCreateViewContentIntersectionObserver();if(!j)return;for(let B of Array.from(f.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has(B))continue;this.observedViewContentElements.add(B),j.observe(B)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanTimer)return;this.viewContentRescanTimer=setTimeout(()=>{if(this.viewContentRescanTimer=null,this.viewContentListenersTornDown||this.destroyed)return;let f=y();if(f)this.observeViewContentElements(f)},o)}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let f=y();if(f)this.observeViewContentElements(f)}installViewContentTracking(f){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(f),typeof MutationObserver>"u")return;let j=f.body??f.documentElement;if(!j)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(j,{childList:!0,subtree:!0})}trackViewContentElement(f){if(this.trackedViewContentElements.has(f))return;this.trackedViewContentElements.add(f);let j=J(f.getAttribute("data-bts-view-content")||f.getAttribute("data-bts-content-id")||f.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:j,contentTitle:J(f.getAttribute("data-bts-content-title")||f.textContent),contentType:J(f.getAttribute("data-bts-content-type")),elementId:J(f.id)})}patchHistory(f){let j=f.history,B=j.pushState.bind(j),$=j.replaceState.bind(j),F=()=>{n(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return j.pushState=(...q)=>{B(...q),F()},j.replaceState=(...q)=>{$(...q),F()},()=>{j.pushState=B,j.replaceState=$}}handleAutoClick(f){if(f.defaultPrevented)return;let j=f.target;if(!(j instanceof Element))return;if(this.autoTrack.outboundLinks){let $=j.closest("a[href]");if($ instanceof HTMLAnchorElement){let F=J($.href);if(!F)return;let q=new URL(F,Y());if(q.origin!==Y()){this.trackStandard("outbound_click",{elementHref:F,elementId:J($.id),elementText:J($.textContent),linkHost:q.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let B=j.closest("button,[role='button'],[data-bts-track-click]");if(!(B instanceof Element))return;this.trackStandard("button_click",{elementId:J(B.id),elementName:J(B.getAttribute("name")),elementRole:J(B.getAttribute("role")),elementText:J(B.textContent)})}handleAutoSubmit(f){if(f.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let j=f.target;if(!(j instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(j);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:J(j.action),formId:J(j.id),formMethod:J(j.method),formName:J(j.getAttribute("name"))})}trackSearchForm(f){if((f.method||"get").toLowerCase()!=="get")return;let B=this.extractSearchQuery(f);if(!B)return;this.trackStandard("search",{autoCaptured:!0,formAction:J(f.action),formId:J(f.id),formName:J(f.getAttribute("name")),queryKey:B.key,searchQuery:B.value})}extractSearchQuery(f){try{let B=new FormData(f);for(let $ of U){let F=B.get($);if(typeof F==="string"){let q=J(F);if(q)return{key:$,value:q}}}}catch{}let j=f.elements;for(let B of U){let $=j?.namedItem?.(B),F=$&&"value"in $?$.value:void 0;if(typeof F==="string"){let q=J(F);if(q)return{key:B,value:q}}}return null}buildEvent(f,j,B,$){let F=$?.path??k(),q=C(),X=P(),L=p(X);return{eventName:f,eventType:j,path:F,referrer:q,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...B??{},...L,event_id:B?.event_id??B?.eventId??X}}}queueEvent(f,j,B){if(this.destroyed)return;let $=i(f),F=t($.canonicalEventName,B),q={...j??{}};if($.aliasOf)q.originalEventName=f;if(this.queue.push(this.buildEvent($.eventName,F,q)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(f,j){let B=`${this.endpoint}${f}`;this.log("POST",B,j);let $=G(j),F=await this.resolveRequestHeaders(f,B,j,$,this.endpoint);return fetch(B,{method:"POST",headers:F,body:$})}async postWebsiteJson(f,j){let B=this.endpoint.replace(/\/analytics$/,""),$=`${B}${f}`;this.log("POST",$,j);let F=G(j),q=await this.resolveRequestHeaders(f,$,j,F,B);return fetch($,{method:"POST",headers:q,body:F})}async postJsonKeepalive(f,j){let B=`${this.endpoint}${f}`;this.log("POST keepalive",B,j);let $=G(j),F=await this.resolveRequestHeaders(f,B,j,$,this.endpoint);return fetch(B,{method:"POST",headers:F,body:$,keepalive:!0})}async resolveRequestHeaders(f,j,B,$,F=this.endpoint){let q={"Content-Type":"application/json"};if(!this.requestHeaders)return q;let X=typeof this.requestHeaders==="function"?await this.requestHeaders({body:B,bodyText:$,endpoint:F,headers:{...q},path:f,siteKey:this.siteKey,url:j}):this.requestHeaders;return{...q,...qf(X)}}async flushBatch(f,j=!1){try{let B=j?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:f}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:f});if(!B.ok)return this.log("flush failed",B.status),!1;return!0}catch(B){return this.log("flush error",B),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let L=[...this.queue];this.queue=[],this.flushBatch(L,!0).then((yf)=>{if(!yf&&!this.destroyed)this.queue.unshift(...L),this.scheduleFlush()});return}let f=Z(),j=f?.navigator?.sendBeacon?.bind(f.navigator);if(!j)return;let B=[...this.queue];this.queue=[];let $=`${this.endpoint}/ingest/batch`,F=G({siteKey:this.siteKey,events:B}),q=new Blob([F],{type:"application/json"});if(!j($,q))this.queue.unshift(...B)}async flushNow(){if(this.destroyed)return;if(this.queue.length===0)return;let f=[...this.queue];if(this.queue=[],!await this.flushBatch(f)&&!this.destroyed)this.queue.unshift(...f),this.scheduleFlush()}recordPageView(f){let j=f??k(),B=K()??j??"/";if(B===this.lastTrackedUrl)return;this.lastTrackedUrl=B,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:j})),this.scheduleFlush()}page(f){this.lastTrackedUrl=null,this.recordPageView(f)}track(f,j){this.queueEvent(f,j)}trackStandard(f,j){this.queueEvent(f,j)}identify(f,j){if(this.destroyed)return;this.queue.push(this.buildEvent("identify","identify",{traits:j??{},userId:f})),this.scheduleFlush()}listStandardEvents(){return S()}async submitContactForm(f){let j=P(),B=p(j),$=await this.postWebsiteJson("/ghl/leads",Zf(this.siteKey,f,B));if(!$.ok)throw Error(`contact form submit failed: ${$.status}`);return await $.json()}async startFunnel(f){c();let j=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:f??k()});if(!j.ok)throw Error(`journey/start failed: ${j.status}`);let B=await j.json();return z()?.setItem(g,B.journeyToken),z()?.setItem(O,B.journeyId),B}getPersistedJourneyToken(){return z()?.getItem(g)??null}decorateUrl(f,j){let B=j??this.getPersistedJourneyToken(),$=new URL(f,Y());if($.searchParams.set(b,this.siteKey),B)$.searchParams.set(T,B);let F=n();if(F){for(let[q,X]of Object.entries(F.utm??{}))if(X)$.searchParams.set(q,X);for(let[q,X]of Object.entries(F.clickIds??{}))if(X)$.searchParams.set(q,X)}return $.toString()}async notifyHandoff(f,j){let B=await this.postJson("/journey/handoff",{journeyToken:f,context:j});if(!B.ok)throw Error(`journey/handoff failed: ${B.status}`)}destroy(){if(this.viewContentListenersTornDown=!0,ff(),this.viewContentRescanTimer)clearTimeout(this.viewContentRescanTimer),this.viewContentRescanTimer=null;let f=Z(),j=y();if(j&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))j.removeEventListener("click",this.clickHandler,!0);if(j&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))j.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,f&&this.popstateHandler)f.removeEventListener("popstate",this.popstateHandler);if(f&&this.pagehideHandler)f.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon(),this.destroyed=!0}}function A(f){return D.init(f)}function d(f){return typeof f==="object"&&f!==null&&!Array.isArray(f)}function Cf(f){return Array.from(f)}function Lf(f){let j=typeof window>"u"?null:window;if(!j)return;let[B,$,F]=f;if(typeof B!=="string")return;if(B==="js")return;if(B==="config"){if(typeof $!=="string"||$.trim().length===0)return;let L=d(F)?F:{};j.btsAnalytics?.destroy?.(),j.btsAnalytics=A({...L,siteKey:$});return}let q=j.btsAnalytics;if(!q)return;let X=d(F)?F:void 0;if(B==="event"&&typeof $==="string"){q.track($,X);return}if(B==="identify"&&typeof $==="string"){q.identify($,X);return}if(B==="page"){q.page(typeof $==="string"?$:void 0);return}if(B==="flush"){q.flushNow();return}if(B==="contact"||B==="submitContactForm"){if(!d($))return;q.submitContactForm($)}}if(typeof window<"u"){let f=Array.isArray(window.btsDataLayer)?[...window.btsDataLayer]:[];window.btsDataLayer=Array.isArray(window.btsDataLayer)?window.btsDataLayer:[],window.BTSAnalytics={BTSAnalytics:D,createBTSAnalytics:A,listStandardWebEvents:S},window.createBTSAnalytics=A;for(let j of f)Lf(Cf(j));window.bts=(...j)=>{window.btsDataLayer?.push(j),Lf(j)}}export{S as listStandardWebEvents,A as createBTSAnalytics,D as BTSAnalytics};
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- var{defineProperty:q,getOwnPropertyNames:g,getOwnPropertyDescriptor:v}=Object,h=Object.prototype.hasOwnProperty;var j=new WeakMap,b=(_)=>{var E=j.get(_),S;if(E)return E;if(E=q({},"__esModule",{value:!0}),_&&typeof _==="object"||typeof _==="function")g(_).map((N)=>!h.call(E,N)&&q(E,N,{get:()=>_[N],enumerable:!(S=v(_,N))||S.enumerable}));return j.set(_,E),E};var m=(_,E)=>{for(var S in E)q(_,S,{get:E[S],enumerable:!0,configurable:!0,set:(N)=>E[S]=()=>N})};var $_={};m($_,{listStandardWebEvents:()=>G,createBTSAnalytics:()=>L_,BTSAnalytics:()=>F});module.exports=b($_);var A=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],y=new Set(A),u=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),l={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function p(_){return y.has(_)}function Y(_){let E=_.trim();if(E.length===0)return{eventName:E,canonicalEventName:E,isStandard:!1};let S=E.toLowerCase(),N=l[S];if(N)return{eventName:N,canonicalEventName:N,aliasOf:N,isStandard:!0};return{eventName:E,canonicalEventName:E,isStandard:p(E)}}function f(_,E){if(E)return E;if(_==="page_view")return"page_view";if(_==="identify")return"identify";if(u.has(_))return"conversion";return"custom"}function G(){return[...A]}var K="bts_analytics_vid",U="bts_analytics_sid",R="bts_analytics_jt",H="bts_analytics_jid",k="bts_analytics_attr",d="bts_site",s="bts_jt",o=300,a="https://api.bts.it.com/v2/website/analytics",r={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},P=["q","query","search"],n=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],i=["_fbp","_fbc"];function L(){return typeof window>"u"?null:window}function $(){return typeof document>"u"?null:document}function J(){return L()?.localStorage??null}function Z(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}function M(_){return _!==null&&typeof _==="object"&&!Array.isArray(_)}function t(_){if(!_)return null;try{let E=JSON.parse(_);if(!M(E))return null;let S=M(E.utm)?Object.fromEntries(Object.entries(E.utm).filter((V)=>typeof V[1]==="string")):{},N=M(E.clickIds)?Object.fromEntries(Object.entries(E.clickIds).filter((V)=>typeof V[1]==="string")):{};return{utm:S,clickIds:N,landingUrl:typeof E.landingUrl==="string"?E.landingUrl:void 0,lastSeenAt:typeof E.lastSeenAt==="string"?E.lastSeenAt:new Date().toISOString(),referrer:typeof E.referrer==="string"?E.referrer:void 0}}catch{return null}}function T(){let _=J();return t(_?.getItem(k)??null)}function e(_){let E=J();if(!E)return;E.setItem(k,JSON.stringify(_))}function O(){let _=L();if(!_)return;return`${_.location.pathname}${_.location.search}`}function I(){return L()?.location.href}function Q(){return L()?.location.origin??"https://behindthescenes.com"}function c(){return $()?.referrer||void 0}function x(_){let E=$();if(!E?.cookie)return;let S=`${_}=`,N=E.cookie.split(";").map((D)=>D.trim()).find((D)=>D.startsWith(S));if(!N)return;let V=N.slice(S.length);if(V==="")return;try{return decodeURIComponent(V)}catch{return V}}function __(){let _=x("_ga");if(!_)return;let E=_.split(".");if(E.length>=4&&/^GA\d+$/i.test(E[0]??""))return E.slice(-2).join(".");return W(_)}function E_(){let E=$()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),S=E&&"src"in E&&typeof E.src==="string"?E.src:void 0;if(!S)return;try{return W(new URL(S).searchParams.get("id"))}catch{return}}function S_(){let _=L(),E=__(),S=E_(),N=typeof _?.gtag==="function"||!!S||!!E;if(!N&&!E&&!S)return;return{tagInstalled:N,clientId:E,measurementId:S}}function w(_){if(!_.googleAnalytics||typeof _.googleAnalytics==="boolean")return;return W(_.googleAnalytics.measurementId)}function N_(_){if(!_.googleAnalytics)return!1;if(_.googleAnalytics===!0)return!1;return _.googleAnalytics.loadTag!==!1&&!!w(_)}function V_(_){let E=L(),S=$();if(!E||!S)return;E.dataLayer=Array.isArray(E.dataLayer)?E.dataLayer:[],E.gtag??=(...V)=>{E.dataLayer?.push(V)};let N=`script[src*="googletagmanager.com/gtag/js?id=${_}"]`;if(!S.querySelector?.(N)){let V=S.createElement("script");V.async=!0,V.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(_)}`,V.setAttribute("data-bts-ga-proxy","true"),(S.head??S.documentElement).appendChild(V)}E.gtag("js",new Date),E.gtag("config",_,{send_page_view:!1})}function D_(){let _=L();if(!_)return;let E=typeof Intl<"u"?W(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,S=_.navigator,N=W(S?.language),V=Array.isArray(S?.languages)?S.languages.filter((X)=>typeof X==="string").slice(0,10):[],D=W(S?.userAgent),B={timezone:E,language:N,languages:V.length>0?V:void 0,userAgent:D};return Object.values(B).some((X)=>X!==void 0)?B:void 0}function z(_){let E=C(),S=S_();return{event_id:_,ga_client_id:typeof S?.clientId==="string"?S.clientId:void 0,ga_tag_installed:typeof S?.tagInstalled==="boolean"?S.tagInstalled:void 0,attribution:E?{utm:E.utm,clickIds:E.clickIds,...E.clickIds,landingUrl:E.landingUrl,referrer:E.referrer}:void 0,client:D_(),googleAnalytics:S,page:{title:$()?.title,url:I()}}}function C(){let _=L();if(!_)return T();let E=new URLSearchParams(_.location.search),S={utm:{},clickIds:{},landingUrl:_.location.href,lastSeenAt:new Date().toISOString(),referrer:c()};for(let D of n){let B=E.get(D);if(!B)continue;if(D.startsWith("utm_")){S.utm[D]=B;continue}S.clickIds[D]=B}for(let D of i){let B=x(D);if(B)S.clickIds[D.replace(/^_/,"")]=B}let N=T(),V={utm:{...N?.utm??{},...S.utm},clickIds:{...N?.clickIds??{},...S.clickIds},landingUrl:S.landingUrl??N?.landingUrl,lastSeenAt:S.lastSeenAt,referrer:S.referrer??N?.referrer};return e(V),V}function W(_){let E=_?.trim();return E?E.slice(0,512):void 0}function W_(_){if(!_)return{};if(_ instanceof Headers){let E={};return _.forEach((S,N)=>{E[N]=S}),E}if(Array.isArray(_))return Object.fromEntries(_.map(([E,S])=>[E,String(S)]));return Object.fromEntries(Object.entries(_).map(([E,S])=>[E,String(S)]))}function B_(_){let E={...r};if(_.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(_.autoTrack&&typeof _.autoTrack==="object")return{pageviews:_.autoTrack.pageviews??E.pageviews,history:_.autoTrack.pageviews===!1?!1:_.autoTrack.history??E.history,outboundLinks:_.autoTrack.outboundLinks??E.outboundLinks,buttonClicks:_.autoTrack.buttonClicks??E.buttonClicks,formSubmissions:_.autoTrack.formSubmissions??E.formSubmissions,search:_.autoTrack.search??E.search,viewContent:_.autoTrack.viewContent??E.viewContent};if(_.autoPageviews===!1)return{...E,pageviews:!1,history:!1};if(_.autoPageviews===!0)return{...E,pageviews:!0};return E}class F{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanPending=!1;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(_){if(this.siteKey=_.siteKey,this.endpoint=(_.endpoint??a).replace(/\/$/,""),this.debug=_.debug??!1,this.flushIntervalMs=_.flushIntervalMs??o,this.autoTrack=B_(_),this.requestHeaders=_.requestHeaders,N_(_)){let E=w(_);if(E)V_(E)}if(C(),L())this.installAutoTracking()}static init(_){return new F(_)}getVisitorId(){let _=J(),E=_?.getItem(K);if(E)return E;let S=Z();return _?.setItem(K,S),S}getSessionId(){let _=J(),E=_?.getItem(U);if(E)return E;let S=Z();return _?.setItem(U,S),S}getPersistedJourneyId(){return J()?.getItem(H)??null}log(..._){if(this.debug)console.log("[@bts/analytics]",..._)}installAutoTracking(){let _=L(),E=$();if(!_||!E)return;if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(_),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},_.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=(S)=>{this.handleAutoClick(S)},this.submitHandler=(S)=>{this.handleAutoSubmit(S)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)E.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)E.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(E);_.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((_,E)=>{for(let S of _){if(!S.isIntersecting||!(S.target instanceof Element))continue;this.trackViewContentElement(S.target),E.unobserve(S.target)}}),this.viewContentObserver}observeViewContentElements(_){if(this.viewContentListenersTornDown||this.destroyed)return;let E=this.getOrCreateViewContentIntersectionObserver();if(!E)return;for(let S of Array.from(_.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has(S))continue;this.observedViewContentElements.add(S),E.observe(S)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanPending)return;this.viewContentRescanPending=!0,queueMicrotask(()=>{if(this.viewContentRescanPending=!1,this.viewContentListenersTornDown||this.destroyed)return;let _=$();if(_)this.observeViewContentElements(_)})}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let _=$();if(_)this.observeViewContentElements(_)}installViewContentTracking(_){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(_),typeof MutationObserver>"u")return;let E=_.body??_.documentElement;if(!E)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(E,{childList:!0,subtree:!0})}trackViewContentElement(_){if(this.trackedViewContentElements.has(_))return;this.trackedViewContentElements.add(_);let E=W(_.getAttribute("data-bts-view-content")||_.getAttribute("data-bts-content-id")||_.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:E,contentTitle:W(_.getAttribute("data-bts-content-title")||_.textContent),contentType:W(_.getAttribute("data-bts-content-type")),elementId:W(_.id)})}patchHistory(_){let E=_.history,S=E.pushState.bind(E),N=E.replaceState.bind(E),V=()=>{C(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return E.pushState=(...D)=>{S(...D),V()},E.replaceState=(...D)=>{N(...D),V()},()=>{E.pushState=S,E.replaceState=N}}handleAutoClick(_){if(_.defaultPrevented)return;let E=_.target;if(!(E instanceof Element))return;if(this.autoTrack.outboundLinks){let N=E.closest("a[href]");if(N instanceof HTMLAnchorElement){let V=W(N.href);if(!V)return;let D=new URL(V,Q());if(D.origin!==Q()){this.trackStandard("outbound_click",{elementHref:V,elementId:W(N.id),elementText:W(N.textContent),linkHost:D.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let S=E.closest("button,[role='button'],[data-bts-track-click]");if(!(S instanceof Element))return;this.trackStandard("button_click",{elementId:W(S.id),elementName:W(S.getAttribute("name")),elementRole:W(S.getAttribute("role")),elementText:W(S.textContent)})}handleAutoSubmit(_){if(_.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let E=_.target;if(!(E instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(E);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:W(E.action),formId:W(E.id),formMethod:W(E.method),formName:W(E.getAttribute("name"))})}trackSearchForm(_){if((_.method||"get").toLowerCase()!=="get")return;let S=this.extractSearchQuery(_);if(!S)return;this.trackStandard("search",{autoCaptured:!0,formAction:W(_.action),formId:W(_.id),formName:W(_.getAttribute("name")),queryKey:S.key,searchQuery:S.value})}extractSearchQuery(_){try{let S=new FormData(_);for(let N of P){let V=S.get(N);if(typeof V==="string"){let D=W(V);if(D)return{key:N,value:D}}}}catch{}let E=_.elements;for(let S of P){let N=E?.namedItem?.(S),V=N&&"value"in N?N.value:void 0;if(typeof V==="string"){let D=W(V);if(D)return{key:S,value:D}}}return null}buildEvent(_,E,S,N){let V=N?.path??O(),D=c(),B=Z(),X=z(B);return{eventName:_,eventType:E,path:V,referrer:D,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...S??{},...X,event_id:S?.event_id??S?.eventId??B}}}queueEvent(_,E,S){let N=Y(_),V=f(N.canonicalEventName,S),D={...E??{}};if(N.aliasOf)D.originalEventName=_;if(this.queue.push(this.buildEvent(N.eventName,V,D)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(_,E){let S=`${this.endpoint}${_}`;this.log("POST",S,E);let N=JSON.stringify(E),V=await this.resolveRequestHeaders(_,S,E,N,this.endpoint);return fetch(S,{method:"POST",headers:V,body:N})}async postWebsiteJson(_,E){let S=this.endpoint.replace(/\/analytics$/,""),N=`${S}${_}`;this.log("POST",N,E);let V=JSON.stringify(E),D=await this.resolveRequestHeaders(_,N,E,V,S);return fetch(N,{method:"POST",headers:D,body:V})}async postJsonKeepalive(_,E){let S=`${this.endpoint}${_}`;this.log("POST keepalive",S,E);let N=JSON.stringify(E),V=await this.resolveRequestHeaders(_,S,E,N,this.endpoint);return fetch(S,{method:"POST",headers:V,body:N,keepalive:!0})}async resolveRequestHeaders(_,E,S,N,V=this.endpoint){let D={"Content-Type":"application/json"};if(!this.requestHeaders)return D;let B=typeof this.requestHeaders==="function"?await this.requestHeaders({body:S,bodyText:N,endpoint:V,headers:{...D},path:_,siteKey:this.siteKey,url:E}):this.requestHeaders;return{...D,...W_(B)}}async flushBatch(_,E=!1){try{let S=E?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:_}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:_});if(!S.ok)return this.log("flush failed",S.status),!1;return!0}catch(S){return this.log("flush error",S),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let B=[...this.queue];this.queue=[],this.flushBatch(B,!0).then((X)=>{if(!X&&!this.destroyed)this.queue.unshift(...B),this.scheduleFlush()});return}let _=L(),E=_?.navigator?.sendBeacon?.bind(_.navigator);if(!E)return;let S=[...this.queue];this.queue=[];let N=`${this.endpoint}/ingest/batch`,V=JSON.stringify({siteKey:this.siteKey,events:S}),D=new Blob([V],{type:"application/json"});E(N,D)}async flushNow(){if(this.queue.length===0)return;let _=[...this.queue];if(this.queue=[],!await this.flushBatch(_)&&!this.destroyed)this.queue.unshift(..._),this.scheduleFlush()}recordPageView(_){let E=_??O(),S=I()??E??"/";if(S===this.lastTrackedUrl)return;this.lastTrackedUrl=S,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:E})),this.scheduleFlush()}page(_){this.lastTrackedUrl=null,this.recordPageView(_)}track(_,E){this.queueEvent(_,E)}trackStandard(_,E){this.queueEvent(_,E)}identify(_,E){this.queue.push(this.buildEvent("identify","identify",{traits:E??{},userId:_})),this.scheduleFlush()}listStandardEvents(){return G()}async submitContactForm(_){let E=Z(),S=z(E),N=await this.postWebsiteJson("/ghl/leads",{siteKey:this.siteKey,locationId:_.locationId,email:_.email,phone:_.phone,subject:_.subject,body:_.body,name:_.name,firstName:_.firstName,lastName:_.lastName,source:_.source,tags:_.tags,customFields:_.customFields,metadata:{..._.metadata??{},...S}});if(!N.ok)throw Error(`contact form submit failed: ${N.status}`);return await N.json()}async startFunnel(_){let E=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:_??O()});if(!E.ok)throw Error(`journey/start failed: ${E.status}`);let S=await E.json();return J()?.setItem(R,S.journeyToken),J()?.setItem(H,S.journeyId),S}getPersistedJourneyToken(){return J()?.getItem(R)??null}decorateUrl(_,E){let S=E??this.getPersistedJourneyToken(),N=new URL(_,Q());if(N.searchParams.set(d,this.siteKey),S)N.searchParams.set(s,S);return N.toString()}async notifyHandoff(_,E){let S=await this.postJson("/journey/handoff",{journeyToken:_,context:E});if(!S.ok)throw Error(`journey/handoff failed: ${S.status}`)}destroy(){this.destroyed=!0,this.viewContentListenersTornDown=!0;let _=L(),E=$();if(E&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))E.removeEventListener("click",this.clickHandler,!0);if(E&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))E.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,_&&this.popstateHandler)_.removeEventListener("popstate",this.popstateHandler);if(_&&this.pagehideHandler)_.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon()}}function L_(_){return F.init(_)}
1
+ var{defineProperty:g,getOwnPropertyNames:zf,getOwnPropertyDescriptor:Qf}=Object,Lf=Object.prototype.hasOwnProperty;function Gf(f){return this[f]}var Bf=(f)=>{var j=(p??=new WeakMap).get(f),$;if(j)return j;if(j=g({},"__esModule",{value:!0}),f&&typeof f==="object"||typeof f==="function"){for(var J of zf(f))if(!Lf.call(j,J))g(j,J,{get:Gf.bind(f,J),enumerable:!($=Qf(f,J))||$.enumerable})}return p.set(f,j),j},p;var Mf=(f)=>f;function Pf(f,j){this[f]=Mf.bind(null,j)}var Wf=(f,j)=>{for(var $ in j)g(f,$,{get:j[$],enumerable:!0,configurable:!0,set:Pf.bind(j,$)})};var Af={};Wf(Af,{listStandardWebEvents:()=>E,createBTSAnalytics:()=>hf,BTSAnalytics:()=>S});module.exports=Bf(Af);var K=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],x="bts_analytics_vid",I="bts_analytics_sid",N="bts_analytics_jt",_="bts_analytics_jid",Y="bts_analytics_attr",d="bts_site",v="bts_jt",l=64,n=300,s="https://api.bts.it.com/v2/website/analytics",o={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},h=["q","query","search"],A=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],c=["_fbp","_fbc"],r=7776000;var wf=new Set(K),Yf=new Set(K.map((f)=>f.toLowerCase())),Df=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),kf={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function i(f){let j=f.trim();if(j.length===0)return{eventName:j,canonicalEventName:j,isStandard:!1};let $=j.toLowerCase(),J=kf[$];if(J)return{eventName:J,canonicalEventName:J,aliasOf:J,isStandard:!0};if(Yf.has($)){let X=$;return{eventName:X,canonicalEventName:X,isStandard:!0}}return{eventName:j,canonicalEventName:j,isStandard:!1}}function a(f,j){if(j)return j;if(f==="page_view")return"page_view";if(f==="identify")return"identify";if(Df.has(f))return"conversion";return"custom"}function E(){return[...K]}function H(){return typeof window>"u"?null:window}function z(){return typeof document>"u"?null:document}function G(){return H()?.localStorage??null}function B(f){let j=z();if(!j?.cookie)return;let $=`${f}=`,J=j.cookie.split(";").map((Z)=>Z.trim()).find((Z)=>Z.startsWith($));if(!J)return;let X=J.slice($.length);if(X==="")return;try{return decodeURIComponent(X)}catch{return X}}function w(f,j){let $=z();if(!$)return;let J=H()?.location.protocol==="https:"?"; Secure":"";$.cookie=`${f}=${encodeURIComponent(j)}; Max-Age=${r}; Path=/; SameSite=Lax${J}`}function Of(){let f=new Uint32Array(1);if(typeof crypto<"u"&&typeof crypto.getRandomValues==="function")return crypto.getRandomValues(f),String(f[0]);return String(Math.floor(Math.random()*10000000000))}function Uf(f=Date.now()){return`fb.1.${f}.${Of()}`}function Cf(f,j=Date.now()){return`fb.1.${j}.${f}`}function t(){let f=H();if(!f)return;if(!B("_fbp"))w("_fbp",Uf());let j=new URLSearchParams(f.location.search).get("fbclid");if(j&&!B("_fbc"))w("_fbc",Cf(j))}function D(){let f=H();if(!f)return;return`${f.location.pathname}${f.location.search}`}function k(){return H()?.location.href}function O(){return H()?.location.origin??"https://behindthescenes.com"}function U(){return z()?.referrer||void 0}function q(f){let j=f?.trim();return j?j.slice(0,512):void 0}function y(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function Rf(f){if(!f)return null;try{let j=JSON.parse(f);if(!y(j))return null;let $=y(j.utm)?Object.fromEntries(Object.entries(j.utm).filter((X)=>typeof X[1]==="string")):{},J=y(j.clickIds)?Object.fromEntries(Object.entries(j.clickIds).filter((X)=>typeof X[1]==="string")):{};return{utm:$,clickIds:J,landingUrl:typeof j.landingUrl==="string"?j.landingUrl:void 0,lastSeenAt:typeof j.lastSeenAt==="string"?j.lastSeenAt:new Date().toISOString(),referrer:typeof j.referrer==="string"?j.referrer:void 0}}catch{return null}}function e(){let f=G();return Rf(f?.getItem(Y)??null)}function Sf(f){let j=G();if(!j)return;let $=JSON.stringify(f);if(j.getItem(Y)===$)return;j.setItem(Y,$)}var u=null,C=null;function ff(){u=null,C=null}function gf(f){let j=new URLSearchParams(f.location.search),$=A.map((X)=>`${X}=${j.get(X)??""}`).join("&"),J=c.map((X)=>`${X}=${B(X)??""}`).join("&");return`${f.location.href} ${$} ${J}`}function R(){let f=H();if(!f)return e();let j=gf(f);if(j===u&&C)return C;let $=new URLSearchParams(f.location.search),J={utm:{},clickIds:{},landingUrl:f.location.href,lastSeenAt:new Date().toISOString(),referrer:U()};for(let F of A){let V=$.get(F);if(!V)continue;if(F.startsWith("utm_")){J.utm[F]=V;continue}J.clickIds[F]=V}for(let F of c){let V=B(F);if(V)J.clickIds[F.replace(/^_/,"")]=V}let X=e(),Z={utm:{...X?.utm??{},...J.utm},clickIds:{...X?.clickIds??{},...J.clickIds},landingUrl:J.landingUrl??X?.landingUrl,lastSeenAt:J.lastSeenAt,referrer:J.referrer??X?.referrer};return Sf(Z),u=j,C=Z,Z}function M(){return t(),R()}function jf(f){let j={...o};if(f.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(f.autoTrack&&typeof f.autoTrack==="object")return{pageviews:f.autoTrack.pageviews??j.pageviews,history:f.autoTrack.pageviews===!1?!1:f.autoTrack.history??j.history,outboundLinks:f.autoTrack.outboundLinks??j.outboundLinks,buttonClicks:f.autoTrack.buttonClicks??j.buttonClicks,formSubmissions:f.autoTrack.formSubmissions??j.formSubmissions,search:f.autoTrack.search??j.search,viewContent:f.autoTrack.viewContent??j.viewContent};if(f.autoPageviews===!1)return{...j,pageviews:!1,history:!1};if(f.autoPageviews===!0)return{...j,pageviews:!0};return j}function xf(){let f=B("_ga");if(!f)return;let j=f.split(".");if(j.length>=4&&/^GA\d+$/i.test(j[0]??""))return j.slice(-2).join(".");return q(f)}function If(){let j=z()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),$=j&&"src"in j&&typeof j.src==="string"?j.src:void 0;if(!$)return;try{return q(new URL($).searchParams.get("id"))}catch{return}}function $f(){let f=H(),j=xf(),$=If(),J=typeof f?.gtag==="function"||!!$||!!j;if(!J&&!j&&!$)return;return{tagInstalled:J,clientId:j,measurementId:$}}function m(f){if(!f.googleAnalytics||typeof f.googleAnalytics==="boolean")return;return q(f.googleAnalytics.measurementId)}function Jf(f){if(!f.googleAnalytics)return!1;if(f.googleAnalytics===!0)return!1;return f.googleAnalytics.loadTag!==!1&&!!m(f)}function Xf(f){let j=H(),$=z();if(!j||!$)return;j.dataLayer=Array.isArray(j.dataLayer)?j.dataLayer:[],j.gtag??=(...X)=>{j.dataLayer?.push(X)};let J=`script[src*="googletagmanager.com/gtag/js?id=${f}"]`;if(!$.querySelector?.(J)){let X=$.createElement("script");X.async=!0,X.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(f)}`,X.setAttribute("data-bts-ga-proxy","true"),($.head??$.documentElement).appendChild(X)}j.gtag("js",new Date),j.gtag("config",f,{send_page_view:!1})}function Nf(){let f=H();if(!f)return;let j=typeof Intl<"u"?q(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,$=f.navigator,J=q($?.language),X=Array.isArray($?.languages)?$.languages.filter((V)=>typeof V==="string").slice(0,10):[],Z=q($?.userAgent),F={timezone:j,language:J,languages:X.length>0?X:void 0,userAgent:Z};return Object.values(F).some((V)=>V!==void 0)?F:void 0}function b(f){let j=M(),$=$f();return{event_id:f,ga_client_id:typeof $?.clientId==="string"?$.clientId:void 0,ga_tag_installed:typeof $?.tagInstalled==="boolean"?$.tagInstalled:void 0,attribution:j?{utm:j.utm,clickIds:j.clickIds,...j.clickIds,landingUrl:j.landingUrl,referrer:j.referrer}:void 0,client:Nf(),googleAnalytics:$,page:{title:z()?.title,url:k()}}}function Zf(f){if(!f)return{};if(f instanceof Headers){let j={};return f.forEach(($,J)=>{j[J]=$}),j}if(Array.isArray(f))return Object.fromEntries(f.map(([j,$])=>[j,String($)]));return Object.fromEntries(Object.entries(f).map(([j,$])=>[j,String($)]))}function qf(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function _f(f,j){if(typeof j==="bigint")return j.toString();if(typeof j==="function"||typeof j==="symbol")return;if(j instanceof Date)return j.toISOString();if(ArrayBuffer.isView(j))return;return j}function P(f){try{return JSON.stringify(f,_f)}catch(j){let $=j instanceof Error?j.message:"unknown";throw Error(`Failed to serialize request body: ${$}`)}}function Q(f){let j=f?.trim();return j&&j.length>0?j:void 0}function T(f,j=0){if(j>8)return;if(f===null||f===void 0)return;if(typeof f==="string"||typeof f==="number"||typeof f==="boolean")return f;if(typeof f==="bigint")return f.toString();if(f instanceof Date)return f.toISOString();if(ArrayBuffer.isView(f)||typeof f==="function"||typeof f==="symbol")return;if(Array.isArray(f)){let J=f.map((X)=>T(X,j+1)).filter((X)=>X!==void 0);return J.length>0?J:void 0}if(!qf(f))return;let $={};for(let[J,X]of Object.entries(f)){let Z=T(X,j+1);if(Z!==void 0)$[J]=Z}return Object.keys($).length>0?$:void 0}function Ff(f){if(!f)return;let j=T(f);return qf(j)?j:void 0}function L(f,j,$){if($===void 0)return;f[j]=$}function Hf(f,j,$){let J={siteKey:f,locationId:j.locationId};if(L(J,"email",Q(j.email)),L(J,"phone",Q(j.phone)),L(J,"subject",Q(j.subject)),L(J,"body",Q(j.body)),L(J,"message",Q(j.message)),L(J,"name",Q(j.name)),L(J,"firstName",Q(j.firstName)),L(J,"lastName",Q(j.lastName)),L(J,"source",Q(j.source)),j.tags&&j.tags.length>0)J.tags=j.tags;if(j.customFields&&Object.keys(j.customFields).length>0)J.customFields=j.customFields;let X=Q(j.pipelineId),Z=Q(j.pipelineStageId);if(X&&Z){if(J.pipelineId=X,J.pipelineStageId=Z,L(J,"opportunityName",Q(j.opportunityName)),typeof j.monetaryValue==="number"&&Number.isFinite(j.monetaryValue))J.monetaryValue=j.monetaryValue}let F=Ff({...j.metadata??{},...$});if(F)J.metadata=F;return J}function W(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}class S{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanTimer=null;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(f){if(this.siteKey=f.siteKey,this.endpoint=(f.endpoint??s).replace(/\/$/,""),this.debug=f.debug??!1,this.flushIntervalMs=f.flushIntervalMs??n,this.autoTrack=jf(f),this.requestHeaders=f.requestHeaders,Jf(f)){let j=m(f);if(j)Xf(j)}if(H())this.installAutoTracking()}static init(f){return new S(f)}getVisitorId(){let f=G(),j=f?.getItem(x);if(j)return j;let $=W();return f?.setItem(x,$),$}getSessionId(){let f=G(),j=f?.getItem(I);if(j)return j;let $=W();return f?.setItem(I,$),$}getPersistedJourneyId(){return G()?.getItem(_)??null}log(...f){if(this.debug)console.log("[@bts/analytics]",...f)}installAutoTracking(){let f=H(),j=z();if(!f||!j)return;if(Object.values(this.autoTrack).some(Boolean))M();if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(f),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},f.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=($)=>{this.handleAutoClick($)},this.submitHandler=($)=>{this.handleAutoSubmit($)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)j.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)j.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(j);f.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((f,j)=>{for(let $ of f){if(!$.isIntersecting||!($.target instanceof Element))continue;this.trackViewContentElement($.target),j.unobserve($.target)}}),this.viewContentObserver}observeViewContentElements(f){if(this.viewContentListenersTornDown||this.destroyed)return;let j=this.getOrCreateViewContentIntersectionObserver();if(!j)return;for(let $ of Array.from(f.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has($))continue;this.observedViewContentElements.add($),j.observe($)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanTimer)return;this.viewContentRescanTimer=setTimeout(()=>{if(this.viewContentRescanTimer=null,this.viewContentListenersTornDown||this.destroyed)return;let f=z();if(f)this.observeViewContentElements(f)},l)}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let f=z();if(f)this.observeViewContentElements(f)}installViewContentTracking(f){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(f),typeof MutationObserver>"u")return;let j=f.body??f.documentElement;if(!j)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(j,{childList:!0,subtree:!0})}trackViewContentElement(f){if(this.trackedViewContentElements.has(f))return;this.trackedViewContentElements.add(f);let j=q(f.getAttribute("data-bts-view-content")||f.getAttribute("data-bts-content-id")||f.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:j,contentTitle:q(f.getAttribute("data-bts-content-title")||f.textContent),contentType:q(f.getAttribute("data-bts-content-type")),elementId:q(f.id)})}patchHistory(f){let j=f.history,$=j.pushState.bind(j),J=j.replaceState.bind(j),X=()=>{R(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return j.pushState=(...Z)=>{$(...Z),X()},j.replaceState=(...Z)=>{J(...Z),X()},()=>{j.pushState=$,j.replaceState=J}}handleAutoClick(f){if(f.defaultPrevented)return;let j=f.target;if(!(j instanceof Element))return;if(this.autoTrack.outboundLinks){let J=j.closest("a[href]");if(J instanceof HTMLAnchorElement){let X=q(J.href);if(!X)return;let Z=new URL(X,O());if(Z.origin!==O()){this.trackStandard("outbound_click",{elementHref:X,elementId:q(J.id),elementText:q(J.textContent),linkHost:Z.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let $=j.closest("button,[role='button'],[data-bts-track-click]");if(!($ instanceof Element))return;this.trackStandard("button_click",{elementId:q($.id),elementName:q($.getAttribute("name")),elementRole:q($.getAttribute("role")),elementText:q($.textContent)})}handleAutoSubmit(f){if(f.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let j=f.target;if(!(j instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(j);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:q(j.action),formId:q(j.id),formMethod:q(j.method),formName:q(j.getAttribute("name"))})}trackSearchForm(f){if((f.method||"get").toLowerCase()!=="get")return;let $=this.extractSearchQuery(f);if(!$)return;this.trackStandard("search",{autoCaptured:!0,formAction:q(f.action),formId:q(f.id),formName:q(f.getAttribute("name")),queryKey:$.key,searchQuery:$.value})}extractSearchQuery(f){try{let $=new FormData(f);for(let J of h){let X=$.get(J);if(typeof X==="string"){let Z=q(X);if(Z)return{key:J,value:Z}}}}catch{}let j=f.elements;for(let $ of h){let J=j?.namedItem?.($),X=J&&"value"in J?J.value:void 0;if(typeof X==="string"){let Z=q(X);if(Z)return{key:$,value:Z}}}return null}buildEvent(f,j,$,J){let X=J?.path??D(),Z=U(),F=W(),V=b(F);return{eventName:f,eventType:j,path:X,referrer:Z,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...$??{},...V,event_id:$?.event_id??$?.eventId??F}}}queueEvent(f,j,$){if(this.destroyed)return;let J=i(f),X=a(J.canonicalEventName,$),Z={...j??{}};if(J.aliasOf)Z.originalEventName=f;if(this.queue.push(this.buildEvent(J.eventName,X,Z)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(f,j){let $=`${this.endpoint}${f}`;this.log("POST",$,j);let J=P(j),X=await this.resolveRequestHeaders(f,$,j,J,this.endpoint);return fetch($,{method:"POST",headers:X,body:J})}async postWebsiteJson(f,j){let $=this.endpoint.replace(/\/analytics$/,""),J=`${$}${f}`;this.log("POST",J,j);let X=P(j),Z=await this.resolveRequestHeaders(f,J,j,X,$);return fetch(J,{method:"POST",headers:Z,body:X})}async postJsonKeepalive(f,j){let $=`${this.endpoint}${f}`;this.log("POST keepalive",$,j);let J=P(j),X=await this.resolveRequestHeaders(f,$,j,J,this.endpoint);return fetch($,{method:"POST",headers:X,body:J,keepalive:!0})}async resolveRequestHeaders(f,j,$,J,X=this.endpoint){let Z={"Content-Type":"application/json"};if(!this.requestHeaders)return Z;let F=typeof this.requestHeaders==="function"?await this.requestHeaders({body:$,bodyText:J,endpoint:X,headers:{...Z},path:f,siteKey:this.siteKey,url:j}):this.requestHeaders;return{...Z,...Zf(F)}}async flushBatch(f,j=!1){try{let $=j?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:f}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:f});if(!$.ok)return this.log("flush failed",$.status),!1;return!0}catch($){return this.log("flush error",$),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let V=[...this.queue];this.queue=[],this.flushBatch(V,!0).then((Vf)=>{if(!Vf&&!this.destroyed)this.queue.unshift(...V),this.scheduleFlush()});return}let f=H(),j=f?.navigator?.sendBeacon?.bind(f.navigator);if(!j)return;let $=[...this.queue];this.queue=[];let J=`${this.endpoint}/ingest/batch`,X=P({siteKey:this.siteKey,events:$}),Z=new Blob([X],{type:"application/json"});if(!j(J,Z))this.queue.unshift(...$)}async flushNow(){if(this.destroyed)return;if(this.queue.length===0)return;let f=[...this.queue];if(this.queue=[],!await this.flushBatch(f)&&!this.destroyed)this.queue.unshift(...f),this.scheduleFlush()}recordPageView(f){let j=f??D(),$=k()??j??"/";if($===this.lastTrackedUrl)return;this.lastTrackedUrl=$,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:j})),this.scheduleFlush()}page(f){this.lastTrackedUrl=null,this.recordPageView(f)}track(f,j){this.queueEvent(f,j)}trackStandard(f,j){this.queueEvent(f,j)}identify(f,j){if(this.destroyed)return;this.queue.push(this.buildEvent("identify","identify",{traits:j??{},userId:f})),this.scheduleFlush()}listStandardEvents(){return E()}async submitContactForm(f){let j=W(),$=b(j),J=await this.postWebsiteJson("/ghl/leads",Hf(this.siteKey,f,$));if(!J.ok)throw Error(`contact form submit failed: ${J.status}`);return await J.json()}async startFunnel(f){M();let j=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:f??D()});if(!j.ok)throw Error(`journey/start failed: ${j.status}`);let $=await j.json();return G()?.setItem(N,$.journeyToken),G()?.setItem(_,$.journeyId),$}getPersistedJourneyToken(){return G()?.getItem(N)??null}decorateUrl(f,j){let $=j??this.getPersistedJourneyToken(),J=new URL(f,O());if(J.searchParams.set(d,this.siteKey),$)J.searchParams.set(v,$);let X=R();if(X){for(let[Z,F]of Object.entries(X.utm??{}))if(F)J.searchParams.set(Z,F);for(let[Z,F]of Object.entries(X.clickIds??{}))if(F)J.searchParams.set(Z,F)}return J.toString()}async notifyHandoff(f,j){let $=await this.postJson("/journey/handoff",{journeyToken:f,context:j});if(!$.ok)throw Error(`journey/handoff failed: ${$.status}`)}destroy(){if(this.viewContentListenersTornDown=!0,ff(),this.viewContentRescanTimer)clearTimeout(this.viewContentRescanTimer),this.viewContentRescanTimer=null;let f=H(),j=z();if(j&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))j.removeEventListener("click",this.clickHandler,!0);if(j&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))j.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,f&&this.popstateHandler)f.removeEventListener("popstate",this.popstateHandler);if(f&&this.pagehideHandler)f.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon(),this.destroyed=!0}}function hf(f){return S.init(f)}
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- var Q=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],x=new Set(Q),w=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),g={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function v(_){return x.has(_)}function C(_){let E=_.trim();if(E.length===0)return{eventName:E,canonicalEventName:E,isStandard:!1};let S=E.toLowerCase(),N=g[S];if(N)return{eventName:N,canonicalEventName:N,aliasOf:N,isStandard:!0};return{eventName:E,canonicalEventName:E,isStandard:v(E)}}function j(_,E){if(E)return E;if(_==="page_view")return"page_view";if(_==="identify")return"identify";if(w.has(_))return"conversion";return"custom"}function A(){return[...Q]}var Y="bts_analytics_vid",f="bts_analytics_sid",K="bts_analytics_jt",U="bts_analytics_jid",T="bts_analytics_attr",h="bts_site",b="bts_jt",m=300,y="https://api.bts.it.com/v2/website/analytics",u={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},R=["q","query","search"],l=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],p=["_fbp","_fbc"];function L(){return typeof window>"u"?null:window}function $(){return typeof document>"u"?null:document}function J(){return L()?.localStorage??null}function Z(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}function F(_){return _!==null&&typeof _==="object"&&!Array.isArray(_)}function d(_){if(!_)return null;try{let E=JSON.parse(_);if(!F(E))return null;let S=F(E.utm)?Object.fromEntries(Object.entries(E.utm).filter((V)=>typeof V[1]==="string")):{},N=F(E.clickIds)?Object.fromEntries(Object.entries(E.clickIds).filter((V)=>typeof V[1]==="string")):{};return{utm:S,clickIds:N,landingUrl:typeof E.landingUrl==="string"?E.landingUrl:void 0,lastSeenAt:typeof E.lastSeenAt==="string"?E.lastSeenAt:new Date().toISOString(),referrer:typeof E.referrer==="string"?E.referrer:void 0}}catch{return null}}function H(){let _=J();return d(_?.getItem(T)??null)}function s(_){let E=J();if(!E)return;E.setItem(T,JSON.stringify(_))}function q(){let _=L();if(!_)return;return`${_.location.pathname}${_.location.search}`}function z(){return L()?.location.href}function G(){return L()?.location.origin??"https://behindthescenes.com"}function k(){return $()?.referrer||void 0}function I(_){let E=$();if(!E?.cookie)return;let S=`${_}=`,N=E.cookie.split(";").map((D)=>D.trim()).find((D)=>D.startsWith(S));if(!N)return;let V=N.slice(S.length);if(V==="")return;try{return decodeURIComponent(V)}catch{return V}}function o(){let _=I("_ga");if(!_)return;let E=_.split(".");if(E.length>=4&&/^GA\d+$/i.test(E[0]??""))return E.slice(-2).join(".");return W(_)}function a(){let E=$()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),S=E&&"src"in E&&typeof E.src==="string"?E.src:void 0;if(!S)return;try{return W(new URL(S).searchParams.get("id"))}catch{return}}function r(){let _=L(),E=o(),S=a(),N=typeof _?.gtag==="function"||!!S||!!E;if(!N&&!E&&!S)return;return{tagInstalled:N,clientId:E,measurementId:S}}function c(_){if(!_.googleAnalytics||typeof _.googleAnalytics==="boolean")return;return W(_.googleAnalytics.measurementId)}function n(_){if(!_.googleAnalytics)return!1;if(_.googleAnalytics===!0)return!1;return _.googleAnalytics.loadTag!==!1&&!!c(_)}function i(_){let E=L(),S=$();if(!E||!S)return;E.dataLayer=Array.isArray(E.dataLayer)?E.dataLayer:[],E.gtag??=(...V)=>{E.dataLayer?.push(V)};let N=`script[src*="googletagmanager.com/gtag/js?id=${_}"]`;if(!S.querySelector?.(N)){let V=S.createElement("script");V.async=!0,V.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(_)}`,V.setAttribute("data-bts-ga-proxy","true"),(S.head??S.documentElement).appendChild(V)}E.gtag("js",new Date),E.gtag("config",_,{send_page_view:!1})}function t(){let _=L();if(!_)return;let E=typeof Intl<"u"?W(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,S=_.navigator,N=W(S?.language),V=Array.isArray(S?.languages)?S.languages.filter((X)=>typeof X==="string").slice(0,10):[],D=W(S?.userAgent),B={timezone:E,language:N,languages:V.length>0?V:void 0,userAgent:D};return Object.values(B).some((X)=>X!==void 0)?B:void 0}function P(_){let E=M(),S=r();return{event_id:_,ga_client_id:typeof S?.clientId==="string"?S.clientId:void 0,ga_tag_installed:typeof S?.tagInstalled==="boolean"?S.tagInstalled:void 0,attribution:E?{utm:E.utm,clickIds:E.clickIds,...E.clickIds,landingUrl:E.landingUrl,referrer:E.referrer}:void 0,client:t(),googleAnalytics:S,page:{title:$()?.title,url:z()}}}function M(){let _=L();if(!_)return H();let E=new URLSearchParams(_.location.search),S={utm:{},clickIds:{},landingUrl:_.location.href,lastSeenAt:new Date().toISOString(),referrer:k()};for(let D of l){let B=E.get(D);if(!B)continue;if(D.startsWith("utm_")){S.utm[D]=B;continue}S.clickIds[D]=B}for(let D of p){let B=I(D);if(B)S.clickIds[D.replace(/^_/,"")]=B}let N=H(),V={utm:{...N?.utm??{},...S.utm},clickIds:{...N?.clickIds??{},...S.clickIds},landingUrl:S.landingUrl??N?.landingUrl,lastSeenAt:S.lastSeenAt,referrer:S.referrer??N?.referrer};return s(V),V}function W(_){let E=_?.trim();return E?E.slice(0,512):void 0}function e(_){if(!_)return{};if(_ instanceof Headers){let E={};return _.forEach((S,N)=>{E[N]=S}),E}if(Array.isArray(_))return Object.fromEntries(_.map(([E,S])=>[E,String(S)]));return Object.fromEntries(Object.entries(_).map(([E,S])=>[E,String(S)]))}function __(_){let E={...u};if(_.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(_.autoTrack&&typeof _.autoTrack==="object")return{pageviews:_.autoTrack.pageviews??E.pageviews,history:_.autoTrack.pageviews===!1?!1:_.autoTrack.history??E.history,outboundLinks:_.autoTrack.outboundLinks??E.outboundLinks,buttonClicks:_.autoTrack.buttonClicks??E.buttonClicks,formSubmissions:_.autoTrack.formSubmissions??E.formSubmissions,search:_.autoTrack.search??E.search,viewContent:_.autoTrack.viewContent??E.viewContent};if(_.autoPageviews===!1)return{...E,pageviews:!1,history:!1};if(_.autoPageviews===!0)return{...E,pageviews:!0};return E}class O{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanPending=!1;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(_){if(this.siteKey=_.siteKey,this.endpoint=(_.endpoint??y).replace(/\/$/,""),this.debug=_.debug??!1,this.flushIntervalMs=_.flushIntervalMs??m,this.autoTrack=__(_),this.requestHeaders=_.requestHeaders,n(_)){let E=c(_);if(E)i(E)}if(M(),L())this.installAutoTracking()}static init(_){return new O(_)}getVisitorId(){let _=J(),E=_?.getItem(Y);if(E)return E;let S=Z();return _?.setItem(Y,S),S}getSessionId(){let _=J(),E=_?.getItem(f);if(E)return E;let S=Z();return _?.setItem(f,S),S}getPersistedJourneyId(){return J()?.getItem(U)??null}log(..._){if(this.debug)console.log("[@bts/analytics]",..._)}installAutoTracking(){let _=L(),E=$();if(!_||!E)return;if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(_),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},_.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=(S)=>{this.handleAutoClick(S)},this.submitHandler=(S)=>{this.handleAutoSubmit(S)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)E.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)E.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(E);_.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((_,E)=>{for(let S of _){if(!S.isIntersecting||!(S.target instanceof Element))continue;this.trackViewContentElement(S.target),E.unobserve(S.target)}}),this.viewContentObserver}observeViewContentElements(_){if(this.viewContentListenersTornDown||this.destroyed)return;let E=this.getOrCreateViewContentIntersectionObserver();if(!E)return;for(let S of Array.from(_.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has(S))continue;this.observedViewContentElements.add(S),E.observe(S)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanPending)return;this.viewContentRescanPending=!0,queueMicrotask(()=>{if(this.viewContentRescanPending=!1,this.viewContentListenersTornDown||this.destroyed)return;let _=$();if(_)this.observeViewContentElements(_)})}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let _=$();if(_)this.observeViewContentElements(_)}installViewContentTracking(_){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(_),typeof MutationObserver>"u")return;let E=_.body??_.documentElement;if(!E)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(E,{childList:!0,subtree:!0})}trackViewContentElement(_){if(this.trackedViewContentElements.has(_))return;this.trackedViewContentElements.add(_);let E=W(_.getAttribute("data-bts-view-content")||_.getAttribute("data-bts-content-id")||_.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:E,contentTitle:W(_.getAttribute("data-bts-content-title")||_.textContent),contentType:W(_.getAttribute("data-bts-content-type")),elementId:W(_.id)})}patchHistory(_){let E=_.history,S=E.pushState.bind(E),N=E.replaceState.bind(E),V=()=>{M(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return E.pushState=(...D)=>{S(...D),V()},E.replaceState=(...D)=>{N(...D),V()},()=>{E.pushState=S,E.replaceState=N}}handleAutoClick(_){if(_.defaultPrevented)return;let E=_.target;if(!(E instanceof Element))return;if(this.autoTrack.outboundLinks){let N=E.closest("a[href]");if(N instanceof HTMLAnchorElement){let V=W(N.href);if(!V)return;let D=new URL(V,G());if(D.origin!==G()){this.trackStandard("outbound_click",{elementHref:V,elementId:W(N.id),elementText:W(N.textContent),linkHost:D.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let S=E.closest("button,[role='button'],[data-bts-track-click]");if(!(S instanceof Element))return;this.trackStandard("button_click",{elementId:W(S.id),elementName:W(S.getAttribute("name")),elementRole:W(S.getAttribute("role")),elementText:W(S.textContent)})}handleAutoSubmit(_){if(_.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let E=_.target;if(!(E instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(E);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:W(E.action),formId:W(E.id),formMethod:W(E.method),formName:W(E.getAttribute("name"))})}trackSearchForm(_){if((_.method||"get").toLowerCase()!=="get")return;let S=this.extractSearchQuery(_);if(!S)return;this.trackStandard("search",{autoCaptured:!0,formAction:W(_.action),formId:W(_.id),formName:W(_.getAttribute("name")),queryKey:S.key,searchQuery:S.value})}extractSearchQuery(_){try{let S=new FormData(_);for(let N of R){let V=S.get(N);if(typeof V==="string"){let D=W(V);if(D)return{key:N,value:D}}}}catch{}let E=_.elements;for(let S of R){let N=E?.namedItem?.(S),V=N&&"value"in N?N.value:void 0;if(typeof V==="string"){let D=W(V);if(D)return{key:S,value:D}}}return null}buildEvent(_,E,S,N){let V=N?.path??q(),D=k(),B=Z(),X=P(B);return{eventName:_,eventType:E,path:V,referrer:D,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...S??{},...X,event_id:S?.event_id??S?.eventId??B}}}queueEvent(_,E,S){let N=C(_),V=j(N.canonicalEventName,S),D={...E??{}};if(N.aliasOf)D.originalEventName=_;if(this.queue.push(this.buildEvent(N.eventName,V,D)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(_,E){let S=`${this.endpoint}${_}`;this.log("POST",S,E);let N=JSON.stringify(E),V=await this.resolveRequestHeaders(_,S,E,N,this.endpoint);return fetch(S,{method:"POST",headers:V,body:N})}async postWebsiteJson(_,E){let S=this.endpoint.replace(/\/analytics$/,""),N=`${S}${_}`;this.log("POST",N,E);let V=JSON.stringify(E),D=await this.resolveRequestHeaders(_,N,E,V,S);return fetch(N,{method:"POST",headers:D,body:V})}async postJsonKeepalive(_,E){let S=`${this.endpoint}${_}`;this.log("POST keepalive",S,E);let N=JSON.stringify(E),V=await this.resolveRequestHeaders(_,S,E,N,this.endpoint);return fetch(S,{method:"POST",headers:V,body:N,keepalive:!0})}async resolveRequestHeaders(_,E,S,N,V=this.endpoint){let D={"Content-Type":"application/json"};if(!this.requestHeaders)return D;let B=typeof this.requestHeaders==="function"?await this.requestHeaders({body:S,bodyText:N,endpoint:V,headers:{...D},path:_,siteKey:this.siteKey,url:E}):this.requestHeaders;return{...D,...e(B)}}async flushBatch(_,E=!1){try{let S=E?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:_}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:_});if(!S.ok)return this.log("flush failed",S.status),!1;return!0}catch(S){return this.log("flush error",S),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let B=[...this.queue];this.queue=[],this.flushBatch(B,!0).then((X)=>{if(!X&&!this.destroyed)this.queue.unshift(...B),this.scheduleFlush()});return}let _=L(),E=_?.navigator?.sendBeacon?.bind(_.navigator);if(!E)return;let S=[...this.queue];this.queue=[];let N=`${this.endpoint}/ingest/batch`,V=JSON.stringify({siteKey:this.siteKey,events:S}),D=new Blob([V],{type:"application/json"});E(N,D)}async flushNow(){if(this.queue.length===0)return;let _=[...this.queue];if(this.queue=[],!await this.flushBatch(_)&&!this.destroyed)this.queue.unshift(..._),this.scheduleFlush()}recordPageView(_){let E=_??q(),S=z()??E??"/";if(S===this.lastTrackedUrl)return;this.lastTrackedUrl=S,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:E})),this.scheduleFlush()}page(_){this.lastTrackedUrl=null,this.recordPageView(_)}track(_,E){this.queueEvent(_,E)}trackStandard(_,E){this.queueEvent(_,E)}identify(_,E){this.queue.push(this.buildEvent("identify","identify",{traits:E??{},userId:_})),this.scheduleFlush()}listStandardEvents(){return A()}async submitContactForm(_){let E=Z(),S=P(E),N=await this.postWebsiteJson("/ghl/leads",{siteKey:this.siteKey,locationId:_.locationId,email:_.email,phone:_.phone,subject:_.subject,body:_.body,name:_.name,firstName:_.firstName,lastName:_.lastName,source:_.source,tags:_.tags,customFields:_.customFields,metadata:{..._.metadata??{},...S}});if(!N.ok)throw Error(`contact form submit failed: ${N.status}`);return await N.json()}async startFunnel(_){let E=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:_??q()});if(!E.ok)throw Error(`journey/start failed: ${E.status}`);let S=await E.json();return J()?.setItem(K,S.journeyToken),J()?.setItem(U,S.journeyId),S}getPersistedJourneyToken(){return J()?.getItem(K)??null}decorateUrl(_,E){let S=E??this.getPersistedJourneyToken(),N=new URL(_,G());if(N.searchParams.set(h,this.siteKey),S)N.searchParams.set(b,S);return N.toString()}async notifyHandoff(_,E){let S=await this.postJson("/journey/handoff",{journeyToken:_,context:E});if(!S.ok)throw Error(`journey/handoff failed: ${S.status}`)}destroy(){this.destroyed=!0,this.viewContentListenersTornDown=!0;let _=L(),E=$();if(E&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))E.removeEventListener("click",this.clickHandler,!0);if(E&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))E.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,_&&this.popstateHandler)_.removeEventListener("popstate",this.popstateHandler);if(_&&this.pagehideHandler)_.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon()}}function N_(_){return O.init(_)}export{A as listStandardWebEvents,N_ as createBTSAnalytics,O as BTSAnalytics};
1
+ var K=["page_view","view_content","search","lead","sign_up","begin_checkout","add_payment_info","purchase","outbound_click","button_click","form_submit"],S="bts_analytics_vid",g="bts_analytics_sid",x="bts_analytics_jt",I="bts_analytics_jid",Y="bts_analytics_attr",b="bts_site",T="bts_jt",p=64,d=300,v="https://api.bts.it.com/v2/website/analytics",l={pageviews:!0,history:!0,outboundLinks:!0,buttonClicks:!0,formSubmissions:!0,search:!0,viewContent:!0},N=["q","query","search"],_=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","fbclid","gclid","gbraid","li_fat_id","msclkid","ttclid","wbraid"],h=["_fbp","_fbc"],n=7776000;var Uf=new Set(K),Vf=new Set(K.map((f)=>f.toLowerCase())),zf=new Set(["lead","sign_up","begin_checkout","add_payment_info","purchase"]),Qf={$pageview:"page_view",checkout_started:"begin_checkout",lead_capture:"lead",purchase_completed:"purchase",registration_complete:"sign_up"};function s(f){let j=f.trim();if(j.length===0)return{eventName:j,canonicalEventName:j,isStandard:!1};let $=j.toLowerCase(),J=Qf[$];if(J)return{eventName:J,canonicalEventName:J,aliasOf:J,isStandard:!0};if(Vf.has($)){let X=$;return{eventName:X,canonicalEventName:X,isStandard:!0}}return{eventName:j,canonicalEventName:j,isStandard:!1}}function o(f,j){if(j)return j;if(f==="page_view")return"page_view";if(f==="identify")return"identify";if(zf.has(f))return"conversion";return"custom"}function r(){return[...K]}function H(){return typeof window>"u"?null:window}function z(){return typeof document>"u"?null:document}function G(){return H()?.localStorage??null}function B(f){let j=z();if(!j?.cookie)return;let $=`${f}=`,J=j.cookie.split(";").map((Z)=>Z.trim()).find((Z)=>Z.startsWith($));if(!J)return;let X=J.slice($.length);if(X==="")return;try{return decodeURIComponent(X)}catch{return X}}function A(f,j){let $=z();if(!$)return;let J=H()?.location.protocol==="https:"?"; Secure":"";$.cookie=`${f}=${encodeURIComponent(j)}; Max-Age=${n}; Path=/; SameSite=Lax${J}`}function Lf(){let f=new Uint32Array(1);if(typeof crypto<"u"&&typeof crypto.getRandomValues==="function")return crypto.getRandomValues(f),String(f[0]);return String(Math.floor(Math.random()*10000000000))}function Gf(f=Date.now()){return`fb.1.${f}.${Lf()}`}function Bf(f,j=Date.now()){return`fb.1.${j}.${f}`}function i(){let f=H();if(!f)return;if(!B("_fbp"))A("_fbp",Gf());let j=new URLSearchParams(f.location.search).get("fbclid");if(j&&!B("_fbc"))A("_fbc",Bf(j))}function D(){let f=H();if(!f)return;return`${f.location.pathname}${f.location.search}`}function k(){return H()?.location.href}function O(){return H()?.location.origin??"https://behindthescenes.com"}function U(){return z()?.referrer||void 0}function q(f){let j=f?.trim();return j?j.slice(0,512):void 0}function c(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function Mf(f){if(!f)return null;try{let j=JSON.parse(f);if(!c(j))return null;let $=c(j.utm)?Object.fromEntries(Object.entries(j.utm).filter((X)=>typeof X[1]==="string")):{},J=c(j.clickIds)?Object.fromEntries(Object.entries(j.clickIds).filter((X)=>typeof X[1]==="string")):{};return{utm:$,clickIds:J,landingUrl:typeof j.landingUrl==="string"?j.landingUrl:void 0,lastSeenAt:typeof j.lastSeenAt==="string"?j.lastSeenAt:new Date().toISOString(),referrer:typeof j.referrer==="string"?j.referrer:void 0}}catch{return null}}function a(){let f=G();return Mf(f?.getItem(Y)??null)}function Pf(f){let j=G();if(!j)return;let $=JSON.stringify(f);if(j.getItem(Y)===$)return;j.setItem(Y,$)}var E=null,C=null;function t(){E=null,C=null}function Wf(f){let j=new URLSearchParams(f.location.search),$=_.map((X)=>`${X}=${j.get(X)??""}`).join("&"),J=h.map((X)=>`${X}=${B(X)??""}`).join("&");return`${f.location.href} ${$} ${J}`}function R(){let f=H();if(!f)return a();let j=Wf(f);if(j===E&&C)return C;let $=new URLSearchParams(f.location.search),J={utm:{},clickIds:{},landingUrl:f.location.href,lastSeenAt:new Date().toISOString(),referrer:U()};for(let F of _){let V=$.get(F);if(!V)continue;if(F.startsWith("utm_")){J.utm[F]=V;continue}J.clickIds[F]=V}for(let F of h){let V=B(F);if(V)J.clickIds[F.replace(/^_/,"")]=V}let X=a(),Z={utm:{...X?.utm??{},...J.utm},clickIds:{...X?.clickIds??{},...J.clickIds},landingUrl:J.landingUrl??X?.landingUrl,lastSeenAt:J.lastSeenAt,referrer:J.referrer??X?.referrer};return Pf(Z),E=j,C=Z,Z}function M(){return i(),R()}function e(f){let j={...l};if(f.autoTrack===!1)return{pageviews:!1,history:!1,outboundLinks:!1,buttonClicks:!1,formSubmissions:!1,search:!1,viewContent:!1};if(f.autoTrack&&typeof f.autoTrack==="object")return{pageviews:f.autoTrack.pageviews??j.pageviews,history:f.autoTrack.pageviews===!1?!1:f.autoTrack.history??j.history,outboundLinks:f.autoTrack.outboundLinks??j.outboundLinks,buttonClicks:f.autoTrack.buttonClicks??j.buttonClicks,formSubmissions:f.autoTrack.formSubmissions??j.formSubmissions,search:f.autoTrack.search??j.search,viewContent:f.autoTrack.viewContent??j.viewContent};if(f.autoPageviews===!1)return{...j,pageviews:!1,history:!1};if(f.autoPageviews===!0)return{...j,pageviews:!0};return j}function Kf(){let f=B("_ga");if(!f)return;let j=f.split(".");if(j.length>=4&&/^GA\d+$/i.test(j[0]??""))return j.slice(-2).join(".");return q(f)}function Yf(){let j=z()?.querySelector?.('script[src*="googletagmanager.com/gtag/js?id="]'),$=j&&"src"in j&&typeof j.src==="string"?j.src:void 0;if(!$)return;try{return q(new URL($).searchParams.get("id"))}catch{return}}function ff(){let f=H(),j=Kf(),$=Yf(),J=typeof f?.gtag==="function"||!!$||!!j;if(!J&&!j&&!$)return;return{tagInstalled:J,clientId:j,measurementId:$}}function w(f){if(!f.googleAnalytics||typeof f.googleAnalytics==="boolean")return;return q(f.googleAnalytics.measurementId)}function jf(f){if(!f.googleAnalytics)return!1;if(f.googleAnalytics===!0)return!1;return f.googleAnalytics.loadTag!==!1&&!!w(f)}function $f(f){let j=H(),$=z();if(!j||!$)return;j.dataLayer=Array.isArray(j.dataLayer)?j.dataLayer:[],j.gtag??=(...X)=>{j.dataLayer?.push(X)};let J=`script[src*="googletagmanager.com/gtag/js?id=${f}"]`;if(!$.querySelector?.(J)){let X=$.createElement("script");X.async=!0,X.src=`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(f)}`,X.setAttribute("data-bts-ga-proxy","true"),($.head??$.documentElement).appendChild(X)}j.gtag("js",new Date),j.gtag("config",f,{send_page_view:!1})}function Df(){let f=H();if(!f)return;let j=typeof Intl<"u"?q(Intl.DateTimeFormat().resolvedOptions().timeZone):void 0,$=f.navigator,J=q($?.language),X=Array.isArray($?.languages)?$.languages.filter((V)=>typeof V==="string").slice(0,10):[],Z=q($?.userAgent),F={timezone:j,language:J,languages:X.length>0?X:void 0,userAgent:Z};return Object.values(F).some((V)=>V!==void 0)?F:void 0}function y(f){let j=M(),$=ff();return{event_id:f,ga_client_id:typeof $?.clientId==="string"?$.clientId:void 0,ga_tag_installed:typeof $?.tagInstalled==="boolean"?$.tagInstalled:void 0,attribution:j?{utm:j.utm,clickIds:j.clickIds,...j.clickIds,landingUrl:j.landingUrl,referrer:j.referrer}:void 0,client:Df(),googleAnalytics:$,page:{title:z()?.title,url:k()}}}function Jf(f){if(!f)return{};if(f instanceof Headers){let j={};return f.forEach(($,J)=>{j[J]=$}),j}if(Array.isArray(f))return Object.fromEntries(f.map(([j,$])=>[j,String($)]));return Object.fromEntries(Object.entries(f).map(([j,$])=>[j,String($)]))}function Xf(f){return f!==null&&typeof f==="object"&&!Array.isArray(f)}function kf(f,j){if(typeof j==="bigint")return j.toString();if(typeof j==="function"||typeof j==="symbol")return;if(j instanceof Date)return j.toISOString();if(ArrayBuffer.isView(j))return;return j}function P(f){try{return JSON.stringify(f,kf)}catch(j){let $=j instanceof Error?j.message:"unknown";throw Error(`Failed to serialize request body: ${$}`)}}function Q(f){let j=f?.trim();return j&&j.length>0?j:void 0}function u(f,j=0){if(j>8)return;if(f===null||f===void 0)return;if(typeof f==="string"||typeof f==="number"||typeof f==="boolean")return f;if(typeof f==="bigint")return f.toString();if(f instanceof Date)return f.toISOString();if(ArrayBuffer.isView(f)||typeof f==="function"||typeof f==="symbol")return;if(Array.isArray(f)){let J=f.map((X)=>u(X,j+1)).filter((X)=>X!==void 0);return J.length>0?J:void 0}if(!Xf(f))return;let $={};for(let[J,X]of Object.entries(f)){let Z=u(X,j+1);if(Z!==void 0)$[J]=Z}return Object.keys($).length>0?$:void 0}function Zf(f){if(!f)return;let j=u(f);return Xf(j)?j:void 0}function L(f,j,$){if($===void 0)return;f[j]=$}function qf(f,j,$){let J={siteKey:f,locationId:j.locationId};if(L(J,"email",Q(j.email)),L(J,"phone",Q(j.phone)),L(J,"subject",Q(j.subject)),L(J,"body",Q(j.body)),L(J,"message",Q(j.message)),L(J,"name",Q(j.name)),L(J,"firstName",Q(j.firstName)),L(J,"lastName",Q(j.lastName)),L(J,"source",Q(j.source)),j.tags&&j.tags.length>0)J.tags=j.tags;if(j.customFields&&Object.keys(j.customFields).length>0)J.customFields=j.customFields;let X=Q(j.pipelineId),Z=Q(j.pipelineStageId);if(X&&Z){if(J.pipelineId=X,J.pipelineStageId=Z,L(J,"opportunityName",Q(j.opportunityName)),typeof j.monetaryValue==="number"&&Number.isFinite(j.monetaryValue))J.monetaryValue=j.monetaryValue}let F=Zf({...j.metadata??{},...$});if(F)J.metadata=F;return J}function W(){if(typeof crypto<"u"&&typeof crypto.randomUUID==="function")return crypto.randomUUID();return`v_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}class m{siteKey;endpoint;debug;flushIntervalMs;autoTrack;requestHeaders;queue=[];flushTimer=null;destroyed=!1;lastTrackedUrl=null;unpatchHistory=null;clickHandler=null;submitHandler=null;pagehideHandler=null;popstateHandler=null;viewContentObserver=null;viewContentMutationObserver=null;viewContentRescanTimer=null;viewContentListenersTornDown=!1;observedViewContentElements=new WeakSet;trackedViewContentElements=new WeakSet;constructor(f){if(this.siteKey=f.siteKey,this.endpoint=(f.endpoint??v).replace(/\/$/,""),this.debug=f.debug??!1,this.flushIntervalMs=f.flushIntervalMs??d,this.autoTrack=e(f),this.requestHeaders=f.requestHeaders,jf(f)){let j=w(f);if(j)$f(j)}if(H())this.installAutoTracking()}static init(f){return new m(f)}getVisitorId(){let f=G(),j=f?.getItem(S);if(j)return j;let $=W();return f?.setItem(S,$),$}getSessionId(){let f=G(),j=f?.getItem(g);if(j)return j;let $=W();return f?.setItem(g,$),$}getPersistedJourneyId(){return G()?.getItem(I)??null}log(...f){if(this.debug)console.log("[@bts/analytics]",...f)}installAutoTracking(){let f=H(),j=z();if(!f||!j)return;if(Object.values(this.autoTrack).some(Boolean))M();if(this.autoTrack.pageviews)this.recordPageView();if(this.autoTrack.history)this.unpatchHistory=this.patchHistory(f),this.popstateHandler=()=>{this.recordPageView(),this.rescanViewContentAfterNavigation()},f.addEventListener("popstate",this.popstateHandler);if(this.clickHandler=($)=>{this.handleAutoClick($)},this.submitHandler=($)=>{this.handleAutoSubmit($)},this.pagehideHandler=()=>{this.viewContentListenersTornDown=!0,this.flushWithBeacon(),this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null},this.autoTrack.outboundLinks||this.autoTrack.buttonClicks)j.addEventListener("click",this.clickHandler,!0);if(this.autoTrack.formSubmissions||this.autoTrack.search)j.addEventListener("submit",this.submitHandler,!0);if(this.autoTrack.viewContent)this.installViewContentTracking(j);f.addEventListener("pagehide",this.pagehideHandler)}getOrCreateViewContentIntersectionObserver(){if(typeof IntersectionObserver>"u"||this.viewContentListenersTornDown)return null;if(this.viewContentObserver)return this.viewContentObserver;return this.viewContentObserver=new IntersectionObserver((f,j)=>{for(let $ of f){if(!$.isIntersecting||!($.target instanceof Element))continue;this.trackViewContentElement($.target),j.unobserve($.target)}}),this.viewContentObserver}observeViewContentElements(f){if(this.viewContentListenersTornDown||this.destroyed)return;let j=this.getOrCreateViewContentIntersectionObserver();if(!j)return;for(let $ of Array.from(f.querySelectorAll("[data-bts-view-content]"))){if(this.observedViewContentElements.has($))continue;this.observedViewContentElements.add($),j.observe($)}}scheduleViewContentRescanFromMutations(){if(this.viewContentListenersTornDown)return;if(this.viewContentRescanTimer)return;this.viewContentRescanTimer=setTimeout(()=>{if(this.viewContentRescanTimer=null,this.viewContentListenersTornDown||this.destroyed)return;let f=z();if(f)this.observeViewContentElements(f)},p)}rescanViewContentAfterNavigation(){if(!this.autoTrack.viewContent)return;if(this.viewContentListenersTornDown)return;let f=z();if(f)this.observeViewContentElements(f)}installViewContentTracking(f){if(typeof IntersectionObserver>"u")return;if(this.observeViewContentElements(f),typeof MutationObserver>"u")return;let j=f.body??f.documentElement;if(!j)return;this.viewContentMutationObserver=new MutationObserver(()=>{this.scheduleViewContentRescanFromMutations()}),this.viewContentMutationObserver.observe(j,{childList:!0,subtree:!0})}trackViewContentElement(f){if(this.trackedViewContentElements.has(f))return;this.trackedViewContentElements.add(f);let j=q(f.getAttribute("data-bts-view-content")||f.getAttribute("data-bts-content-id")||f.id);this.trackStandard("view_content",{autoCaptured:!0,contentId:j,contentTitle:q(f.getAttribute("data-bts-content-title")||f.textContent),contentType:q(f.getAttribute("data-bts-content-type")),elementId:q(f.id)})}patchHistory(f){let j=f.history,$=j.pushState.bind(j),J=j.replaceState.bind(j),X=()=>{R(),this.recordPageView(),this.rescanViewContentAfterNavigation()};return j.pushState=(...Z)=>{$(...Z),X()},j.replaceState=(...Z)=>{J(...Z),X()},()=>{j.pushState=$,j.replaceState=J}}handleAutoClick(f){if(f.defaultPrevented)return;let j=f.target;if(!(j instanceof Element))return;if(this.autoTrack.outboundLinks){let J=j.closest("a[href]");if(J instanceof HTMLAnchorElement){let X=q(J.href);if(!X)return;let Z=new URL(X,O());if(Z.origin!==O()){this.trackStandard("outbound_click",{elementHref:X,elementId:q(J.id),elementText:q(J.textContent),linkHost:Z.hostname});return}}}if(!this.autoTrack.buttonClicks)return;let $=j.closest("button,[role='button'],[data-bts-track-click]");if(!($ instanceof Element))return;this.trackStandard("button_click",{elementId:q($.id),elementName:q($.getAttribute("name")),elementRole:q($.getAttribute("role")),elementText:q($.textContent)})}handleAutoSubmit(f){if(f.defaultPrevented||!this.autoTrack.formSubmissions&&!this.autoTrack.search)return;let j=f.target;if(!(j instanceof HTMLFormElement))return;if(this.autoTrack.search)this.trackSearchForm(j);if(!this.autoTrack.formSubmissions)return;this.trackStandard("form_submit",{formAction:q(j.action),formId:q(j.id),formMethod:q(j.method),formName:q(j.getAttribute("name"))})}trackSearchForm(f){if((f.method||"get").toLowerCase()!=="get")return;let $=this.extractSearchQuery(f);if(!$)return;this.trackStandard("search",{autoCaptured:!0,formAction:q(f.action),formId:q(f.id),formName:q(f.getAttribute("name")),queryKey:$.key,searchQuery:$.value})}extractSearchQuery(f){try{let $=new FormData(f);for(let J of N){let X=$.get(J);if(typeof X==="string"){let Z=q(X);if(Z)return{key:J,value:Z}}}}catch{}let j=f.elements;for(let $ of N){let J=j?.namedItem?.($),X=J&&"value"in J?J.value:void 0;if(typeof X==="string"){let Z=q(X);if(Z)return{key:$,value:Z}}}return null}buildEvent(f,j,$,J){let X=J?.path??D(),Z=U(),F=W(),V=y(F);return{eventName:f,eventType:j,path:X,referrer:Z,occurredAt:new Date().toISOString(),journeyId:this.getPersistedJourneyId()??void 0,visitorId:this.getVisitorId(),sessionId:this.getSessionId(),properties:{...$??{},...V,event_id:$?.event_id??$?.eventId??F}}}queueEvent(f,j,$){if(this.destroyed)return;let J=s(f),X=o(J.canonicalEventName,$),Z={...j??{}};if(J.aliasOf)Z.originalEventName=f;if(this.queue.push(this.buildEvent(J.eventName,X,Z)),this.queue.length>=50){this.flushNow();return}this.scheduleFlush()}scheduleFlush(){if(this.flushTimer)return;this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flushNow()},this.flushIntervalMs)}async postJson(f,j){let $=`${this.endpoint}${f}`;this.log("POST",$,j);let J=P(j),X=await this.resolveRequestHeaders(f,$,j,J,this.endpoint);return fetch($,{method:"POST",headers:X,body:J})}async postWebsiteJson(f,j){let $=this.endpoint.replace(/\/analytics$/,""),J=`${$}${f}`;this.log("POST",J,j);let X=P(j),Z=await this.resolveRequestHeaders(f,J,j,X,$);return fetch(J,{method:"POST",headers:Z,body:X})}async postJsonKeepalive(f,j){let $=`${this.endpoint}${f}`;this.log("POST keepalive",$,j);let J=P(j),X=await this.resolveRequestHeaders(f,$,j,J,this.endpoint);return fetch($,{method:"POST",headers:X,body:J,keepalive:!0})}async resolveRequestHeaders(f,j,$,J,X=this.endpoint){let Z={"Content-Type":"application/json"};if(!this.requestHeaders)return Z;let F=typeof this.requestHeaders==="function"?await this.requestHeaders({body:$,bodyText:J,endpoint:X,headers:{...Z},path:f,siteKey:this.siteKey,url:j}):this.requestHeaders;return{...Z,...Jf(F)}}async flushBatch(f,j=!1){try{let $=j?await this.postJsonKeepalive("/ingest/batch",{siteKey:this.siteKey,events:f}):await this.postJson("/ingest/batch",{siteKey:this.siteKey,events:f});if(!$.ok)return this.log("flush failed",$.status),!1;return!0}catch($){return this.log("flush error",$),!1}}flushWithBeacon(){if(this.queue.length===0)return;if(this.requestHeaders){let V=[...this.queue];this.queue=[],this.flushBatch(V,!0).then((Ff)=>{if(!Ff&&!this.destroyed)this.queue.unshift(...V),this.scheduleFlush()});return}let f=H(),j=f?.navigator?.sendBeacon?.bind(f.navigator);if(!j)return;let $=[...this.queue];this.queue=[];let J=`${this.endpoint}/ingest/batch`,X=P({siteKey:this.siteKey,events:$}),Z=new Blob([X],{type:"application/json"});if(!j(J,Z))this.queue.unshift(...$)}async flushNow(){if(this.destroyed)return;if(this.queue.length===0)return;let f=[...this.queue];if(this.queue=[],!await this.flushBatch(f)&&!this.destroyed)this.queue.unshift(...f),this.scheduleFlush()}recordPageView(f){let j=f??D(),$=k()??j??"/";if($===this.lastTrackedUrl)return;this.lastTrackedUrl=$,this.queue.push(this.buildEvent("page_view","page_view",{autoCaptured:!0},{path:j})),this.scheduleFlush()}page(f){this.lastTrackedUrl=null,this.recordPageView(f)}track(f,j){this.queueEvent(f,j)}trackStandard(f,j){this.queueEvent(f,j)}identify(f,j){if(this.destroyed)return;this.queue.push(this.buildEvent("identify","identify",{traits:j??{},userId:f})),this.scheduleFlush()}listStandardEvents(){return r()}async submitContactForm(f){let j=W(),$=y(j),J=await this.postWebsiteJson("/ghl/leads",qf(this.siteKey,f,$));if(!J.ok)throw Error(`contact form submit failed: ${J.status}`);return await J.json()}async startFunnel(f){M();let j=await this.postJson("/journey/start",{siteKey:this.siteKey,entryPath:f??D()});if(!j.ok)throw Error(`journey/start failed: ${j.status}`);let $=await j.json();return G()?.setItem(x,$.journeyToken),G()?.setItem(I,$.journeyId),$}getPersistedJourneyToken(){return G()?.getItem(x)??null}decorateUrl(f,j){let $=j??this.getPersistedJourneyToken(),J=new URL(f,O());if(J.searchParams.set(b,this.siteKey),$)J.searchParams.set(T,$);let X=R();if(X){for(let[Z,F]of Object.entries(X.utm??{}))if(F)J.searchParams.set(Z,F);for(let[Z,F]of Object.entries(X.clickIds??{}))if(F)J.searchParams.set(Z,F)}return J.toString()}async notifyHandoff(f,j){let $=await this.postJson("/journey/handoff",{journeyToken:f,context:j});if(!$.ok)throw Error(`journey/handoff failed: ${$.status}`)}destroy(){if(this.viewContentListenersTornDown=!0,t(),this.viewContentRescanTimer)clearTimeout(this.viewContentRescanTimer),this.viewContentRescanTimer=null;let f=H(),j=z();if(j&&this.clickHandler&&(this.autoTrack.outboundLinks||this.autoTrack.buttonClicks))j.removeEventListener("click",this.clickHandler,!0);if(j&&this.submitHandler&&(this.autoTrack.formSubmissions||this.autoTrack.search))j.removeEventListener("submit",this.submitHandler,!0);if(this.viewContentObserver?.disconnect(),this.viewContentObserver=null,this.viewContentMutationObserver?.disconnect(),this.viewContentMutationObserver=null,f&&this.popstateHandler)f.removeEventListener("popstate",this.popstateHandler);if(f&&this.pagehideHandler)f.removeEventListener("pagehide",this.pagehideHandler);if(this.flushTimer)clearTimeout(this.flushTimer),this.flushTimer=null;this.unpatchHistory?.(),this.unpatchHistory=null,this.flushWithBeacon(),this.destroyed=!0}}function Bj(f){return m.init(f)}export{r as listStandardWebEvents,Bj as createBTSAnalytics,m as BTSAnalytics};
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@behindthescenes/analytics",
3
- "version": "0.0.12",
4
- "generatedAt": "2026-04-30T05:05:49.933Z",
3
+ "version": "0.0.14",
4
+ "generatedAt": "2026-05-20T12:14:18.095Z",
5
5
  "artifacts": {
6
6
  "browser": "browser/browser.js",
7
7
  "cjs": "cjs/index.js",
@@ -1,15 +1,3 @@
1
- import { BTSAnalytics, createBTSAnalytics, listStandardWebEvents, type BTSAnalyticsEventType, type BTSAnalyticsContactFormInput, type BTSAnalyticsContactFormResult, type BTSAnalyticsInit, type BTSAnalyticsRequestContext, type BTSAnalyticsRequestHeaders, type BTSAnalyticsStandardEventName } from "./index";
2
- declare global {
3
- interface Window {
4
- BTSAnalytics?: {
5
- BTSAnalytics: typeof BTSAnalytics;
6
- createBTSAnalytics: typeof createBTSAnalytics;
7
- listStandardWebEvents: typeof listStandardWebEvents;
8
- };
9
- createBTSAnalytics?: typeof createBTSAnalytics;
10
- btsAnalytics?: BTSAnalytics;
11
- btsDataLayer?: Array<ArrayLike<unknown>>;
12
- bts?: (...args: unknown[]) => void;
13
- }
14
- }
15
- export { BTSAnalytics, createBTSAnalytics, listStandardWebEvents, type BTSAnalyticsEventType, type BTSAnalyticsContactFormInput, type BTSAnalyticsContactFormResult, type BTSAnalyticsInit, type BTSAnalyticsRequestContext, type BTSAnalyticsRequestHeaders, type BTSAnalyticsStandardEventName, };
1
+ import { BTSAnalytics, createBTSAnalytics, listStandardWebEvents } from "./index";
2
+ export { BTSAnalytics, createBTSAnalytics, listStandardWebEvents };
3
+ export type { BTSAnalyticsContactFormInput, BTSAnalyticsContactFormResult, BTSAnalyticsEventType, BTSAnalyticsInit, BTSAnalyticsPayloadProperties, BTSAnalyticsRequestContext, BTSAnalyticsRequestHeaders, BTSAnalyticsStandardEventName, } from "./types/index.types";
@@ -0,0 +1,32 @@
1
+ /** Canonical standard web events accepted by `trackStandard` and documented for external users. */
2
+ declare const STANDARD_WEB_EVENTS: readonly ["page_view", "view_content", "search", "lead", "sign_up", "begin_checkout", "add_payment_info", "purchase", "outbound_click", "button_click", "form_submit"];
3
+ /** Browser storage keys are stable because published SDK versions may read values written by older bundles. */
4
+ declare const STORAGE_VISITOR = "bts_analytics_vid";
5
+ declare const STORAGE_SESSION = "bts_analytics_sid";
6
+ declare const STORAGE_JOURNEY = "bts_analytics_jt";
7
+ declare const STORAGE_JOURNEY_ID = "bts_analytics_jid";
8
+ declare const STORAGE_ATTRIBUTION = "bts_analytics_attr";
9
+ declare const QUERY_SITE = "bts_site";
10
+ declare const QUERY_JOURNEY = "bts_jt";
11
+ /** Debounce DOM-wide view-content rescans after mutations (ms). */
12
+ declare const VIEW_CONTENT_MUTATION_RESCAN_MS = 64;
13
+ declare const DEFAULT_FLUSH_INTERVAL_MS = 300;
14
+ /** Production BTS website analytics endpoint used when consumers do not override `endpoint`. */
15
+ declare const DEFAULT_ENDPOINT = "https://api.bts.it.com/v2/website/analytics";
16
+ /** Default browser auto-capture behavior for newly initialized SDK instances. */
17
+ declare const DEFAULT_AUTO_TRACK: {
18
+ readonly pageviews: true;
19
+ readonly history: true;
20
+ readonly outboundLinks: true;
21
+ readonly buttonClicks: true;
22
+ readonly formSubmissions: true;
23
+ readonly search: true;
24
+ readonly viewContent: true;
25
+ };
26
+ declare const SEARCH_QUERY_KEYS: readonly ["q", "query", "search"];
27
+ /** Query parameters that should be persisted for attribution across later events and journeys. */
28
+ declare const ATTRIBUTION_QUERY_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "fbclid", "gclid", "gbraid", "li_fat_id", "msclkid", "ttclid", "wbraid"];
29
+ /** Browser cookies copied into attribution context for server-side conversion forwarding. */
30
+ declare const ATTRIBUTION_COOKIE_KEYS: readonly ["_fbp", "_fbc"];
31
+ declare const META_COOKIE_MAX_AGE_SECONDS: number;
32
+ export { STANDARD_WEB_EVENTS, STORAGE_VISITOR, STORAGE_SESSION, STORAGE_JOURNEY, STORAGE_JOURNEY_ID, STORAGE_ATTRIBUTION, QUERY_SITE, QUERY_JOURNEY, VIEW_CONTENT_MUTATION_RESCAN_MS, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_ENDPOINT, DEFAULT_AUTO_TRACK, SEARCH_QUERY_KEYS, ATTRIBUTION_QUERY_KEYS, ATTRIBUTION_COOKIE_KEYS, META_COOKIE_MAX_AGE_SECONDS, };
@@ -1,12 +1,10 @@
1
- export declare const STANDARD_WEB_EVENTS: readonly ["page_view", "view_content", "search", "lead", "sign_up", "begin_checkout", "add_payment_info", "purchase", "outbound_click", "button_click", "form_submit"];
2
- export type BTSAnalyticsStandardEventName = (typeof STANDARD_WEB_EVENTS)[number];
3
- export type BTSAnalyticsEventType = "page_view" | "custom" | "identify" | "conversion";
4
- export declare function isStandardWebEventName(eventName: string): eventName is BTSAnalyticsStandardEventName;
1
+ import type * as BTSEventTypes from "./types/BTSEvents.types";
2
+ export declare function isStandardWebEventName(eventName: string): eventName is BTSEventTypes.BTSAnalyticsStandardEventName;
5
3
  export declare function normalizeEventName(eventName: string): {
6
4
  eventName: string;
7
5
  canonicalEventName: string;
8
- aliasOf?: BTSAnalyticsStandardEventName;
6
+ aliasOf?: BTSEventTypes.BTSAnalyticsStandardEventName;
9
7
  isStandard: boolean;
10
8
  };
11
- export declare function resolveEventType(eventName: string, explicitType?: BTSAnalyticsEventType): BTSAnalyticsEventType;
12
- export declare function listStandardWebEvents(): BTSAnalyticsStandardEventName[];
9
+ export declare function resolveEventType(eventName: string, explicitType?: BTSEventTypes.BTSAnalyticsEventType): BTSEventTypes.BTSAnalyticsEventType;
10
+ export declare function listStandardWebEvents(): BTSEventTypes.BTSAnalyticsStandardEventName[];
@@ -1,66 +1,6 @@
1
- import { listStandardWebEvents, type BTSAnalyticsEventType, type BTSAnalyticsStandardEventName } from "./events";
2
- type AutoTrackConfig = {
3
- pageviews: boolean;
4
- history: boolean;
5
- outboundLinks: boolean;
6
- buttonClicks: boolean;
7
- formSubmissions: boolean;
8
- search: boolean;
9
- viewContent: boolean;
10
- };
11
- export type BTSAnalyticsRequestContext = {
12
- body: unknown;
13
- bodyText: string;
14
- /** Base URL for the outgoing request (e.g. analytics `.../website/analytics` vs website `.../website`). */
15
- endpoint: string;
16
- headers: Record<string, string>;
17
- path: string;
18
- siteKey: string;
19
- url: string;
20
- };
21
- export type BTSAnalyticsRequestHeaders = HeadersInit | ((request: BTSAnalyticsRequestContext) => HeadersInit | Promise<HeadersInit>);
22
- export type BTSAnalyticsInit = {
23
- siteKey: string;
24
- /** Defaults to the production BTS website analytics endpoint. Override for staging/dev. */
25
- endpoint?: string;
26
- autoPageviews?: boolean;
27
- autoTrack?: boolean | Partial<AutoTrackConfig>;
28
- debug?: boolean;
29
- flushIntervalMs?: number;
30
- /**
31
- * Optional GA4 compatibility mode. When a measurement ID is provided, the SDK loads the Google tag with
32
- * `send_page_view: false` so GA scanners can detect an installed tag while BTS forwards events server-side.
33
- */
34
- googleAnalytics?: boolean | {
35
- loadTag?: boolean;
36
- measurementId?: string;
37
- };
38
- requestHeaders?: BTSAnalyticsRequestHeaders;
39
- };
40
- export type BTSAnalyticsPayloadProperties = Record<string, unknown>;
41
- /**
42
- * Contact form payload for BTS website lead capture.
43
- *
44
- * The backend requires at least one of `email` or `phone`; validation is enforced server-side.
45
- */
46
- export type BTSAnalyticsContactFormInput = {
47
- locationId: string;
48
- email?: string;
49
- phone?: string;
50
- subject?: string;
51
- body?: string;
52
- name?: string;
53
- firstName?: string;
54
- lastName?: string;
55
- source?: string;
56
- tags?: string[];
57
- customFields?: Record<string, string | number | boolean>;
58
- metadata?: Record<string, unknown>;
59
- };
60
- export type BTSAnalyticsContactFormResult = {
61
- ok: boolean;
62
- data?: unknown;
63
- };
1
+ import { listStandardWebEvents } from "./events";
2
+ import type * as BTSEventTypes from "./types/BTSEvents.types";
3
+ import type * as BTSSDKTypes from "./types/BTSSDK.types";
64
4
  export declare class BTSAnalytics {
65
5
  private siteKey;
66
6
  private endpoint;
@@ -79,12 +19,12 @@ export declare class BTSAnalytics {
79
19
  private popstateHandler;
80
20
  private viewContentObserver;
81
21
  private viewContentMutationObserver;
82
- private viewContentRescanPending;
22
+ private viewContentRescanTimer;
83
23
  private viewContentListenersTornDown;
84
24
  private observedViewContentElements;
85
25
  private trackedViewContentElements;
86
- constructor(init: BTSAnalyticsInit);
87
- static init(opts: BTSAnalyticsInit): BTSAnalytics;
26
+ constructor(init: BTSSDKTypes.BTSAnalyticsInit);
27
+ static init(opts: BTSSDKTypes.BTSAnalyticsInit): BTSAnalytics;
88
28
  getVisitorId(): string;
89
29
  getSessionId(): string;
90
30
  private getPersistedJourneyId;
@@ -115,11 +55,11 @@ export declare class BTSAnalytics {
115
55
  flushNow(): Promise<void>;
116
56
  private recordPageView;
117
57
  page(path?: string): void;
118
- track(eventName: string, properties?: BTSAnalyticsPayloadProperties): void;
119
- trackStandard(eventName: BTSAnalyticsStandardEventName, properties?: BTSAnalyticsPayloadProperties): void;
120
- identify(userId: string, traits?: BTSAnalyticsPayloadProperties): void;
121
- listStandardEvents(): BTSAnalyticsStandardEventName[];
122
- submitContactForm(input: BTSAnalyticsContactFormInput): Promise<BTSAnalyticsContactFormResult>;
58
+ track(eventName: string, properties?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
59
+ trackStandard(eventName: BTSEventTypes.BTSAnalyticsStandardEventName, properties?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
60
+ identify(userId: string, traits?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
61
+ listStandardEvents(): BTSEventTypes.BTSAnalyticsStandardEventName[];
62
+ submitContactForm(input: BTSEventTypes.BTSAnalyticsContactFormInput): Promise<BTSEventTypes.BTSAnalyticsContactFormResult>;
123
63
  /** Start a cross-site funnel; persists journey token for decorateUrl. */
124
64
  startFunnel(entryPath?: string): Promise<{
125
65
  journeyId: string;
@@ -127,11 +67,12 @@ export declare class BTSAnalytics {
127
67
  expiresAt: number;
128
68
  }>;
129
69
  getPersistedJourneyToken(): string | null;
130
- /** Append site key + journey token to a BTS URL (checkout, join, etc.). */
70
+ /** Append site key, journey token, UTMs, and click IDs to a BTS URL (checkout, join, etc.). */
131
71
  decorateUrl(url: string, journeyToken?: string): string;
132
72
  /** Call from BTS after accepting the journey (optional; server can also infer). */
133
73
  notifyHandoff(journeyToken: string, context?: Record<string, unknown>): Promise<void>;
134
74
  destroy(): void;
135
75
  }
136
- export declare function createBTSAnalytics(init: BTSAnalyticsInit): BTSAnalytics;
137
- export { listStandardWebEvents, type BTSAnalyticsEventType, type BTSAnalyticsStandardEventName, };
76
+ export declare function createBTSAnalytics(init: BTSSDKTypes.BTSAnalyticsInit): BTSAnalytics;
77
+ export { listStandardWebEvents };
78
+ export type { BTSAnalyticsContactFormInput, BTSAnalyticsContactFormResult, BTSAnalyticsEventType, BTSAnalyticsInit, BTSAnalyticsPayloadProperties, BTSAnalyticsRequestContext, BTSAnalyticsRequestHeaders, BTSAnalyticsStandardEventName, } from "./types/index.types";
@@ -0,0 +1,20 @@
1
+ import type { BTSAnalytics, createBTSAnalytics, listStandardWebEvents } from "../index";
2
+ declare global {
3
+ interface Window {
4
+ /** SDK namespace installed by the hosted browser bundle. */
5
+ BTSAnalytics?: {
6
+ BTSAnalytics: typeof BTSAnalytics;
7
+ createBTSAnalytics: typeof createBTSAnalytics;
8
+ listStandardWebEvents: typeof listStandardWebEvents;
9
+ };
10
+ /** Convenience factory installed on `window` by the hosted browser bundle. */
11
+ createBTSAnalytics?: typeof createBTSAnalytics;
12
+ /** Active browser SDK instance created by the tag loader. */
13
+ btsAnalytics?: BTSAnalytics;
14
+ /** Queue consumed by the hosted tag before `window.bts` is ready. */
15
+ btsDataLayer?: Array<ArrayLike<unknown>>;
16
+ /** Hosted tag command function, compatible with queued `btsDataLayer` commands. */
17
+ bts?: (...args: unknown[]) => void;
18
+ }
19
+ }
20
+ export {};
@@ -0,0 +1,78 @@
1
+ import { STANDARD_WEB_EVENTS } from "../constants";
2
+ /** Canonical BTS web analytics event names supported by `trackStandard`. */
3
+ export type BTSAnalyticsStandardEventName = (typeof STANDARD_WEB_EVENTS)[number];
4
+ /** Backend event classification used for routing, reporting, and conversion handling. */
5
+ export type BTSAnalyticsEventType = "page_view" | "custom" | "identify" | "conversion";
6
+ /** Arbitrary JSON-compatible event metadata supplied by the site or captured by the SDK. */
7
+ export type BTSAnalyticsPayloadProperties = Record<string, unknown>;
8
+ /**
9
+ * Contact form payload for BTS website lead capture.
10
+ *
11
+ * The backend requires at least one of `email` or `phone`; validation is enforced server-side.
12
+ */
13
+ export type BTSAnalyticsContactFormInput = {
14
+ /** GoHighLevel location ID that receives the lead. */
15
+ locationId: string;
16
+ /** Lead email address; either `email` or `phone` is expected by the backend. */
17
+ email?: string;
18
+ /** Lead phone number; either `phone` or `email` is expected by the backend. */
19
+ phone?: string;
20
+ /** Optional message subject for contact-style forms. */
21
+ subject?: string;
22
+ /** Optional free-form message body. */
23
+ body?: string;
24
+ /** Optional free-form message alias accepted by the backend contact form route. */
25
+ message?: string;
26
+ /** Full contact name when the form captures a single name field. */
27
+ name?: string;
28
+ /** Contact first name when the form captures split name fields. */
29
+ firstName?: string;
30
+ /** Contact last name when the form captures split name fields. */
31
+ lastName?: string;
32
+ /** Caller-defined lead source label forwarded to BTS/GHL. */
33
+ source?: string;
34
+ /** Optional tags to attach to the lead. */
35
+ tags?: string[];
36
+ /** Optional custom fields supported by the configured GHL location. */
37
+ customFields?: Record<string, string | number | boolean>;
38
+ /** Extra metadata merged with the SDK's attribution and browser context. */
39
+ metadata?: Record<string, unknown>;
40
+ /** Optional GHL pipeline ID for creating an opportunity with the contact. */
41
+ pipelineId?: string;
42
+ /** Optional GHL pipeline stage ID; required when `pipelineId` is provided. */
43
+ pipelineStageId?: string;
44
+ /** Optional opportunity title when pipeline fields are provided. */
45
+ opportunityName?: string;
46
+ /** Optional opportunity value when pipeline fields are provided. */
47
+ monetaryValue?: number;
48
+ };
49
+ /** Result returned by the BTS website lead endpoint. */
50
+ export type BTSAnalyticsContactFormResult = {
51
+ ok: boolean;
52
+ data?: unknown;
53
+ };
54
+ /** Attribution snapshot persisted in browser storage across page views and funnels. */
55
+ export type StoredAttribution = {
56
+ /** Latest known UTM fields keyed by their original query parameter names. */
57
+ utm: Record<string, string>;
58
+ /** Latest known ad/click identifiers, including Meta cookies normalized without a leading underscore. */
59
+ clickIds: Record<string, string>;
60
+ /** URL where the current attribution snapshot was last observed. */
61
+ landingUrl?: string;
62
+ /** ISO timestamp for the last attribution refresh. */
63
+ lastSeenAt: string;
64
+ /** Document referrer captured with the attribution snapshot. */
65
+ referrer?: string;
66
+ };
67
+ /** Internal queued event shape sent to `/ingest/batch`. */
68
+ export type QueuedAnalyticsEvent = {
69
+ eventName: string;
70
+ eventType: BTSAnalyticsEventType;
71
+ path?: string;
72
+ referrer?: string;
73
+ occurredAt: string;
74
+ journeyId?: string;
75
+ visitorId: string;
76
+ sessionId: string;
77
+ properties: BTSAnalyticsPayloadProperties;
78
+ };
@@ -0,0 +1,42 @@
1
+ import type * as BTSEventTypes from "./BTSEvents.types";
2
+ import type * as BTSSDKTypes from "./BTSSDK.types";
3
+ /** Public instance contract implemented by `BTSAnalytics`. */
4
+ export interface IBTSAnalyticsSDK {
5
+ /** Returns the persisted anonymous visitor ID, creating one when needed. */
6
+ getVisitorId(): string;
7
+ /** Returns the persisted browser session ID, creating one when needed. */
8
+ getSessionId(): string;
9
+ /** Immediately attempts to send queued analytics events. */
10
+ flushNow(): Promise<void>;
11
+ /** Manually records a page view, optionally overriding the current path. */
12
+ page(path?: string): void;
13
+ /** Tracks a custom or standard event name with optional properties. */
14
+ track(eventName: string, properties?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
15
+ /** Tracks one of the documented standard web events. */
16
+ trackStandard(eventName: BTSEventTypes.BTSAnalyticsStandardEventName, properties?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
17
+ /** Associates subsequent analytics activity with a known user ID and traits. */
18
+ identify(userId: string, traits?: BTSEventTypes.BTSAnalyticsPayloadProperties): void;
19
+ /** Lists the standard web events supported by `trackStandard`. */
20
+ listStandardEvents(): BTSEventTypes.BTSAnalyticsStandardEventName[];
21
+ /** Sends a BTS website contact form lead to the configured GHL location. */
22
+ submitContactForm(input: BTSEventTypes.BTSAnalyticsContactFormInput): Promise<BTSEventTypes.BTSAnalyticsContactFormResult>;
23
+ /** Starts a cross-site journey and persists the returned journey identifiers. */
24
+ startFunnel(entryPath?: string): Promise<{
25
+ journeyId: string;
26
+ journeyToken: string;
27
+ expiresAt: number;
28
+ }>;
29
+ /** Returns a stored journey token from a previous `startFunnel` call. */
30
+ getPersistedJourneyToken(): string | null;
31
+ /** Adds the BTS site key and journey token to a destination URL. */
32
+ decorateUrl(url: string, journeyToken?: string): string;
33
+ /** Notifies BTS that a cross-site journey was accepted by the destination. */
34
+ notifyHandoff(journeyToken: string, context?: Record<string, unknown>): Promise<void>;
35
+ /** Flushes pending data where possible and removes browser listeners. */
36
+ destroy(): void;
37
+ }
38
+ /** Constructor contract for SDK factories that expose a static `init` helper. */
39
+ export interface BTSAnalyticsConstructor {
40
+ new (init: BTSSDKTypes.BTSAnalyticsInit): IBTSAnalyticsSDK;
41
+ init(opts: BTSSDKTypes.BTSAnalyticsInit): IBTSAnalyticsSDK;
42
+ }
@@ -0,0 +1,63 @@
1
+ /** Granular auto-capture switches used by the browser SDK. */
2
+ export type AutoTrackConfig = {
3
+ /** Emit an initial `page_view` when the SDK is created. */
4
+ pageviews: boolean;
5
+ /** Patch browser history APIs and listen for `popstate` to emit SPA `page_view` events. */
6
+ history: boolean;
7
+ /** Capture clicks on anchors that navigate away from the current origin. */
8
+ outboundLinks: boolean;
9
+ /** Capture clicks on buttons, button roles, and explicit `data-bts-track-click` elements. */
10
+ buttonClicks: boolean;
11
+ /** Capture form submit metadata. */
12
+ formSubmissions: boolean;
13
+ /** Capture GET search forms using common query field names. */
14
+ search: boolean;
15
+ /** Capture visible elements marked with `data-bts-view-content`. */
16
+ viewContent: boolean;
17
+ };
18
+ /** Context passed to custom request header resolvers. */
19
+ export type BTSAnalyticsRequestContext = {
20
+ /** Parsed request body before JSON serialization. */
21
+ body: unknown;
22
+ /** Serialized JSON request body that will be sent over the network. */
23
+ bodyText: string;
24
+ /** Base URL for the outgoing request, e.g. analytics `.../website/analytics` vs website `.../website`. */
25
+ endpoint: string;
26
+ /** Default headers that will be sent unless overridden. */
27
+ headers: Record<string, string>;
28
+ /** Request path relative to `endpoint`. */
29
+ path: string;
30
+ /** Public BTS site key configured for this SDK instance. */
31
+ siteKey: string;
32
+ /** Full request URL. */
33
+ url: string;
34
+ };
35
+ /** Static headers or a callback used to sign/augment SDK network requests. */
36
+ export type BTSAnalyticsRequestHeaders = HeadersInit | ((request: BTSAnalyticsRequestContext) => HeadersInit | Promise<HeadersInit>);
37
+ /** Options accepted by `createBTSAnalytics` and the `BTSAnalytics` constructor. */
38
+ export type BTSAnalyticsInit = {
39
+ /** Public site key from the BTS website integration settings. */
40
+ siteKey: string;
41
+ /** Defaults to the production BTS website analytics endpoint. Override for staging/dev. */
42
+ endpoint?: string;
43
+ /** Legacy page-view switch kept for existing integrations; use `autoTrack.pageviews` for new code. */
44
+ autoPageviews?: boolean;
45
+ /** Disable all auto-capture with `false`, or override individual auto-capture switches. */
46
+ autoTrack?: boolean | Partial<AutoTrackConfig>;
47
+ /** Enables console logging for SDK network requests and flush failures. */
48
+ debug?: boolean;
49
+ /** Time in milliseconds before queued events are flushed automatically. */
50
+ flushIntervalMs?: number;
51
+ /**
52
+ * Optional GA4 compatibility mode. When a measurement ID is provided, the SDK loads the Google tag with
53
+ * `send_page_view: false` so GA scanners can detect an installed tag while BTS forwards events server-side.
54
+ */
55
+ googleAnalytics?: boolean | {
56
+ /** Set to `false` to report GA context without injecting the Google tag script. */
57
+ loadTag?: boolean;
58
+ /** GA4 measurement ID, e.g. `G-XXXXXXXXXX`. */
59
+ measurementId?: string;
60
+ };
61
+ /** Optional static headers or async resolver for signing SDK requests. */
62
+ requestHeaders?: BTSAnalyticsRequestHeaders;
63
+ };
@@ -0,0 +1,6 @@
1
+ export type * from "./BTSEvents.types";
2
+ export type * from "./BTSSDK.interfaces";
3
+ export type * from "./BTSSDK.types";
4
+ export type * as BTSBrowserTypes from "./BTSBrowser.types";
5
+ export type * as BTSEventTypes from "./BTSEvents.types";
6
+ export type * as BTSSDKTypes from "./BTSSDK.types";
@@ -0,0 +1,5 @@
1
+ import type * as BTSEventTypes from "../types/BTSEvents.types";
2
+ declare function clearAttributionReadCache(): void;
3
+ declare function readCurrentAttribution(): BTSEventTypes.StoredAttribution | null;
4
+ declare function captureCurrentAttributionForTracking(): BTSEventTypes.StoredAttribution | null;
5
+ export { captureCurrentAttributionForTracking, clearAttributionReadCache, readCurrentAttribution, };
@@ -0,0 +1,3 @@
1
+ import type * as BTSSDKTypes from "../types/BTSSDK.types";
2
+ declare function createAutoTrackConfig(init: BTSSDKTypes.BTSAnalyticsInit): BTSSDKTypes.AutoTrackConfig;
3
+ export { createAutoTrackConfig };
@@ -0,0 +1,7 @@
1
+ /** Safely returns `window` when the SDK is running in a browser. */
2
+ declare function safeWindow(): Window | null;
3
+ /** Safely returns `document` without making module imports fail in SSR/non-browser runtimes. */
4
+ declare function safeDocument(): Document | null;
5
+ /** Safely returns browser localStorage when it is available. */
6
+ declare function safeStorage(): Storage | null;
7
+ export { safeDocument, safeStorage, safeWindow, };
@@ -0,0 +1,4 @@
1
+ import type * as BTSEventTypes from "../types/BTSEvents.types";
2
+ declare function readClientContext(): Record<string, unknown> | undefined;
3
+ declare function buildContextProperties(eventId: string): BTSEventTypes.BTSAnalyticsPayloadProperties;
4
+ export { buildContextProperties, readClientContext, };
@@ -0,0 +1,3 @@
1
+ declare function readCookie(name: string): string | undefined;
2
+ declare function writeCookie(name: string, value: string): void;
3
+ export { readCookie, writeCookie, };
@@ -0,0 +1,6 @@
1
+ import type * as BTSSDKTypes from "../types/BTSSDK.types";
2
+ declare function readGoogleAnalyticsContext(): Record<string, unknown> | undefined;
3
+ declare function resolveGoogleAnalyticsMeasurementId(init: BTSSDKTypes.BTSAnalyticsInit): string | undefined;
4
+ declare function shouldLoadGoogleAnalyticsTag(init: BTSSDKTypes.BTSAnalyticsInit): boolean;
5
+ declare function installGoogleAnalyticsTag(measurementId: string): void;
6
+ export { installGoogleAnalyticsTag, readGoogleAnalyticsContext, resolveGoogleAnalyticsMeasurementId, shouldLoadGoogleAnalyticsTag, };
@@ -0,0 +1,3 @@
1
+ import type * as BTSEventTypes from "../types/BTSEvents.types";
2
+ declare function buildGhlLeadRequestBody(siteKey: string, input: BTSEventTypes.BTSAnalyticsContactFormInput, context: Record<string, unknown>): Record<string, unknown>;
3
+ export { buildGhlLeadRequestBody };
@@ -0,0 +1,2 @@
1
+ declare function normalizeHeaders(headers?: HeadersInit): Record<string, string>;
2
+ export { normalizeHeaders };
@@ -0,0 +1,6 @@
1
+ declare function safeJsonStringify(value: unknown): string;
2
+ declare function nonEmptyString(value: string | undefined): string | undefined;
3
+ declare function sanitizeJsonValue(value: unknown, depth?: number): unknown;
4
+ declare function sanitizeJsonRecord(value: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
5
+ declare function appendIfDefined(target: Record<string, unknown>, key: string, value: unknown): void;
6
+ export { appendIfDefined, nonEmptyString, safeJsonStringify, sanitizeJsonRecord, sanitizeJsonValue, };
@@ -0,0 +1,4 @@
1
+ declare function createMetaBrowserId(now?: number): string;
2
+ declare function createMetaClickId(fbclid: string, now?: number): string;
3
+ declare function ensureMetaPixelCookies(): void;
4
+ export { createMetaBrowserId, createMetaClickId, ensureMetaPixelCookies, };
@@ -0,0 +1,6 @@
1
+ declare function currentPath(): string | undefined;
2
+ declare function currentUrl(): string | undefined;
3
+ declare function currentOrigin(): string;
4
+ declare function currentReferrer(): string | undefined;
5
+ declare function sanitizeText(value: string | null | undefined): string | undefined;
6
+ export { currentOrigin, currentPath, currentReferrer, currentUrl, sanitizeText, };
@@ -0,0 +1,2 @@
1
+ declare function randomId(): string;
2
+ export { randomId };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@behindthescenes/analytics",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "Browser analytics SDK for BTS external-site event tracking and attribution.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",