cryptique-sdk 1.2.18 → 1.2.19

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/lib/cjs/index.js CHANGED
@@ -5639,7 +5639,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5639
5639
  */
5640
5640
  startPageSummaryTracking() {
5641
5641
  try {
5642
- const GRID_SIZE = 40;
5642
+ const GRID_SIZE = 60;
5643
5643
 
5644
5644
  // In-memory accumulators — never sent to the server individually
5645
5645
  const moveGrid = new Map(); // cellKey → move count
@@ -5760,6 +5760,62 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5760
5760
  } catch (_) {}
5761
5761
  }, { passive: true });
5762
5762
 
5763
+ // ── Viewport visibility → viewport_element_dwells (replaces individual element_view events)
5764
+ const viewportDwellsMap = new Map(); // elemKey → {tag,id,cls,text,dwell_ms,x,y,w,h}
5765
+ const vpEnterTimes = new Map(); // elemKey → {enterTime,x,y,w,h}
5766
+ try {
5767
+ if (typeof IntersectionObserver !== 'undefined') {
5768
+ const VP_SELECTOR = [
5769
+ '[id]:not([id=""])', '[data-cq-track]',
5770
+ 'button', 'a[href]', 'input:not([type=hidden])', 'select', 'textarea',
5771
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img[alt]',
5772
+ '[role="button"]', '[role="tab"]', '[role="menuitem"]', '[role="link"]'
5773
+ ].join(', ');
5774
+ const vpKey = el => `${el.tagName}|${el.id || ''}|${(el.textContent || '').trim().slice(0, 30)}`;
5775
+ const vpObserver = new IntersectionObserver(entries => {
5776
+ entries.forEach(entry => {
5777
+ const el = entry.target;
5778
+ const key = vpKey(el);
5779
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
5780
+ if (!vpEnterTimes.has(key)) {
5781
+ const r = el.getBoundingClientRect();
5782
+ vpEnterTimes.set(key, {
5783
+ enterTime: Date.now(),
5784
+ x: Math.round(r.left + window.scrollX),
5785
+ y: Math.round(r.top + window.scrollY),
5786
+ w: Math.round(r.width),
5787
+ h: Math.round(r.height),
5788
+ });
5789
+ }
5790
+ } else {
5791
+ const rec = vpEnterTimes.get(key);
5792
+ if (rec) {
5793
+ const dwell = Date.now() - rec.enterTime;
5794
+ vpEnterTimes.delete(key);
5795
+ if (dwell >= 1000) {
5796
+ const ex = viewportDwellsMap.get(key);
5797
+ if (ex) { ex.dwell_ms += dwell; }
5798
+ else {
5799
+ viewportDwellsMap.set(key, {
5800
+ tag: el.tagName.toLowerCase(),
5801
+ id: el.id || '',
5802
+ cls: el.className ? String(el.className).trim().slice(0, 60) : '',
5803
+ text: (el.textContent || '').trim().slice(0, 60),
5804
+ dwell_ms: dwell,
5805
+ x: rec.x, y: rec.y, w: rec.w, h: rec.h,
5806
+ });
5807
+ }
5808
+ }
5809
+ }
5810
+ }
5811
+ });
5812
+ }, { threshold: [0.5] });
5813
+ document.querySelectorAll(VP_SELECTOR).forEach(el => {
5814
+ try { if (el.getBoundingClientRect().height >= 20) vpObserver.observe(el); } catch (_) {}
5815
+ });
5816
+ }
5817
+ } catch (_) {}
5818
+
5763
5819
  // ── Tab visibility → tab_switches + total_tab_hidden_ms
