@kryptonhq/analytics 0.1.6 → 0.1.9

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.
package/README.md CHANGED
@@ -1,136 +1,77 @@
1
1
  # @kryptonhq/analytics
2
2
 
3
- Krypton Analytics JavaScript SDK.
4
-
5
- ## Install (npm)
6
-
7
- ```bash
8
- npm install @kryptonhq/analytics
9
- ```
10
-
11
- ```ts
12
- import { Krypton } from "@kryptonhq/analytics";
13
-
14
- const krypton = new Krypton({
15
- apiKey: "kapi_xxx",
16
- endpoint: "https://ingest.yourdomain.com",
17
- autoPageview: true,
18
- heatmap: true,
19
- consentRequired: true,
20
- showConsentBanner: true,
21
- });
22
-
23
- krypton.track("signup_clicked", { plan: "pro" });
24
- ```
3
+ Krypton Analytics JavaScript SDK — privacy-first analytics tracking.
25
4
 
26
5
  ## Install (CDN, script tag)
27
6
 
28
- Use jsDelivr:
29
-
30
7
  ```html
31
8
  <script defer src="https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js"></script>
32
9
  <script>
33
- window.addEventListener("DOMContentLoaded", function () {
34
- var krypton = window.KryptonAnalytics.init({
10
+ window.addEventListener("load", function () {
11
+ window.krypton = window.KryptonAnalytics.init({
35
12
  apiKey: "kapi_xxx",
36
13
  endpoint: "https://ingest.yourdomain.com",
37
14
  autoPageview: true,
38
15
  heatmap: true,
39
16
  consentRequired: true,
40
17
  showConsentBanner: true
41
- });
42
-
43
- krypton.track("page_loaded");
44
- });
18
+ })
19
+ })
45
20
  </script>
46
21
  ```
47
22
 
48
23
  The CDN build exposes a global: `window.KryptonAnalytics`.
49
24
 
50
- ## Consent (default deny + categories)
51
-
52
- The SDK supports category-level consent:
53
-
54
- - `analytics`
55
- - `heatmaps`
56
- - `geo` (browser geolocation, if granted by user)
25
+ ## Install (npm)
57
26
 
58
- Example:
27
+ ```bash
28
+ npm install @kryptonhq/analytics
29
+ ```
59
30
 
60
31
  ```ts
61
- import { Krypton } from "@kryptonhq/analytics";
32
+ import { createKrypton } from "@kryptonhq/analytics";
62
33
 
63
- const krypton = new Krypton({
34
+ const krypton = createKrypton({
64
35
  apiKey: "kapi_xxx",
65
36
  endpoint: "https://ingest.yourdomain.com",
37
+ autoPageview: true,
66
38
  heatmap: true,
67
- consentRequired: true, // default deny
68
- showConsentBanner: true, // built-in popup
39
+ consentRequired: true,
40
+ showConsentBanner: true,
69
41
  });
70
42
 
71
- // Optional manual control
72
- krypton.setConsent({
73
- analytics: true,
74
- heatmaps: false,
75
- geo: false,
76
- });
43
+ krypton.track("signup", { plan: "pro" });
77
44
  ```
78
45
 
79
- ### GA-style bootstrap snippet (single paste)
46
+ ## Consent (default deny + categories)
80
47
 
81
- ```html
82
- <script>
83
- (function (w, d, s, u, n) {
84
- w[n] = w[n] || function () { (w[n].q = w[n].q || []).push(arguments); };
85
- w[n].l = +new Date();
86
- var js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
87
- js.async = 1;
88
- js.src = u;
89
- js.onload = function () {
90
- var cfg = w[n].cfg;
91
- w[n].client = w.KryptonAnalytics.init(cfg);
92
- var q = w[n].q || [];
93
- for (var i = 0; i < q.length; i++) {
94
- var args = q[i];
95
- if (args[0] === "track") w[n].client.track(args[1], args[2]);
96
- }
97
- };
98
- fjs.parentNode.insertBefore(js, fjs);
99
- })(window, document, "script", "https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js", "krypton");
100
-
101
- krypton.cfg = {
102
- apiKey: "kapi_xxx",
103
- endpoint: "https://ingest.yourdomain.com",
104
- autoPageview: true,
105
- heatmap: true
106
- };
107
-
108
- krypton("track", "landing_view");
109
- </script>
110
- ```
48
+ The SDK supports category-level consent:
111
49
 
112
- ## Publish to npm
50
+ - `analytics` pageviews and custom events
51
+ - `heatmaps` — click and scroll interaction maps
113
52
 
114
- This repository includes a GitHub Actions workflow at:
53
+ When `consentRequired: true` and `showConsentBanner: true`, a built-in consent popup is shown automatically. No data is collected until the user grants consent.
115
54
 
116
- - `.github/workflows/publish-sdk.yml`
55
+ Geolocation is resolved server-side from the request IP (no browser Geolocation API needed).
117
56
 
118
- It triggers on:
57
+ ### Manual consent control
119
58
 
120
- - Manual run (`workflow_dispatch`)
121
- - Tag push matching `sdk-v*` (example: `sdk-v0.1.1`)
59
+ ```ts
60
+ krypton.setConsent({ analytics: true, heatmaps: false });
122
61
 
123
- Required GitHub secret:
62
+ krypton.grantConsent(); // grant all
63
+ krypton.revokeConsent(); // revoke all
124
64
 
125
- - None, when using npm Trusted Publishing (recommended)
65
+ krypton.showConsentBanner(); // re-show the popup
66
+ ```
126
67
 
127
- Publish flow:
68
+ ## API
128
69
 