5764
5820
  document.addEventListener('visibilitychange', () => {
5765
5821
  if (document.hidden) {
@@ -5852,6 +5908,23 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5852
5908
  if (!hasData) return;
5853
5909
  summarySent = true;
5854
5910
  try {
5911
+ // Flush still-visible elements into viewportDwellsMap before summarising
5912
+ vpEnterTimes.forEach((rec, key) => {
5913
+ const dwell = Date.now() - rec.enterTime;
5914
+ if (dwell < 1000) return;
5915
+ const ex = viewportDwellsMap.get(key);
5916
+ if (ex) { ex.dwell_ms += dwell; }
5917
+ else {
5918
+ const parts = key.split('|');
5919
+ viewportDwellsMap.set(key, { tag: (parts[0] || '').toLowerCase(), id: parts[1] || '', cls: '', text: parts[2] || '', dwell_ms: dwell, x: rec.x, y: rec.y, w: rec.w, h: rec.h });
5920
+ }
5921
+ });
5922
+ // Serialize viewport_element_dwells: filter ≥ 1000ms, sort desc, cap at 25
5923
+ const viewportElementDwells = Array.from(viewportDwellsMap.values())
5924
+ .filter(e => e.dwell_ms >= 1000)
5925
+ .sort((a, b) => b.dwell_ms - a.dwell_ms)
5926
+ .slice(0, 25);
5927
+
5855
5928
  // Serialize element_dwells: filter ≥ 300ms, sort desc, cap at 20
5856
5929
  const elementDwells = Array.from(elementDwellsMap.values())
5857
5930
  .filter(e => e.dwell_ms >= 300)
@@ -5867,6 +5940,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5867
5940
  hover_grid: serializeGrid(hoverGrid),
5868
5941
  field_dwells: fieldDwells,
5869
5942
  element_dwells: elementDwells,
5943
+ viewport_element_dwells: viewportElementDwells,
5870
5944
  first_interaction_ms: firstInteractionMs,
5871
5945
  exit_intent_count: exitIntentCount,
5872
5946
  exit_intent_last_scroll_depth: exitIntentLastScrollDepth,
@@ -5913,7 +5987,8 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5913
5987
  this.startNetworkTracking();
5914
5988
  this.startAdvancedFormTracking();
5915
5989
  this.startFormAbandonmentTracking();
5916
- this.startElementVisibilityTracking();
5990
+ // element_view events replaced by viewport_element_dwells inside page_summary
5991
+ // this.startElementVisibilityTracking();
5917
5992
  this.startPageSummaryTracking();
5918
5993
  }
5919
5994
  };
package/lib/esm/index.js CHANGED
@@ -5637,7 +5637,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5637
5637
  */
5638
5638
  startPageSummaryTracking() {
5639
5639
  try {
5640
- const GRID_SIZE = 40;
5640
+ const GRID_SIZE = 60;
5641
5641
 
5642
5642
  // In-memory accumulators — never sent to the server individually
5643
5643
  const moveGrid = new Map(); // cellKey → move count
@@ -5758,6 +5758,62 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5758
5758
  } catch (_) {}
5759
5759
  }, { passive: true });
5760
5760
 
5761
+ // ── Viewport visibility → viewport_element_dwells (replaces individual element_view events)
5762
+ const viewportDwellsMap = new Map(); // elemKey → {tag,id,cls,text,dwell_ms,x,y,w,h}
5763
+ const vpEnterTimes = new Map(); // elemKey → {enterTime,x,y,w,h}
5764
+ try {
5765
+ if (typeof IntersectionObserver !== 'undefined') {
5766
+ const VP_SELECTOR = [
5767
+ '[id]:not([id=""])', '[data-cq-track]',
5768
+ 'button', 'a[href]', 'input:not([type=hidden])', 'select', 'textarea',
5769
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img[alt]',
5770
+ '[role="button"]', '[role="tab"]', '[role="menuitem"]', '[role="link"]'
5771
+ ].join(', ');
5772
+ const vpKey = el => `${el.tagName}|${el.id || ''}|${(el.textContent || '').trim().slice(0, 30)}`;
5773
+ const vpObserver = new IntersectionObserver(entries => {
5774
+ entries.forEach(entry => {
5775
+ const el = entry.target;
5776
+ const key = vpKey(el);
5777
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
5778
+ if (!vpEnterTimes.has(key)) {
5779
+ const r = el.getBoundingClientRect();
5780
+ vpEnterTimes.set(key, {
5781
+ enterTime: Date.now(),
5782
+ x: Math.round(r.left + window.scrollX),
5783
+ y: Math.round(r.top + window.scrollY),
5784
+ w: Math.round(r.width),
5785
+ h: Math.round(r.height),
5786
+ });
5787
+ }
5788
+ } else {
5789
+ const rec = vpEnterTimes.get(key);
5790
+ if (rec) {
5791
+ const dwell = Date.now() - rec.enterTime;
5792
+ vpEnterTimes.delete(key);
5793
+ if (dwell >= 1000) {
5794
+ const ex = viewportDwellsMap.get(key);
5795
+ if (ex) { ex.dwell_ms += dwell; }
5796
+ else {
5797
+ viewportDwellsMap.set(key, {
5798
+ tag: el.tagName.toLowerCase(),
5799
+ id: el.id || '',
5800
+ cls: el.className ? String(el.className).trim().slice(0, 60) : '',
5801
+ text: (el.textContent || '').trim().slice(0, 60),
5802
+ dwell_ms: dwell,
5803
+ x: rec.x, y: rec.y, w: rec.w, h: rec.h,
5804
+ });
5805
+ }
5806
+ }
5807
+ }
5808
+ }
5809
+ });
5810
+ }, { threshold: [0.5] });
5811
+ document.querySelectorAll(VP_SELECTOR).forEach(el => {
5812
+ try { if (el.getBoundingClientRect().height >= 20) vpObserver.observe(el); } catch (_) {}
5813
+ });
5814
+ }
5815
+ } catch (_) {}
5816
+
5761
5817
  // ── Tab visibility → tab_switches + total_tab_hidden_ms