129
- 1. Configure npm Trusted Publishing for this package/repo in npm settings.
130
- 2. Bump version in `package.json`.
131
- 3. Commit and push.
132
- 4. Create and push tag:
133
- ```bash
134
- git tag sdk-v0.1.1
135
- git push origin sdk-v0.1.1
136
- ```
70
+ ```ts
71
+ krypton.track("event_name", { key: "value" });
72
+ krypton.trackPageview();
73
+ krypton.identify("user-123");
74
+ krypton.flush();
75
+ krypton.shutdown();
76
+ krypton.getConsent(); // { analytics: boolean, heatmaps: boolean }
77
+ ```
@@ -1,21 +1,17 @@
1
- "use strict";var KryptonAnalytics=(()=>{var Z=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Se=Object.prototype.hasOwnProperty;var Ce=(e,t)=>{for(var r in t)Z(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of be(t))!Se.call(e,i)&&i!==r&&Z(e,i,{get:()=>t[i],enumerable:!(n=ke(t,i))||n.enumerable});return e};var Ie=e=>xe(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>$,default:()=>it,init:()=>ye});var v;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(v||(v={}));function Te(e){return e.nodeType===e.ELEMENT_NODE}function Ee(e){var t=e?.host;return t?.shadowRoot===e}function ee(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function Le(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function te(e){try{var t=e.rules||e.cssRules;return t?Le(Array.from(t).map(Re).join("")):null}catch{return null}}function Re(e){var t=e.cssText;if(_e(e))try{t=te(e.styleSheet)||t}catch{}return t}function _e(e){return"styleSheet"in e}var Ne=(function(){function e(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}return e.prototype.getId=function(t){var r;if(!t)return-1;var n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1},e.prototype.getNode=function(t){return this.idNodeMap.get(t)||null},e.prototype.getIds=function(){return Array.from(this.idNodeMap.keys())},e.prototype.getMeta=function(t){return this.nodeMetaMap.get(t)||null},e.prototype.removeNodeFromMap=function(t){var r=this,n=this.getId(t);this.idNodeMap.delete(n),t.childNodes&&t.childNodes.forEach(function(i){return r.removeNodeFromMap(i)})},e.prototype.has=function(t){return this.idNodeMap.has(t)},e.prototype.hasNode=function(t){return this.nodeMetaMap.has(t)},e.prototype.add=function(t,r){var n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var n=this.getNode(t);if(n){var i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)},e.prototype.reset=function(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap},e})();function Oe(e){var t=e.maskInputOptions,r=e.tagName,n=e.type,i=e.value,a=e.maskInputFn,c=i||"";return(t[r.toLowerCase()]||t[n])&&(a?c=a(c):c="*".repeat(c.length)),c}var le="__rrweb_original__";function Ae(e){var t=e.getContext("2d");if(!t)return!0;for(var r=50,n=0;n<e.width;n+=r)for(var i=0;i<e.height;i+=r){var a=t.getImageData,c=le in a?a[le]:a,u=new Uint32Array(c.call(t,n,i,Math.min(r,e.width-n),Math.min(r,e.height-i)).data.buffer);if(u.some(function(o){return o!==0}))return!1}return!0}var Me=1,Pe=new RegExp("[^a-z0-9-_:]"),ue=-2;function De(){return Me++}function Fe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return Pe.test(t)?"div":t}function He(e){return e.cssRules?Array.from(e.cssRules).map(function(t){return t.cssText||""}).join(""):""}function Ue(e){var t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}var q,fe,We=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Be=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,Ke=/^(data:)([^,]*),(.*)/i;function Q(e,t){return(e||"").replace(We,function(r,n,i,a,c,u){var o=i||c||u,f=n||a||"";if(!o)return r;if(!Be.test(o)||Ke.test(o))return"url(".concat(f).concat(o).concat(f,")");if(o[0]==="/")return"url(".concat(f).concat(Ue(t)+o).concat(f,")");var l=t.split("/"),p=o.split("/");l.pop();for(var S=0,w=p;S<w.length;S++){var k=w[S];k!=="."&&(k===".."?l.pop():l.push(k))}return"url(".concat(f).concat(l.join("/")).concat(f,")")})}var qe=/^[^ \t\n\r\u000c]+/,ze=/^[, \t\n\r\u000c]+/;function $e(e,t){if(t.trim()==="")return t;var r=0;function n(f){var l,p=f.exec(t.substring(r));return p?(l=p[0],r+=l.length,l):""}for(var i=[];n(ze),!(r>=t.length);){var a=n(qe);if(a.slice(-1)===",")a=z(e,a.substring(0,a.length-1)),i.push(a);else{var c="";a=z(e,a);for(var u=!1;;){var o=t.charAt(r);if(o===""){i.push((a+c).trim());break}else if(u)o===")"&&(u=!1);else if(o===","){r+=1,i.push((a+c).trim());break}else o==="("&&(u=!0);c+=o,r+=1}}}return i.join(", ")}function z(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function je(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ne(){var e=document.createElement("a");return e.href="",e.href}function Ge(e,t,r,n){return r==="src"||r==="href"&&n&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n&&n[0]!=="#"||r==="background"&&n&&(t==="table"||t==="td"||t==="th")?z(e,n):r==="srcset"&&n?$e(e,n):r==="style"&&n?Q(n,ne()):t==="object"&&r==="data"&&n?z(e,n):n}function Qe(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?e.matches(r):!1}function re(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?re(e.parentNode,t,r):!1;for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var n=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(n===null)return!1;if(typeof t=="string"){if(n.classList.contains(t)||n.closest(".".concat(t)))return!0}else if(re(n,t,!0))return!0;return!!(r&&(n.matches(r)||n.closest(r)))}function Ve(e,t,r){var n=e.contentWindow;if(n){var i=!1,a;try{a=n.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(c),i=!0,t()});return}var u="about:blank";if(n.location.href!==u||e.src===u||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}}function Ye(e,t,r){var n=!1,i;try{i=e.sheet}catch{return}if(!i){var a=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(a),n=!0,t()})}}function Xe(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.inlineStylesheet,f=t.maskInputOptions,l=f===void 0?{}:f,p=t.maskTextFn,S=t.maskInputFn,w=t.dataURLOptions,k=w===void 0?{}:w,x=t.inlineImages,I=t.recordCanvas,T=t.keepIframeSrcFn,h=t.newlyAddedElement,s=h===void 0?!1:h,y=Ze(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:v.Document,childNodes:[],compatMode:e.compatMode}:{type:v.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:v.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return tt(e,{doc:r,blockClass:i,blockSelector:a,inlineStylesheet:o,maskInputOptions:l,maskInputFn:S,dataURLOptions:k,inlineImages:x,recordCanvas:I,keepIframeSrcFn:T,newlyAddedElement:s,rootId:y});case e.TEXT_NODE:return et(e,{maskTextClass:c,maskTextSelector:u,maskTextFn:p,rootId:y});case e.CDATA_SECTION_NODE:return{type:v.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:v.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function Ze(e,t){if(t.hasNode(e)){var r=t.getId(e);return r===1?void 0:r}}function et(e,t){var r,n=t.maskTextClass,i=t.maskTextSelector,a=t.maskTextFn,c=t.rootId,u=e.parentNode&&e.parentNode.tagName,o=e.textContent,f=u==="STYLE"?!0:void 0,l=u==="SCRIPT"?!0:void 0;if(f&&o){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(o=He(e.parentNode.sheet))}catch(p){console.warn("Cannot get CSS styles from text's parentNode. Error: ".concat(p),e)}o=Q(o,ne())}return l&&(o="SCRIPT_PLACEHOLDER"),!f&&!l&&o&&Je(e,n,i)&&(o=a?a(o):o.replace(/[\S]/g,"*")),{type:v.Text,textContent:o||"",isStyle:f,rootId:c}}function tt(e,t){for(var r=t.doc,n=t.blockClass,i=t.blockSelector,a=t.inlineStylesheet,c=t.maskInputOptions,u=c===void 0?{}:c,o=t.maskInputFn,f=t.dataURLOptions,l=f===void 0?{}:f,p=t.inlineImages,S=t.recordCanvas,w=t.keepIframeSrcFn,k=t.newlyAddedElement,x=k===void 0?!1:k,I=t.rootId,T=Qe(e,n,i),h=Fe(e),s={},y=e.attributes.length,A=0;A<y;A++){var E=e.attributes[A];s[E.name]=Ge(r,h,E.name,E.value)}if(h==="link"&&a){var C=Array.from(r.styleSheets).find(function(R){return R.href===e.href}),m=null;C&&(m=te(C)),m&&(delete s.rel,delete s.href,s._cssText=Q(m,C.href))}if(h==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=Q(m,ne()))}if(h==="input"||h==="textarea"||h==="select"){var F=e.value,_=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&F?s.value=Oe({type:s.type,tagName:h,value:F,maskInputOptions:u,maskInputFn:o}):_&&(s.checked=_)}if(h==="option"&&(e.selected&&!u.select?s.selected=!0:delete s.selected),h==="canvas"&&S){if(e.__context==="2d")Ae(e)||(s.rr_dataURL=e.toDataURL(l.type,l.quality));else if(!("__context"in e)){var L=e.toDataURL(l.type,l.quality),M=document.createElement("canvas");M.width=e.width,M.height=e.height;var P=M.toDataURL(l.type,l.quality);L!==P&&(s.rr_dataURL=L)}}if(h==="img"&&p){q||(q=r.createElement("canvas"),fe=q.getContext("2d"));var b=e,N=b.crossOrigin;b.crossOrigin="anonymous";var D=function(){try{q.width=b.naturalWidth,q.height=b.naturalHeight,fe.drawImage(b,0,0),s.rr_dataURL=q.toDataURL(l.type,l.quality)}catch(R){console.warn("Cannot inline img src=".concat(b.currentSrc,"! Error: ").concat(R))}N?s.crossOrigin=N:b.removeAttribute("crossorigin")};b.complete&&b.naturalWidth!==0?D():b.onload=D}if((h==="audio"||h==="video")&&(s.rr_mediaState=e.paused?"paused":"played",s.rr_mediaCurrentTime=e.currentTime),x||(e.scrollLeft&&(s.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(s.rr_scrollTop=e.scrollTop)),T){var U=e.getBoundingClientRect(),W=U.width,O=U.height;s={class:s.class,rr_width:"".concat(W,"px"),rr_height:"".concat(O,"px")}}return h==="iframe"&&!w(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:v.Element,tagName:h,attributes:s,childNodes:[],isSVG:je(e)||void 0,needBlock:T,rootId:I}}function d(e){return e===void 0?"":e.toLowerCase()}function rt(e,t){if(t.comment&&e.type===v.Comment)return!0;if(e.type===v.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&e.attributes.rel==="preload"&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&e.attributes.href.endsWith(".js")))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(d(e.attributes.name).match(/^msapplication-tile(image|color)$/)||d(e.attributes.name)==="application-name"||d(e.attributes.rel)==="icon"||d(e.attributes.rel)==="apple-touch-icon"||d(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&d(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(d(e.attributes.property).match(/^(og|twitter|fb):/)||d(e.attributes.name).match(/^(og|twitter):/)||d(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(d(e.attributes.name)==="robots"||d(e.attributes.name)==="googlebot"||d(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(d(e.attributes.name)==="author"||d(e.attributes.name)==="generator"||d(e.attributes.name)==="framework"||d(e.attributes.name)==="publisher"||d(e.attributes.name)==="progid"||d(e.attributes.property).match(/^article:/)||d(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(d(e.attributes.name)==="google-site-verification"||d(e.attributes.name)==="yandex-verification"||d(e.attributes.name)==="csrf-token"||d(e.attributes.name)==="p:domain_verify"||d(e.attributes.name)==="verify-v1"||d(e.attributes.name)==="verification"||d(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function G(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.skipChild,f=o===void 0?!1:o,l=t.inlineStylesheet,p=l===void 0?!0:l,S=t.maskInputOptions,w=S===void 0?{}:S,k=t.maskTextFn,x=t.maskInputFn,I=t.slimDOMOptions,T=t.dataURLOptions,h=T===void 0?{}:T,s=t.inlineImages,y=s===void 0?!1:s,A=t.recordCanvas,E=A===void 0?!1:A,C=t.onSerialize,m=t.onIframeLoad,F=t.iframeLoadTimeout,_=F===void 0?5e3:F,L=t.onStylesheetLoad,M=t.stylesheetLoadTimeout,P=M===void 0?5e3:M,b=t.keepIframeSrcFn,N=b===void 0?function(){return!1}:b,D=t.newlyAddedElement,U=D===void 0?!1:D,W=t.preserveWhiteSpace,O=W===void 0?!0:W,R=Xe(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,dataURLOptions:h,inlineImages:y,recordCanvas:E,keepIframeSrcFn:N,newlyAddedElement:U});if(!R)return console.warn(e,"not serialized"),null;var j;n.hasNode(e)?j=n.getId(e):rt(R,I)||!O&&R.type===v.Text&&!R.isStyle&&!R.textContent.replace(/^\s+|\s+$/gm,"").length?j=ue:j=De();var g=Object.assign(R,{id:j});if(n.add(e,g),j===ue)return null;C&&C(e);var J=!f;if(g.type===v.Element){J=J&&!g.needBlock,delete g.needBlock;var ie=e.shadowRoot;ie&&ee(ie)&&(g.isShadowHost=!0)}if((g.type===v.Document||g.type===v.Element)&&J){I.headWhitespace&&g.type===v.Element&&g.tagName==="head"&&(O=!1);for(var ae={doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:f,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N},V=0,oe=Array.from(e.childNodes);V<oe.length;V++){var Y=oe[V],B=G(Y,ae);B&&g.childNodes.push(B)}if(Te(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var Y=se[X],B=G(Y,ae);B&&(ee(e.shadowRoot)&&(B.isShadow=!0),g.childNodes.push(B))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(g.isShadow=!0),g.type===v.Element&&g.tagName==="iframe"&&Ve(e,function(){var K=e.contentDocument;if(K&&m){var ce=G(K,{doc:K,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});ce&&m(e,ce)}},_),g.type===v.Element&&g.tagName==="link"&&g.attributes.rel==="stylesheet"&&Ye(e,function(){if(L){var K=G(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});K&&L(e,K)}},P),g}function de(e,t){var r=t||{},n=r.mirror,i=n===void 0?new Ne:n,a=r.blockClass,c=a===void 0?"rr-block":a,u=r.blockSelector,o=u===void 0?null:u,f=r.maskTextClass,l=f===void 0?"rr-mask":f,p=r.maskTextSelector,S=p===void 0?null:p,w=r.inlineStylesheet,k=w===void 0?!0:w,x=r.inlineImages,I=x===void 0?!1:x,T=r.recordCanvas,h=T===void 0?!1:T,s=r.maskAllInputs,y=s===void 0?!1:s,A=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,F=r.dataURLOptions,_=r.preserveWhiteSpace,L=r.onSerialize,M=r.onIframeLoad,P=r.iframeLoadTimeout,b=r.onStylesheetLoad,N=r.stylesheetLoadTimeout,D=r.keepIframeSrcFn,U=D===void 0?function(){return!1}:D,W=y===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:y===!1?{password:!0}:y,O=m===!0||m==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:m==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:m===!1?{}:m;return G(e,{doc:e,mirror:i,blockClass:c,blockSelector:o,maskTextClass:l,maskTextSelector:S,skipChild:!1,inlineStylesheet:k,maskInputOptions:W,maskTextFn:A,maskInputFn:E,slimDOMOptions:O,dataURLOptions:F,inlineImages:I,recordCanvas:h,preserveWhiteSpace:_,onSerialize:L,onIframeLoad:M,iframeLoadTimeout:P,onStylesheetLoad:b,stylesheetLoadTimeout:N,keepIframeSrcFn:U,newlyAddedElement:!1})}var nt=/([^\\]):hover/,st=new RegExp(nt.source,"g");function H(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function he(){let e="_krypton_sid";try{if(typeof sessionStorage<"u"){let t=sessionStorage.getItem(e);return t||(t=H(),sessionStorage.setItem(e,t)),t}}catch{}return H()}function pe(){let e="_krypton_did";try{if(typeof localStorage<"u"){let t=localStorage.getItem(e);return t||(t=H(),localStorage.setItem(e,t)),t}}catch{}return H()}function me(){if(typeof window>"u")return{};let e=new URLSearchParams(window.location.search),t={};for(let r of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let n=e.get(r);n&&(t[r]=n)}return t}function ge(){if(typeof window>"u")return"unknown";let e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function ve(e){if(e.id)return`#${e.id}`;let t=[],r=e;for(;r&&r!==document.body;){let n=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let i=r.className.trim().split(/\s+/).slice(0,2).join(".");i&&(n+=`.${i}`)}t.unshift(n),r=r.parentElement}return t.join(" > ")}var $=class{constructor(t){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.lastSnapshotUrl=null;this.heatmapSetup=!1;this.geoRequested=!1;this.geoContext=null;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,debug:!1,disableConfigCache:!1,...t},this.distinctId=H(),this.sessionId=H(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(t){this.warn("setupTracking failed",t)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()?(this.debug("showing consent banner automatically",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner}),this.showConsentBannerWhenReady()):this.debug("skipping consent banner",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner,hasStoredConsent:this.hasStoredConsent()})}catch(t){this.warn("consent banner initialization failed",t)}}))}showConsentBannerWhenReady(t=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}t<=0||setTimeout(()=>this.showConsentBannerWhenReady(t-1),50)}}resolveInitialConsent(){let t=this.loadStoredConsent();return t||{...this.config.consentRequired?{analytics:!1,heatmaps:!1,geo:!1}:{analytics:!0,heatmaps:!!this.config.heatmap,geo:!1},...this.config.consentCategories}}consentStorageKey(){return`_krypton_consent_${this.config.apiKey}`}hasStoredConsent(){try{return typeof localStorage>"u"?!1:!!localStorage.getItem(this.consentStorageKey())}catch{return!1}}loadStoredConsent(){try{if(typeof localStorage>"u")return null;let t=localStorage.getItem(this.consentStorageKey());if(!t)return null;let r=JSON.parse(t);return{analytics:!!r.analytics,heatmaps:!!r.heatmaps,geo:!!r.geo}}catch{return null}}persistConsent(){try{if(typeof localStorage>"u")return;localStorage.setItem(this.consentStorageKey(),JSON.stringify(this.consent))}catch{}}promotePersistentIds(){this.distinctId=pe(),this.sessionId=he()}canTrackAnalytics(){return!!this.consent.analytics}isHeatmapFeatureEnabled(){return!this.config.heatmap||this.configFetched&&!this.serverConfig?.heatmaps_enabled?!1:!!this.consent.heatmaps}async fetchConfig(){if(typeof window>"u")return;let t=`_krypton_config_${this.config.apiKey}`,r=null;if(!this.config.disableConfigCache)try{r=sessionStorage.getItem(t)}catch{r=null}if(r)try{let n=JSON.parse(r);if(n._ts&&Date.now()-n._ts<300*1e3){this.serverConfig=n,this.configFetched=!0,this.debug("config loaded from session cache",n);return}}catch{}try{let n=new AbortController,i=setTimeout(()=>n.abort(),5e3),a=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:n.signal});if(clearTimeout(i),a.ok){let c=await a.json();if(this.serverConfig=c,this.configFetched=!0,this.debug("config fetched from API",c),!this.config.disableConfigCache)try{sessionStorage.setItem(t,JSON.stringify({...c,_ts:Date.now()}))}catch{}}else this.warn(`Config fetch failed (${a.status})`,{endpoint:this.config.endpoint})}catch(n){this.warn("Config fetch failed",n)}}setupTracking(){if(this.flushTimer=setInterval(()=>{this.flush()},this.config.flushInterval),typeof window>"u")return;window.addEventListener("beforeunload",()=>{this.flush()}),this.config.autoPageview&&this.canTrackAnalytics()&&this.trackPageview();let t=history.pushState;history.pushState=(...n)=>{try{t.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("pushState hook failed",i)}};let r=history.replaceState;history.replaceState=(...n)=>{try{r.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(n){this.warn("popstate hook failed",n)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap(),this.consent.geo&&this.captureGeoOnce()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let t=document.createElement("div");t.id="krypton-consent-banner",t.style.cssText=["position:fixed","left:16px","right:16px","bottom:16px","z-index:2147483647","max-width:720px","margin:0 auto","background:#111827","color:#f9fafb","border-radius:12px","padding:16px","box-shadow:0 12px 30px rgba(0,0,0,0.35)","font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif","font-size:14px","line-height:1.4"].join(";");let r=a=>a?"checked":"";t.innerHTML=`
1
+ "use strict";var KryptonAnalytics=(()=>{var l=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var x=(s,e)=>{for(var n in e)l(s,n,{get:e[n],enumerable:!0})},b=(s,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of w(e))!v.call(s,i)&&i!==n&&l(s,i,{get:()=>e[i],enumerable:!(t=y(e,i))||t.enumerable});return s};var k=s=>b(l({},"__esModule",{value:!0}),s);var S={};x(S,{Krypton:()=>r,default:()=>C,init:()=>g});function a(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let e=Math.random()*16|0;return(s==="x"?e:e&3|8).toString(16)})}function d(){let s="_krypton_sid";try{if(typeof sessionStorage<"u"){let e=sessionStorage.getItem(s);return e||(e=a(),sessionStorage.setItem(s,e)),e}}catch{}return a()}function h(){let s="_krypton_did";try{if(typeof localStorage<"u"){let e=localStorage.getItem(s);return e||(e=a(),localStorage.setItem(s,e)),e}}catch{}return a()}function u(){if(typeof window>"u")return{};let s=new URLSearchParams(window.location.search),e={};for(let n of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let t=s.get(n);t&&(e[n]=t)}return e}function p(){if(typeof window>"u")return"unknown";let s=window.innerWidth;return s<768?"mobile":s<1024?"tablet":"desktop"}function f(s){if(s.id)return`#${s.id}`;let e=[],n=s;for(;n&&n!==document.body;){let t=n.tagName.toLowerCase();if(n.id){e.unshift(`#${n.id}`);break}if(n.className&&typeof n.className=="string"){let i=n.className.trim().split(/\s+/).slice(0,2).join(".");i&&(t+=`.${i}`)}e.unshift(t),n=n.parentElement}return e.join(" > ")}var r=class{constructor(e){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.heatmapSetup=!1;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,debug:!1,disableConfigCache:!1,...e},this.distinctId=a(),this.sessionId=a(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(e){this.warn("setupTracking failed",e)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()?(this.debug("showing consent banner automatically",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner}),this.showConsentBannerWhenReady()):this.debug("skipping consent banner",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner,hasStoredConsent:this.hasStoredConsent()})}catch(e){this.warn("consent banner initialization failed",e)}}))}showConsentBannerWhenReady(e=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}e<=0||setTimeout(()=>this.showConsentBannerWhenReady(e-1),50)}}resolveInitialConsent(){let e=this.loadStoredConsent();return e||{...this.config.consentRequired?{analytics:!1,heatmaps:!1}:{analytics:!0,heatmaps:!!this.config.heatmap},...this.config.consentCategories}}consentStorageKey(){return`_krypton_consent_${this.config.apiKey}`}hasStoredConsent(){try{return typeof localStorage>"u"?!1:!!localStorage.getItem(this.consentStorageKey())}catch{return!1}}loadStoredConsent(){try{if(typeof localStorage>"u")return null;let e=localStorage.getItem(this.consentStorageKey());if(!e)return null;let n=JSON.parse(e);return{analytics:!!n.analytics,heatmaps:!!n.heatmaps}}catch{return null}}persistConsent(){try{if(typeof localStorage>"u")return;localStorage.setItem(this.consentStorageKey(),JSON.stringify(this.consent))}catch{}}promotePersistentIds(){this.distinctId=h(),this.sessionId=d()}canTrackAnalytics(){return!!this.consent.analytics}isHeatmapFeatureEnabled(){return!this.config.heatmap||this.configFetched&&!this.serverConfig?.heatmaps_enabled?!1:!!this.consent.heatmaps}async fetchConfig(){if(typeof window>"u")return;let e=`_krypton_config_${this.config.apiKey}`,n=null;if(!this.config.disableConfigCache)try{n=sessionStorage.getItem(e)}catch{n=null}if(n)try{let t=JSON.parse(n);if(t._ts&&Date.now()-t._ts<300*1e3){this.serverConfig=t,this.configFetched=!0,this.debug("config loaded from session cache",t);return}}catch{}try{let t=new AbortController,i=setTimeout(()=>t.abort(),5e3),o=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:t.signal});if(clearTimeout(i),o.ok){let c=await o.json();if(this.serverConfig=c,this.configFetched=!0,this.debug("config fetched from API",c),!this.config.disableConfigCache)try{sessionStorage.setItem(e,JSON.stringify({...c,_ts:Date.now()}))}catch{}}else this.warn(`Config fetch failed (${o.status})`,{endpoint:this.config.endpoint})}catch(t){this.warn("Config fetch failed",t)}}setupTracking(){if(this.flushTimer=setInterval(()=>{this.flush()},this.config.flushInterval),typeof window>"u")return;window.addEventListener("beforeunload",()=>{this.flush()}),this.config.autoPageview&&this.canTrackAnalytics()&&this.trackPageview();let e=history.pushState;history.pushState=(...t)=>{try{e.apply(history,t),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(i){this.warn("pushState hook failed",i)}};let n=history.replaceState;history.replaceState=(...t)=>{try{n.apply(history,t),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(t){this.warn("popstate hook failed",t)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let e=document.createElement("div");e.id="krypton-consent-banner",e.style.cssText=["position:fixed","left:16px","right:16px","bottom:16px","z-index:2147483647","max-width:720px","margin:0 auto","background:#111827","color:#f9fafb","border-radius:12px","padding:16px","box-shadow:0 12px 30px rgba(0,0,0,0.35)","font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif","font-size:14px","line-height:1.4"].join(";");let n=o=>o?"checked":"";e.innerHTML=`
2
2
  <div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
3
3
  <div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
4
4
  <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
5
- <input type="checkbox" id="krypton-consent-analytics" ${r(this.consent.analytics)} />
5
+ <input type="checkbox" id="krypton-consent-analytics" ${n(this.consent.analytics)} />
6
6
  <span><strong>Analytics</strong> (pageviews and custom events)</span>
7
7
  </label>
8
8
  <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
9
- <input type="checkbox" id="krypton-consent-heatmaps" ${r(this.consent.heatmaps)} />
9
+ <input type="checkbox" id="krypton-consent-heatmaps" ${n(this.consent.heatmaps)} />
10
10
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
11
11
  </label>
12
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
13
- <input type="checkbox" id="krypton-consent-geo" ${r(this.consent.geo)} />
14
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
15
- </label>
16
- <div style="display:flex;gap:8px;flex-wrap:wrap">
12
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
17
13
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
18
14
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
19
15
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
20
16
  </div>
21
- `;let n=()=>{t.remove();try{document.body&&(document.body.style.cursor=""),document.documentElement&&(document.documentElement.style.cursor="")}catch{}},i=a=>!!document.getElementById(a)?.checked;t.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{let a={analytics:i("krypton-consent-analytics"),heatmaps:i("krypton-consent-heatmaps"),geo:i("krypton-consent-geo")};n(),setTimeout(()=>this.setConsent(a),0)}),t.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!0,heatmaps:!0,geo:!0}),0)}),t.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!1,heatmaps:!1,geo:!1}),0)}),document.body.appendChild(t)}setConsent(t,r=!0){try{let n={...this.consent};this.consent={analytics:t.analytics??n.analytics,heatmaps:t.heatmaps??n.heatmaps,geo:t.geo??n.geo},r&&this.persistConsent(),!n.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),n.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!n.heatmaps&&this.isHeatmapFeatureEnabled()&&(this.setupHeatmap(),this.captureSnapshot()),n.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[]),!n.geo&&this.consent.geo&&this.captureGeoOnce()}catch(n){this.warn("setConsent failed",n)}}getConsent(){return{...this.consent}}grantConsent(){this.setConsent({analytics:!0,heatmaps:!0,geo:!0})}revokeConsent(){this.setConsent({analytics:!1,heatmaps:!1,geo:!1}),this.eventQueue=[],this.heatmapQueue=[]}identify(t){try{if(this.distinctId=t,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",t)}catch{}}catch(r){this.warn("identify failed",r)}}trackPageview(t){try{if(!this.canTrackAnalytics())return;this.track("$pageview",{...t})}catch(r){this.warn("trackPageview failed",r)}}track(t,r){try{if(!this.canTrackAnalytics())return;let n=me(),i={...r||{}};this.consent.geo&&this.geoContext&&(i.geo=this.geoContext);let a={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:t,timestamp:new Date().toISOString(),properties:i,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:n.utm_source||"",utm_medium:n.utm_medium||"",utm_campaign:n.utm_campaign||"",utm_term:n.utm_term||"",utm_content:n.utm_content||"",device_type:ge(),browser:this.getBrowser(),screen_width:typeof window<"u"?window.screen.width:0,screen_height:typeof window<"u"?window.screen.height:0,session_id:this.sessionId};this.eventQueue.push(a),this.eventQueue.length>=this.config.batchSize&&this.flush()}catch(n){this.warn("track failed",n)}}async flush(){try{await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}catch(t){this.warn("flush failed",t)}}shutdown(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush()}captureGeoOnce(){this.geoRequested||this.consent.geo&&(typeof navigator>"u"||!navigator.geolocation||(this.geoRequested=!0,navigator.geolocation.getCurrentPosition(t=>{let r=(n,i=3)=>Number(n.toFixed(i));this.geoContext={lat:r(t.coords.latitude),lon:r(t.coords.longitude),accuracy_m:Math.round(t.coords.accuracy),captured_at:new Date().toISOString()}},()=>{},{enableHighAccuracy:!1,maximumAge:600*1e3,timeout:5e3})))}async flushEvents(){if(this.eventQueue.length===0)return;let t=this.eventQueue.splice(0,this.eventQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/ingest/batch`,r)||this.eventQueue.length<this.config.batchSize*5&&this.eventQueue.unshift(...t)}async flushHeatmapEvents(){if(this.heatmapQueue.length===0)return;let t=this.heatmapQueue.splice(0,this.heatmapQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/heatmap`,r)||this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...t)}captureSnapshot(){if(typeof window>"u"||typeof document>"u"||!this.isHeatmapFeatureEnabled())return;let t=window.location.href;this.lastSnapshotUrl!==t&&(this.lastSnapshotUrl=t,setTimeout(()=>{try{let r=de(document,{maskAllInputs:!0,blockSelector:"[data-krypton-block]",inlineStylesheet:!0});if(!r)return;let n=JSON.stringify(r),i={api_key:this.config.apiKey,page_url:t,snapshot:n,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,timestamp:new Date().toISOString()};this.safePost(`${this.config.endpoint}/api/v1/snapshot`,i)}catch{}},1e3))}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,this.captureSnapshot(),document.addEventListener("click",n=>{if(this.isHeatmapFeatureEnabled())try{let i=n.target;this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"click",x:n.clientX+window.scrollX,y:n.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:ve(i)})}catch(i){this.warn("heatmap click capture failed",i)}});let t=0,r=null;window.addEventListener("scroll",()=>{if(this.isHeatmapFeatureEnabled())try{let n=window.scrollY||document.documentElement.scrollTop,i=document.documentElement.scrollHeight-window.innerHeight,a=i>0?n/i*100:0;a>t&&(t=a),r&&clearTimeout(r),r=setTimeout(()=>{this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"scroll",scroll_depth:t,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight})},500)}catch(n){this.warn("heatmap scroll capture failed",n)}})}async safePost(t,r){try{let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0});return n.ok?!0:(this.warn(`API request failed (${n.status})`,{url:t}),!1)}catch(n){return this.warn("API request failed",{url:t,err:n}),!1}}warn(t,r){try{console.warn(`${this.logPrefix} ${t}`,r??"")}catch{}}debug(t,r){if(this.config.debug)try{console.log(`${this.logPrefix} ${t}`,r??"")}catch{}}getBrowser(){if(typeof navigator>"u")return"unknown";let t=navigator.userAgent;return t.includes("Firefox")?"Firefox":t.includes("Edg")?"Edge":t.includes("Chrome")?"Chrome":t.includes("Safari")?"Safari":"Other"}};function ye(e){return new $(e)}var we={Krypton:$,init:ye};typeof window<"u"&&(window.KryptonAnalytics=we);var it=we;return Ie(at);})();
17
+ `;let t=()=>{e.remove();try{document.body&&(document.body.style.cursor=""),document.documentElement&&(document.documentElement.style.cursor="")}catch{}},i=o=>!!document.getElementById(o)?.checked;e.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{let o={analytics:i("krypton-consent-analytics"),heatmaps:i("krypton-consent-heatmaps")};t(),setTimeout(()=>this.setConsent(o),0)}),e.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{t(),setTimeout(()=>this.setConsent({analytics:!0,heatmaps:!0}),0)}),e.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{t(),setTimeout(()=>this.setConsent({analytics:!1,heatmaps:!1}),0)}),document.body.appendChild(e)}setConsent(e,n=!0){try{let t={...this.consent};this.consent={analytics:e.analytics??t.analytics,heatmaps:e.heatmaps??t.heatmaps},n&&this.persistConsent(),!t.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),t.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!t.heatmaps&&this.isHeatmapFeatureEnabled()&&this.setupHeatmap(),t.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[])}catch(t){this.warn("setConsent failed",t)}}getConsent(){return{...this.consent}}grantConsent(){this.setConsent({analytics:!0,heatmaps:!0})}revokeConsent(){this.setConsent({analytics:!1,heatmaps:!1}),this.eventQueue=[],this.heatmapQueue=[]}identify(e){try{if(this.distinctId=e,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",e)}catch{}}catch(n){this.warn("identify failed",n)}}trackPageview(e){try{if(!this.canTrackAnalytics())return;this.track("$pageview",{...e})}catch(n){this.warn("trackPageview failed",n)}}track(e,n){try{if(!this.canTrackAnalytics())return;let t=u(),i={...n||{}},o={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:e,timestamp:new Date().toISOString(),properties:i,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:t.utm_source||"",utm_medium:t.utm_medium||"",utm_campaign:t.utm_campaign||"",utm_term:t.utm_term||"",utm_content:t.utm_content||"",device_type:p(),browser:this.getBrowser(),screen_width:typeof window<"u"?window.screen.width:0,screen_height:typeof window<"u"?window.screen.height:0,session_id:this.sessionId};this.eventQueue.push(o),this.eventQueue.length>=this.config.batchSize&&this.flush()}catch(t){this.warn("track failed",t)}}async flush(){try{await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}catch(e){this.warn("flush failed",e)}}shutdown(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush()}async flushEvents(){if(this.eventQueue.length===0)return;let e=this.eventQueue.splice(0,this.eventQueue.length),n={api_key:this.config.apiKey,events:e};await this.safePost(`${this.config.endpoint}/api/v1/ingest/batch`,n)||this.eventQueue.length<this.config.batchSize*5&&this.eventQueue.unshift(...e)}async flushHeatmapEvents(){if(this.heatmapQueue.length===0)return;let e=this.heatmapQueue.splice(0,this.heatmapQueue.length),n={api_key:this.config.apiKey,events:e};await this.safePost(`${this.config.endpoint}/api/v1/heatmap`,n)||this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...e)}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,document.addEventListener("click",t=>{if(this.isHeatmapFeatureEnabled())try{let i=t.target;this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"click",x:t.clientX+window.scrollX,y:t.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:f(i)})}catch(i){this.warn("heatmap click capture failed",i)}});let e=0,n=null;window.addEventListener("scroll",()=>{if(this.isHeatmapFeatureEnabled())try{let t=window.scrollY||document.documentElement.scrollTop,i=document.documentElement.scrollHeight-window.innerHeight,o=i>0?t/i*100:0;o>e&&(e=o),n&&clearTimeout(n),n=setTimeout(()=>{this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"scroll",scroll_depth:e,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight})},500)}catch(t){this.warn("heatmap scroll capture failed",t)}})}async safePost(e,n,t=!0){try{let i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),...t?{keepalive:!0}:{}});return i.ok?!0:(this.warn(`API request failed (${i.status})`,{url:e}),!1)}catch(i){return this.warn("API request failed",{url:e,err:i}),!1}}warn(e,n){try{console.warn(`${this.logPrefix} ${e}`,n??"")}catch{}}debug(e,n){if(this.config.debug)try{console.log(`${this.logPrefix} ${e}`,n??"")}catch{}}getBrowser(){if(typeof navigator>"u")return"unknown";let e=navigator.userAgent;return e.includes("Firefox")?"Firefox":e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Safari")?"Safari":"Other"}};function g(s){return new r(s)}var m={Krypton:r,init:g};typeof window<"u"&&(window.KryptonAnalytics=m);var C=m;return k(S);})();
package/dist/index.d.mts CHANGED
@@ -22,11 +22,10 @@ interface KryptonConfig {
22
22
  /** Disable SDK config cache and fetch project config on each init (default: false) */
23
23
  disableConfigCache?: boolean;
24
24
  }
25
- type ConsentCategory = "analytics" | "heatmaps" | "geo";
25
+ type ConsentCategory = "analytics" | "heatmaps";
26
26
  interface ConsentPreferences {
27
27
  analytics: boolean;
28
28
  heatmaps: boolean;
29
- geo: boolean;
30
29
  }
31
30
  interface EventPayload {
32
31
  project_id: string;
@@ -76,10 +75,7 @@ declare class Krypton {
76
75
  private heatmapQueue;
77
76
  private flushTimer;
78
77
  private initialized;
79
- private lastSnapshotUrl;
80
78
  private heatmapSetup;
81
- private geoRequested;
82
- private geoContext;
83
79
  private consent;
84
80
  private serverConfig;
85
81
  private configFetched;
@@ -97,7 +93,7 @@ declare class Krypton {
97
93
  private isHeatmapFeatureEnabled;
98
94
  private fetchConfig;
99
95
  private setupTracking;
100
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
96
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
101
97
  showConsentBanner(): void;
102
98
  /** Set one or more consent categories and apply changes immediately. */
103
99
  setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
@@ -114,10 +110,8 @@ declare class Krypton {
114
110
  track(eventName: string, properties?: Record<string, unknown>): void;
115
111
  flush(): Promise<void>;
116
112
  shutdown(): void;
117
- private captureGeoOnce;
118
113
  private flushEvents;
119
114
  private flushHeatmapEvents;
120
- private captureSnapshot;
121
115
  private setupHeatmap;
122
116
  private safePost;
123
117
  private warn;
package/dist/index.d.ts CHANGED
@@ -22,11 +22,10 @@ interface KryptonConfig {
22
22
  /** Disable SDK config cache and fetch project config on each init (default: false) */
23
23
  disableConfigCache?: boolean;
24
24
  }
25
- type ConsentCategory = "analytics" | "heatmaps" | "geo";
25
+ type ConsentCategory = "analytics" | "heatmaps";
26
26
  interface ConsentPreferences {
27
27
  analytics: boolean;
28
28
  heatmaps: boolean;
29
- geo: boolean;
30
29
  }
31
30
  interface EventPayload {
32
31
  project_id: string;
@@ -76,10 +75,7 @@ declare class Krypton {
76
75
  private heatmapQueue;
77
76
  private flushTimer;
78
77
  private initialized;
79
- private lastSnapshotUrl;
80
78
  private heatmapSetup;
81
- private geoRequested;
82
- private geoContext;
83
79
  private consent;
84
80
  private serverConfig;
85
81
  private configFetched;
@@ -97,7 +93,7 @@ declare class Krypton {
97
93
  private isHeatmapFeatureEnabled;
98
94
  private fetchConfig;
99
95
  private setupTracking;
100
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
96
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
101
97
  showConsentBanner(): void;
102
98
  /** Set one or more consent categories and apply changes immediately. */
103
99
  setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
@@ -114,10 +110,8 @@ declare class Krypton {
114
110
  track(eventName: string, properties?: Record<string, unknown>): void;
115
111
  flush(): Promise<void>;
116
112
  shutdown(): void;
117
- private captureGeoOnce;
118
113
  private flushEvents;
119
114
  private flushHeatmapEvents;
120
- private captureSnapshot;
121
115
  private setupHeatmap;
122
116
  private safePost;
123
117
  private warn;
package/dist/index.js CHANGED
@@ -24,7 +24,6 @@ __export(index_exports, {
24
24
  createKrypton: () => createKrypton
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
- var import_rrweb_snapshot = require("rrweb-snapshot");
28
27
 
29
28
  // src/utils.ts
30
29
  function generateId() {
@@ -111,10 +110,7 @@ var Krypton = class {
111
110
  this.heatmapQueue = [];
112
111
  this.flushTimer = null;
113
112
  this.initialized = false;
114
- this.lastSnapshotUrl = null;
115
113
  this.heatmapSetup = false;
116
- this.geoRequested = false;
117
- this.geoContext = null;
118
114
  this.serverConfig = null;
119
115
  this.configFetched = false;
120
116
  this.logPrefix = "[Krypton SDK]";
@@ -179,10 +175,9 @@ var Krypton = class {
179
175
  resolveInitialConsent() {
180
176
  const stored = this.loadStoredConsent();
181
177
  if (stored) return stored;
182
- const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
178
+ const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
183
179
  analytics: true,
184
- heatmaps: !!this.config.heatmap,
185
- geo: false
180
+ heatmaps: !!this.config.heatmap
186
181
  };
187
182
  return {
188
183
  ...base,
@@ -208,8 +203,7 @@ var Krypton = class {
208
203
  const parsed = JSON.parse(raw);
209
204
  return {
210
205
  analytics: !!parsed.analytics,
211
- heatmaps: !!parsed.heatmaps,
212
- geo: !!parsed.geo
206
+ heatmaps: !!parsed.heatmaps
213
207
  };
214
208
  } catch {
215
209
  return null;
@@ -301,9 +295,6 @@ var Krypton = class {
301
295
  if (this.config.autoPageview && this.canTrackAnalytics()) {
302
296
  setTimeout(() => this.trackPageview(), 0);
303
297
  }
304
- if (this.isHeatmapFeatureEnabled()) {
305
- setTimeout(() => this.captureSnapshot(), 0);
306
- }
307
298
  } catch (err) {
308
299
  this.warn("pushState hook failed", err);
309
300
  }
@@ -315,9 +306,6 @@ var Krypton = class {
315
306
  if (this.config.autoPageview && this.canTrackAnalytics()) {
316
307
  setTimeout(() => this.trackPageview(), 0);
317
308
  }
318
- if (this.isHeatmapFeatureEnabled()) {
319
- setTimeout(() => this.captureSnapshot(), 0);
320
- }
321
309
  } catch (err) {
322
310
  this.warn("replaceState hook failed", err);
323
311
  }
@@ -327,9 +315,6 @@ var Krypton = class {
327
315
  if (this.config.autoPageview && this.canTrackAnalytics()) {
328
316
  setTimeout(() => this.trackPageview(), 0);
329
317
  }
330
- if (this.isHeatmapFeatureEnabled()) {
331
- setTimeout(() => this.captureSnapshot(), 0);
332
- }
333
318
  } catch (err) {
334
319
  this.warn("popstate hook failed", err);
335
320
  }
@@ -337,11 +322,8 @@ var Krypton = class {
337
322
  if (this.isHeatmapFeatureEnabled()) {
338
323
  this.setupHeatmap();
339
324
  }
340
- if (this.consent.geo) {
341
- this.captureGeoOnce();
342
- }
343
325
  }
344
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
326
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
345
327
  showConsentBanner() {
346
328
  if (typeof document === "undefined") return;
347
329
  if (document.getElementById("krypton-consent-banner")) return;
@@ -376,11 +358,7 @@ var Krypton = class {
376
358
  <input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
377
359
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
378
360
  </label>
379
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
380
- <input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
381
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
382
- </label>
383
- <div style="display:flex;gap:8px;flex-wrap:wrap">
361
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
384
362
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
385
363
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
386
364
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
@@ -401,19 +379,18 @@ var Krypton = class {
401
379
  banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
402
380
  const next = {
403
381
  analytics: readValue("krypton-consent-analytics"),
404
- heatmaps: readValue("krypton-consent-heatmaps"),
405
- geo: readValue("krypton-consent-geo")
382
+ heatmaps: readValue("krypton-consent-heatmaps")
406
383
  };
407
384
  remove();
408
385
  setTimeout(() => this.setConsent(next), 0);
409
386
  });
410
387
  banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
411
388
  remove();
412
- setTimeout(() => this.setConsent({ analytics: true, heatmaps: true, geo: true }), 0);
389
+ setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
413
390
  });
414
391
  banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
415
392
  remove();
416
- setTimeout(() => this.setConsent({ analytics: false, heatmaps: false, geo: false }), 0);
393
+ setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
417
394
  });
418
395
  document.body.appendChild(banner);
419
396
  }
@@ -423,8 +400,7 @@ var Krypton = class {
423
400
  const prev = { ...this.consent };
424
401
  this.consent = {
425
402
  analytics: next.analytics ?? prev.analytics,
426
- heatmaps: next.heatmaps ?? prev.heatmaps,
427
- geo: next.geo ?? prev.geo
403
+ heatmaps: next.heatmaps ?? prev.heatmaps
428
404
  };
429
405
  if (persist) {
430
406
  this.persistConsent();
@@ -440,14 +416,10 @@ var Krypton = class {
440
416
  }
441
417
  if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
442
418
  this.setupHeatmap();
443
- this.captureSnapshot();
444
419
  }
445
420
  if (prev.heatmaps && !this.consent.heatmaps) {
446
421
  this.heatmapQueue = [];
447
422
  }
448
- if (!prev.geo && this.consent.geo) {
449
- this.captureGeoOnce();
450
- }
451
423
  } catch (err) {
452
424
  this.warn("setConsent failed", err);
453
425
  }
@@ -457,11 +429,11 @@ var Krypton = class {
457
429
  }
458
430
  /** Backward-compatible: grant all categories. */
459
431
  grantConsent() {
460
- this.setConsent({ analytics: true, heatmaps: true, geo: true });
432
+ this.setConsent({ analytics: true, heatmaps: true });
461
433
  }
462
434
  /** Backward-compatible: revoke all categories and clear queues. */
463
435
  revokeConsent() {
464
- this.setConsent({ analytics: false, heatmaps: false, geo: false });
436
+ this.setConsent({ analytics: false, heatmaps: false });
465
437
  this.eventQueue = [];
466
438
  this.heatmapQueue = [];
467
439
  }
@@ -498,9 +470,6 @@ var Krypton = class {
498
470
  if (!this.canTrackAnalytics()) return;
499
471
  const utm = getUTMParams();
500
472
  const mergedProperties = { ...properties || {} };
501
- if (this.consent.geo && this.geoContext) {
502
- mergedProperties.geo = this.geoContext;
503
- }
504
473
  const event = {
505
474
  project_id: this.config.apiKey,
506
475
  distinct_id: this.distinctId,
@@ -543,30 +512,6 @@ var Krypton = class {
543
512
  }
544
513
  void this.flush();
545
514
  }
546
- captureGeoOnce() {
547
- if (this.geoRequested) return;
548
- if (!this.consent.geo) return;
549
- if (typeof navigator === "undefined" || !navigator.geolocation) return;
550
- this.geoRequested = true;
551
- navigator.geolocation.getCurrentPosition(
552
- (pos) => {
553
- const round = (value, precision = 3) => Number(value.toFixed(precision));
554
- this.geoContext = {
555
- lat: round(pos.coords.latitude),
556
- lon: round(pos.coords.longitude),
557
- accuracy_m: Math.round(pos.coords.accuracy),
558
- captured_at: (/* @__PURE__ */ new Date()).toISOString()
559
- };
560
- },
561
- () => {
562
- },
563
- {
564
- enableHighAccuracy: false,
565
- maximumAge: 10 * 60 * 1e3,
566
- timeout: 5e3
567
- }
568
- );
569
- }
570
515
  async flushEvents() {
571
516
  if (this.eventQueue.length === 0) return;
572
517
  const events = this.eventQueue.splice(0, this.eventQueue.length);
@@ -595,41 +540,10 @@ var Krypton = class {
595
540
  }
596
541
  }
597
542
  }
598
- captureSnapshot() {
599
- if (typeof window === "undefined" || typeof document === "undefined") return;
600
- if (!this.isHeatmapFeatureEnabled()) return;
601
- const currentUrl = window.location.href;
602
- if (this.lastSnapshotUrl === currentUrl) return;
603
- this.lastSnapshotUrl = currentUrl;
604
- setTimeout(() => {
605
- try {
606
- const node = (0, import_rrweb_snapshot.snapshot)(document, {
607
- maskAllInputs: true,
608
- blockSelector: "[data-krypton-block]",
609
- inlineStylesheet: true
610
- });
611
- if (!node) return;
612
- const snapshotJson = JSON.stringify(node);
613
- const payload = {
614
- api_key: this.config.apiKey,
615
- page_url: currentUrl,
616
- snapshot: snapshotJson,
617
- viewport_width: window.innerWidth,
618
- viewport_height: window.innerHeight,
619
- page_width: document.documentElement.scrollWidth,
620
- page_height: document.documentElement.scrollHeight,
621
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
622
- };
623
- void this.safePost(`${this.config.endpoint}/api/v1/snapshot`, payload);
624
- } catch {
625
- }
626
- }, 1e3);
627
- }
628
543
  setupHeatmap() {
629
544
  if (typeof window === "undefined") return;
630
545
  if (this.heatmapSetup) return;
631
546
  this.heatmapSetup = true;
632
- this.captureSnapshot();
633
547
  document.addEventListener("click", (e) => {
634
548
  if (!this.isHeatmapFeatureEnabled()) return;
635
549
  try {
@@ -685,13 +599,13 @@ var Krypton = class {
685
599
  }
686
600
  });
687
601
  }
688
- async safePost(url, payload) {
602
+ async safePost(url, payload, keepalive = true) {
689
603
  try {
690
604
  const res = await fetch(url, {
691
605
  method: "POST",
692
606
  headers: { "Content-Type": "application/json" },
693
607
  body: JSON.stringify(payload),
694
- keepalive: true
608
+ ...keepalive ? { keepalive: true } : {}
695
609
  });
696
610
  if (!res.ok) {
697
611
  this.warn(`API request failed (${res.status})`, { url });
package/dist/index.mjs CHANGED
@@ -1,6 +1,3 @@
1
- // src/index.ts
2
- import { snapshot as rrwebSnapshot } from "rrweb-snapshot";
3
-
4
1
  // src/utils.ts
5
2
  function generateId() {
6
3
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
@@ -86,10 +83,7 @@ var Krypton = class {
86
83
  this.heatmapQueue = [];
87
84
  this.flushTimer = null;
88
85
  this.initialized = false;
89
- this.lastSnapshotUrl = null;
90
86
  this.heatmapSetup = false;
91
- this.geoRequested = false;
92
- this.geoContext = null;
93
87
  this.serverConfig = null;
94
88
  this.configFetched = false;
95
89
  this.logPrefix = "[Krypton SDK]";
@@ -154,10 +148,9 @@ var Krypton = class {
154
148
  resolveInitialConsent() {
155
149
  const stored = this.loadStoredConsent();
156
150
  if (stored) return stored;
157
- const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
151
+ const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
158
152
  analytics: true,
159
- heatmaps: !!this.config.heatmap,
160
- geo: false
153
+ heatmaps: !!this.config.heatmap
161
154
  };
162
155
  return {
163
156
  ...base,
@@ -183,8 +176,7 @@ var Krypton = class {
183
176
  const parsed = JSON.parse(raw);
184
177
  return {
185
178
  analytics: !!parsed.analytics,
186
- heatmaps: !!parsed.heatmaps,
187
- geo: !!parsed.geo
179
+ heatmaps: !!parsed.heatmaps
188
180
  };
189
181
  } catch {
190
182
  return null;
@@ -276,9 +268,6 @@ var Krypton = class {
276
268
  if (this.config.autoPageview && this.canTrackAnalytics()) {
277
269
  setTimeout(() => this.trackPageview(), 0);
278
270
  }
279
- if (this.isHeatmapFeatureEnabled()) {
280
- setTimeout(() => this.captureSnapshot(), 0);
281
- }
282
271
  } catch (err) {
283
272
  this.warn("pushState hook failed", err);
284
273
  }
@@ -290,9 +279,6 @@ var Krypton = class {
290
279
  if (this.config.autoPageview && this.canTrackAnalytics()) {
291
280
  setTimeout(() => this.trackPageview(), 0);
292
281
  }
293
- if (this.isHeatmapFeatureEnabled()) {
294
- setTimeout(() => this.captureSnapshot(), 0);
295
- }
296
282
  } catch (err) {
297
283
  this.warn("replaceState hook failed", err);
298
284
  }
@@ -302,9 +288,6 @@ var Krypton = class {
302
288
  if (this.config.autoPageview && this.canTrackAnalytics()) {
303
289
  setTimeout(() => this.trackPageview(), 0);
304
290
  }
305
- if (this.isHeatmapFeatureEnabled()) {
306
- setTimeout(() => this.captureSnapshot(), 0);
307
- }
308
291
  } catch (err) {
309
292
  this.warn("popstate hook failed", err);
310
293
  }
@@ -312,11 +295,8 @@ var Krypton = class {
312
295
  if (this.isHeatmapFeatureEnabled()) {
313
296
  this.setupHeatmap();
314
297
  }
315
- if (this.consent.geo) {
316
- this.captureGeoOnce();
317
- }
318
298
  }
319
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
299
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
320
300
  showConsentBanner() {
321
301
  if (typeof document === "undefined") return;
322
302
  if (document.getElementById("krypton-consent-banner")) return;
@@ -351,11 +331,7 @@ var Krypton = class {
351
331
  <input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
352
332
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
353
333
  </label>
354
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
355
- <input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
356
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
357
- </label>
358
- <div style="display:flex;gap:8px;flex-wrap:wrap">
334
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
359
335
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
360
336
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
361
337
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
@@ -376,19 +352,18 @@ var Krypton = class {
376
352
  banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
377
353
  const next = {
378
354
  analytics: readValue("krypton-consent-analytics"),
379
- heatmaps: readValue("krypton-consent-heatmaps"),
380
- geo: readValue("krypton-consent-geo")
355
+ heatmaps: readValue("krypton-consent-heatmaps")
381
356
  };
382
357
  remove();
383
358
  setTimeout(() => this.setConsent(next), 0);
384
359
  });
385
360
  banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
386
361
  remove();
387
- setTimeout(() => this.setConsent({ analytics: true, heatmaps: true, geo: true }), 0);
362
+ setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
388
363
  });
389
364
  banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
390
365
  remove();
391
- setTimeout(() => this.setConsent({ analytics: false, heatmaps: false, geo: false }), 0);
366
+ setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
392
367
  });
393
368
  document.body.appendChild(banner);
394
369
  }
@@ -398,8 +373,7 @@ var Krypton = class {
398
373
  const prev = { ...this.consent };
399
374
  this.consent = {
400
375
  analytics: next.analytics ?? prev.analytics,
401
- heatmaps: next.heatmaps ?? prev.heatmaps,
402
- geo: next.geo ?? prev.geo
376
+ heatmaps: next.heatmaps ?? prev.heatmaps
403
377
  };
404
378
  if (persist) {
405
379
  this.persistConsent();
@@ -415,14 +389,10 @@ var Krypton = class {
415
389
  }
416
390
  if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
417
391
  this.setupHeatmap();
418
- this.captureSnapshot();
419
392
  }
420
393
  if (prev.heatmaps && !this.consent.heatmaps) {
421
394
  this.heatmapQueue = [];
422
395
  }
423
- if (!prev.geo && this.consent.geo) {
424
- this.captureGeoOnce();
425
- }
426
396
  } catch (err) {
427
397
  this.warn("setConsent failed", err);
428
398
  }
@@ -432,11 +402,11 @@ var Krypton = class {
432
402
  }
433
403
  /** Backward-compatible: grant all categories. */
434
404
  grantConsent() {
435
- this.setConsent({ analytics: true, heatmaps: true, geo: true });
405
+ this.setConsent({ analytics: true, heatmaps: true });
436
406
  }
437
407
  /** Backward-compatible: revoke all categories and clear queues. */
438
408
  revokeConsent() {
439
- this.setConsent({ analytics: false, heatmaps: false, geo: false });
409
+ this.setConsent({ analytics: false, heatmaps: false });
440
410
  this.eventQueue = [];
441
411
  this.heatmapQueue = [];
442
412
  }
@@ -473,9 +443,6 @@ var Krypton = class {
473
443
  if (!this.canTrackAnalytics()) return;
474
444
  const utm = getUTMParams();
475
445
  const mergedProperties = { ...properties || {} };
476
- if (this.consent.geo && this.geoContext) {
477
- mergedProperties.geo = this.geoContext;
478
- }
479
446
  const event = {
480
447
  project_id: this.config.apiKey,
481
448
  distinct_id: this.distinctId,
@@ -518,30 +485,6 @@ var Krypton = class {
518
485
  }
519
486
  void this.flush();
520
487
  }
521
- captureGeoOnce() {
522
- if (this.geoRequested) return;
523
- if (!this.consent.geo) return;
524
- if (typeof navigator === "undefined" || !navigator.geolocation) return;
525
- this.geoRequested = true;
526
- navigator.geolocation.getCurrentPosition(
527
- (pos) => {
528
- const round = (value, precision = 3) => Number(value.toFixed(precision));
529
- this.geoContext = {
530
- lat: round(pos.coords.latitude),
531
- lon: round(pos.coords.longitude),
532
- accuracy_m: Math.round(pos.coords.accuracy),
533
- captured_at: (/* @__PURE__ */ new Date()).toISOString()
534
- };
535
- },
536
- () => {
537
- },
538
- {
539
- enableHighAccuracy: false,
540
- maximumAge: 10 * 60 * 1e3,
541
- timeout: 5e3
542
- }
543
- );
544
- }
545
488
  async flushEvents() {
546
489
  if (this.eventQueue.length === 0) return;
547
490
  const events = this.eventQueue.splice(0, this.eventQueue.length);
@@ -570,41 +513,10 @@ var Krypton = class {
570
513
  }
571
514
  }
572
515
  }
573
- captureSnapshot() {
574
- if (typeof window === "undefined" || typeof document === "undefined") return;
575
- if (!this.isHeatmapFeatureEnabled()) return;
576
- const currentUrl = window.location.href;
577
- if (this.lastSnapshotUrl === currentUrl) return;
578
- this.lastSnapshotUrl = currentUrl;
579
- setTimeout(() => {
580
- try {
581
- const node = rrwebSnapshot(document, {
582
- maskAllInputs: true,
583
- blockSelector: "[data-krypton-block]",
584
- inlineStylesheet: true
585
- });
586
- if (!node) return;
587
- const snapshotJson = JSON.stringify(node);
588
- const payload = {
589
- api_key: this.config.apiKey,
590
- page_url: currentUrl,
591
- snapshot: snapshotJson,
592
- viewport_width: window.innerWidth,
593
- viewport_height: window.innerHeight,
594
- page_width: document.documentElement.scrollWidth,
595
- page_height: document.documentElement.scrollHeight,
596
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
597
- };
598
- void this.safePost(`${this.config.endpoint}/api/v1/snapshot`, payload);
599
- } catch {
600
- }
601
- }, 1e3);
602
- }
603
516
  setupHeatmap() {
604
517
  if (typeof window === "undefined") return;
605
518
  if (this.heatmapSetup) return;
606
519
  this.heatmapSetup = true;
607
- this.captureSnapshot();
608
520
  document.addEventListener("click", (e) => {
609
521
  if (!this.isHeatmapFeatureEnabled()) return;
610
522
  try {
@@ -660,13 +572,13 @@ var Krypton = class {
660
572
  }
661
573
  });
662
574
  }
663
- async safePost(url, payload) {
575
+ async safePost(url, payload, keepalive = true) {
664
576
  try {
665
577
  const res = await fetch(url, {
666
578
  method: "POST",
667
579
  headers: { "Content-Type": "application/json" },
668
580
  body: JSON.stringify(payload),
669
- keepalive: true
581
+ ...keepalive ? { keepalive: true } : {}
670
582
  });
671
583
  if (!res.ok) {
672
584
  this.warn(`API request failed (${res.status})`, { url });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kryptonhq/analytics",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "Krypton Analytics JavaScript SDK — privacy-first analytics tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -27,8 +27,5 @@
27
27
  "tsup": "^8.0.0",
28
28
  "typescript": "^5.4.0"
29
29
  },
30
- "license": "MIT",
31
- "dependencies": {
32
- "rrweb-snapshot": "^2.0.0-alpha.4"
33
- }
30
+ "license": "MIT"
34
31
  }