5762
5818
  document.addEventListener('visibilitychange', () => {
5763
5819
  if (document.hidden) {
@@ -5850,6 +5906,23 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5850
5906
  if (!hasData) return;
5851
5907
  summarySent = true;
5852
5908
  try {
5909
+ // Flush still-visible elements into viewportDwellsMap before summarising
5910
+ vpEnterTimes.forEach((rec, key) => {
5911
+ const dwell = Date.now() - rec.enterTime;
5912
+ if (dwell < 1000) return;
5913
+ const ex = viewportDwellsMap.get(key);
5914
+ if (ex) { ex.dwell_ms += dwell; }
5915
+ else {
5916
+ const parts = key.split('|');
5917
+ viewportDwellsMap.set(key, { tag: (parts[0] || '').toLowerCase(), id: parts[1] || '', cls: '', text: parts[2] || '', dwell_ms: dwell, x: rec.x, y: rec.y, w: rec.w, h: rec.h });
5918
+ }
5919
+ });
5920
+ // Serialize viewport_element_dwells: filter ≥ 1000ms, sort desc, cap at 25
5921
+ const viewportElementDwells = Array.from(viewportDwellsMap.values())
5922
+ .filter(e => e.dwell_ms >= 1000)
5923
+ .sort((a, b) => b.dwell_ms - a.dwell_ms)
5924
+ .slice(0, 25);
5925
+
5853
5926
  // Serialize element_dwells: filter ≥ 300ms, sort desc, cap at 20
5854
5927
  const elementDwells = Array.from(elementDwellsMap.values())
5855
5928
  .filter(e => e.dwell_ms >= 300)
@@ -5865,6 +5938,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5865
5938
  hover_grid: serializeGrid(hoverGrid),
5866
5939
  field_dwells: fieldDwells,
5867
5940
  element_dwells: elementDwells,
5941
+ viewport_element_dwells: viewportElementDwells,
5868
5942
  first_interaction_ms: firstInteractionMs,
5869
5943
  exit_intent_count: exitIntentCount,
5870
5944
  exit_intent_last_scroll_depth: exitIntentLastScrollDepth,
@@ -5911,7 +5985,8 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5911
5985
  this.startNetworkTracking();
5912
5986
  this.startAdvancedFormTracking();
5913
5987
  this.startFormAbandonmentTracking();
5914
- this.startElementVisibilityTracking();
5988
+ // element_view events replaced by viewport_element_dwells inside page_summary
5989
+ // this.startElementVisibilityTracking();
5915
5990
  this.startPageSummaryTracking();
5916
5991
  }
5917
5992
  };
package/lib/umd/index.js CHANGED
@@ -5643,7 +5643,7 @@
5643
5643
  */
5644
5644
  startPageSummaryTracking() {
5645
5645
  try {
5646
- const GRID_SIZE = 40;
5646
+ const GRID_SIZE = 60;
5647
5647
 
5648
5648
  // In-memory accumulators — never sent to the server individually
5649
5649
  const moveGrid = new Map(); // cellKey → move count
@@ -5764,6 +5764,62 @@
5764
5764
  } catch (_) {}
5765
5765
  }, { passive: true });
5766
5766
 
5767
+ // ── Viewport visibility → viewport_element_dwells (replaces individual element_view events)
5768
+ const viewportDwellsMap = new Map(); // elemKey → {tag,id,cls,text,dwell_ms,x,y,w,h}
5769
+ const vpEnterTimes = new Map(); // elemKey → {enterTime,x,y,w,h}
5770
+ try {
5771
+ if (typeof IntersectionObserver !== 'undefined') {
5772
+ const VP_SELECTOR = [
5773
+ '[id]:not([id=""])', '[data-cq-track]',
5774
+ 'button', 'a[href]', 'input:not([type=hidden])', 'select', 'textarea',
5775
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img[alt]',
5776
+ '[role="button"]', '[role="tab"]', '[role="menuitem"]', '[role="link"]'
5777
+ ].join(', ');
5778
+ const vpKey = el => `${el.tagName}|${el.id || ''}|${(el.textContent || '').trim().slice(0, 30)}`;
5779
+ const vpObserver = new IntersectionObserver(entries => {
5780
+ entries.forEach(entry => {
5781
+ const el = entry.target;
5782
+ const key = vpKey(el);
5783
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
5784
+ if (!vpEnterTimes.has(key)) {
5785
+ const r = el.getBoundingClientRect();
5786
+ vpEnterTimes.set(key, {
5787
+ enterTime: Date.now(),
5788
+ x: Math.round(r.left + window.scrollX),
5789
+ y: Math.round(r.top + window.scrollY),
5790
+ w: Math.round(r.width),
5791
+ h: Math.round(r.height),
5792
+ });
5793
+ }
5794
+ } else {
5795
+ const rec = vpEnterTimes.get(key);
5796
+ if (rec) {
5797
+ const dwell = Date.now() - rec.enterTime;
5798
+ vpEnterTimes.delete(key);
5799
+ if (dwell >= 1000) {
5800
+ const ex = viewportDwellsMap.get(key);
5801
+ if (ex) { ex.dwell_ms += dwell; }
5802
+ else {
5803
+ viewportDwellsMap.set(key, {
5804
+ tag: el.tagName.toLowerCase(),
5805
+ id: el.id || '',
5806
+ cls: el.className ? String(el.className).trim().slice(0, 60) : '',
5807
+ text: (el.textContent || '').trim().slice(0, 60),
5808
+ dwell_ms: dwell,
5809
+ x: rec.x, y: rec.y, w: rec.w, h: rec.h,
5810
+ });
5811
+ }
5812
+ }
5813
+ }
5814
+ }
5815
+ });
5816
+ }, { threshold: [0.5] });
5817
+ document.querySelectorAll(VP_SELECTOR).forEach(el => {
5818
+ try { if (el.getBoundingClientRect().height >= 20) vpObserver.observe(el); } catch (_) {}
5819
+ });
5820
+ }
5821
+ } catch (_) {}
5822
+
5767
5823
  // ── Tab visibility → tab_switches + total_tab_hidden_ms
5768
5824
  document.addEventListener('visibilitychange', () => {
5769
5825
  if (document.hidden) {
@@ -5856,6 +5912,23 @@
5856
5912
  if (!hasData) return;
5857
5913
  summarySent = true;
5858
5914
  try {
5915
+ // Flush still-visible elements into viewportDwellsMap before summarising
5916
+ vpEnterTimes.forEach((rec, key) => {
5917
+ const dwell = Date.now() - rec.enterTime;
5918
+ if (dwell < 1000) return;
5919
+ const ex = viewportDwellsMap.get(key);
5920
+ if (ex) { ex.dwell_ms += dwell; }
5921
+ else {
5922
+ const parts = key.split('|');
5923
+ viewportDwellsMap.set(key, { tag: (parts[0] || '').toLowerCase(), id: parts[1] || '', cls: '', text: parts[2] || '', dwell_ms: dwell, x: rec.x, y: rec.y, w: rec.w, h: rec.h });
5924
+ }
5925
+ });
5926
+ // Serialize viewport_element_dwells: filter ≥ 1000ms, sort desc, cap at 25
5927
+ const viewportElementDwells = Array.from(viewportDwellsMap.values())
5928
+ .filter(e => e.dwell_ms >= 1000)
5929
+ .sort((a, b) => b.dwell_ms - a.dwell_ms)
5930
+ .slice(0, 25);
5931
+
5859
5932
  // Serialize element_dwells: filter ≥ 300ms, sort desc, cap at 20
5860
5933
  const elementDwells = Array.from(elementDwellsMap.values())
5861
5934
  .filter(e => e.dwell_ms >= 300)
@@ -5871,6 +5944,7 @@
5871
5944
  hover_grid: serializeGrid(hoverGrid),
5872
5945
  field_dwells: fieldDwells,
5873
5946
  element_dwells: elementDwells,
5947
+ viewport_element_dwells: viewportElementDwells,
5874
5948
  first_interaction_ms: firstInteractionMs,
5875
5949
  exit_intent_count: exitIntentCount,
5876
5950
  exit_intent_last_scroll_depth: exitIntentLastScrollDepth,
@@ -5917,7 +5991,8 @@
5917
5991
  this.startNetworkTracking();
5918
5992
  this.startAdvancedFormTracking();
5919
5993
  this.startFormAbandonmentTracking();
5920
- this.startElementVisibilityTracking();
5994
+ // element_view events replaced by viewport_element_dwells inside page_summary
5995
+ // this.startElementVisibilityTracking();
5921
5996
  this.startPageSummaryTracking();
5922
5997
  }
5923
5998
  };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "cryptique-sdk",
3
- "version": "1.2.18",
3
+ "version": "1.2.19",
4
4
  "type": "module",
5
5
  "description": "Cryptique Analytics SDK - Comprehensive web analytics and user tracking for modern web applications",
6
6
  "main": "lib/cjs/index.js",
7
-
7
+
8
8
  "module": "lib/esm/index.js",
9
9
  "browser": "lib/umd/index.js",
10
10
  "types": "lib/types/index.d.ts",