@grainql/analytics-web 3.2.0 → 3.2.1
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/dist/cjs/heatmap-tracking.d.ts +7 -0
- package/dist/cjs/heatmap-tracking.d.ts.map +1 -1
- package/dist/cjs/heatmap-tracking.js +44 -1
- package/dist/cjs/heatmap-tracking.js.map +1 -1
- package/dist/cjs/types/heatmap-tracking.d.ts +2 -0
- package/dist/cjs/types/heatmap-tracking.d.ts.map +1 -1
- package/dist/esm/heatmap-tracking.d.ts +7 -0
- package/dist/esm/heatmap-tracking.d.ts.map +1 -1
- package/dist/esm/heatmap-tracking.js +44 -1
- package/dist/esm/heatmap-tracking.js.map +1 -1
- package/dist/esm/types/heatmap-tracking.d.ts +2 -0
- package/dist/esm/types/heatmap-tracking.d.ts.map +1 -1
- package/dist/heatmap-tracking.d.ts +7 -0
- package/dist/heatmap-tracking.d.ts.map +1 -1
- package/dist/heatmap-tracking.js +44 -1
- package/dist/index.global.dev.js +52 -11
- package/dist/index.global.dev.js.map +2 -2
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +3 -3
- package/dist/types/heatmap-tracking.d.ts +2 -0
- package/dist/types/heatmap-tracking.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/heatmap-tracking.js
CHANGED
|
@@ -65,8 +65,12 @@ class HeatmapTrackingManager {
|
|
|
65
65
|
// Snapshot capture state
|
|
66
66
|
this.snapshotCaptured = false;
|
|
67
67
|
this.snapshotEnabled = false;
|
|
68
|
+
// Device type detection
|
|
69
|
+
this.deviceType = 'desktop';
|
|
68
70
|
this.tracker = tracker;
|
|
69
71
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
72
|
+
// Detect device type on initialization
|
|
73
|
+
this.deviceType = this.detectDeviceType();
|
|
70
74
|
// Initialize attention quality manager
|
|
71
75
|
this.attentionQuality = new attention_quality_1.AttentionQualityManager(tracker.getActivityDetector(), {
|
|
72
76
|
maxSectionDuration: 9000, // 9 seconds per viewport section
|
|
@@ -109,6 +113,34 @@ class HeatmapTrackingManager {
|
|
|
109
113
|
/**
|
|
110
114
|
* Check remote config for snapshot capture enablement
|
|
111
115
|
*/
|
|
116
|
+
/**
|
|
117
|
+
* Detect device type based on viewport width and user agent
|
|
118
|
+
* Mobile: width < 768px OR mobile user agent
|
|
119
|
+
* Desktop: width >= 768px AND non-mobile user agent
|
|
120
|
+
*/
|
|
121
|
+
detectDeviceType() {
|
|
122
|
+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
123
|
+
return 'desktop'; // SSR default
|
|
124
|
+
}
|
|
125
|
+
// Check viewport width
|
|
126
|
+
const width = window.innerWidth || window.screen?.width || 0;
|
|
127
|
+
const isMobileWidth = width < 768;
|
|
128
|
+
// Check user agent for mobile indicators
|
|
129
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
130
|
+
const mobileKeywords = [
|
|
131
|
+
'mobile',
|
|
132
|
+
'android',
|
|
133
|
+
'iphone',
|
|
134
|
+
'ipad',
|
|
135
|
+
'ipod',
|
|
136
|
+
'blackberry',
|
|
137
|
+
'windows phone',
|
|
138
|
+
'webos',
|
|
139
|
+
];
|
|
140
|
+
const isMobileUserAgent = mobileKeywords.some((keyword) => userAgent.includes(keyword));
|
|
141
|
+
// Device is mobile if either width OR user agent indicates mobile
|
|
142
|
+
return isMobileWidth || isMobileUserAgent ? 'mobile' : 'desktop';
|
|
143
|
+
}
|
|
112
144
|
/**
|
|
113
145
|
* Normalize URL by removing query params and hash, and stripping www prefix
|
|
114
146
|
* This ensures heatmap data is aggregated by page, not by URL variations
|
|
@@ -205,7 +237,8 @@ class HeatmapTrackingManager {
|
|
|
205
237
|
sessionId,
|
|
206
238
|
pageUrl,
|
|
207
239
|
snapshot: JSON.stringify(snapshot),
|
|
208
|
-
timestamp: Date.now()
|
|
240
|
+
timestamp: Date.now(),
|
|
241
|
+
deviceType: this.deviceType
|
|
209
242
|
})
|
|
210
243
|
});
|
|
211
244
|
if (!response.ok) {
|
|
@@ -349,6 +382,7 @@ class HeatmapTrackingManager {
|
|
|
349
382
|
exitTimestamp: currentTime,
|
|
350
383
|
pageHeight,
|
|
351
384
|
viewportHeight,
|
|
385
|
+
deviceType: this.deviceType,
|
|
352
386
|
};
|
|
353
387
|
// Send immediately using beacon to ensure delivery
|
|
354
388
|
this.tracker.trackSystemEvent('_grain_heatmap_scroll', {
|
|
@@ -360,6 +394,7 @@ class HeatmapTrackingManager {
|
|
|
360
394
|
exit_timestamp: scrollData.exitTimestamp,
|
|
361
395
|
page_height: scrollData.pageHeight,
|
|
362
396
|
viewport_height: scrollData.viewportHeight,
|
|
397
|
+
device_type: scrollData.deviceType,
|
|
363
398
|
is_split: true, // Flag to indicate periodic tracking, not final exit
|
|
364
399
|
}, { flush: true });
|
|
365
400
|
// Update attention quality duration tracker
|
|
@@ -390,6 +425,7 @@ class HeatmapTrackingManager {
|
|
|
390
425
|
exitTimestamp: currentTime,
|
|
391
426
|
pageHeight: document.documentElement.scrollHeight,
|
|
392
427
|
viewportHeight: window.innerHeight,
|
|
428
|
+
deviceType: this.deviceType,
|
|
393
429
|
};
|
|
394
430
|
this.pendingScrolls.push(scrollData);
|
|
395
431
|
}
|
|
@@ -448,6 +484,7 @@ class HeatmapTrackingManager {
|
|
|
448
484
|
elementTag,
|
|
449
485
|
elementText: elementText || undefined,
|
|
450
486
|
timestamp: Date.now(),
|
|
487
|
+
deviceType: this.deviceType,
|
|
451
488
|
};
|
|
452
489
|
// Check if this is a navigation link
|
|
453
490
|
const isNavigationLink = element instanceof HTMLAnchorElement && element.href;
|
|
@@ -466,6 +503,7 @@ class HeatmapTrackingManager {
|
|
|
466
503
|
element_tag: clickData.elementTag,
|
|
467
504
|
element_text: clickData.elementText,
|
|
468
505
|
timestamp: clickData.timestamp,
|
|
506
|
+
device_type: clickData.deviceType,
|
|
469
507
|
}, { flush: true });
|
|
470
508
|
}
|
|
471
509
|
else {
|
|
@@ -510,6 +548,7 @@ class HeatmapTrackingManager {
|
|
|
510
548
|
exitTimestamp: currentTime,
|
|
511
549
|
pageHeight,
|
|
512
550
|
viewportHeight,
|
|
551
|
+
deviceType: this.deviceType,
|
|
513
552
|
};
|
|
514
553
|
this.pendingScrolls.push(scrollData);
|
|
515
554
|
}
|
|
@@ -645,6 +684,7 @@ class HeatmapTrackingManager {
|
|
|
645
684
|
element_tag: clickData.elementTag,
|
|
646
685
|
element_text: clickData.elementText,
|
|
647
686
|
timestamp: clickData.timestamp,
|
|
687
|
+
device_type: clickData.deviceType,
|
|
648
688
|
});
|
|
649
689
|
}
|
|
650
690
|
this.pendingClicks = [];
|
|
@@ -661,6 +701,7 @@ class HeatmapTrackingManager {
|
|
|
661
701
|
exit_timestamp: scrollData.exitTimestamp,
|
|
662
702
|
page_height: scrollData.pageHeight,
|
|
663
703
|
viewport_height: scrollData.viewportHeight,
|
|
704
|
+
device_type: scrollData.deviceType,
|
|
664
705
|
});
|
|
665
706
|
}
|
|
666
707
|
this.pendingScrolls = [];
|
|
@@ -693,6 +734,7 @@ class HeatmapTrackingManager {
|
|
|
693
734
|
element_tag: clickData.elementTag,
|
|
694
735
|
element_text: clickData.elementText,
|
|
695
736
|
timestamp: clickData.timestamp,
|
|
737
|
+
device_type: clickData.deviceType,
|
|
696
738
|
}, { flush: true });
|
|
697
739
|
}
|
|
698
740
|
this.pendingClicks = [];
|
|
@@ -709,6 +751,7 @@ class HeatmapTrackingManager {
|
|
|
709
751
|
exit_timestamp: scrollData.exitTimestamp,
|
|
710
752
|
page_height: scrollData.pageHeight,
|
|
711
753
|
viewport_height: scrollData.viewportHeight,
|
|
754
|
+
device_type: scrollData.deviceType,
|
|
712
755
|
}, { flush: true });
|
|
713
756
|
}
|
|
714
757
|
this.pendingScrolls = [];
|
package/dist/index.global.dev.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Grain Analytics Web SDK v3.2.
|
|
1
|
+
/* Grain Analytics Web SDK v3.2.1 | MIT License | Development Build */
|
|
2
2
|
"use strict";
|
|
3
3
|
var Grain = (() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -5851,8 +5851,11 @@ var Grain = (() => {
|
|
|
5851
5851
|
// Snapshot capture state
|
|
5852
5852
|
this.snapshotCaptured = false;
|
|
5853
5853
|
this.snapshotEnabled = false;
|
|
5854
|
+
// Device type detection
|
|
5855
|
+
this.deviceType = "desktop";
|
|
5854
5856
|
this.tracker = tracker;
|
|
5855
5857
|
this.options = { ...DEFAULT_OPTIONS2, ...options };
|
|
5858
|
+
this.deviceType = this.detectDeviceType();
|
|
5856
5859
|
this.attentionQuality = new AttentionQualityManager(
|
|
5857
5860
|
tracker.getActivityDetector(),
|
|
5858
5861
|
{
|
|
@@ -5892,6 +5895,33 @@ var Grain = (() => {
|
|
|
5892
5895
|
/**
|
|
5893
5896
|
* Check remote config for snapshot capture enablement
|
|
5894
5897
|
*/
|
|
5898
|
+
/**
|
|
5899
|
+
* Detect device type based on viewport width and user agent
|
|
5900
|
+
* Mobile: width < 768px OR mobile user agent
|
|
5901
|
+
* Desktop: width >= 768px AND non-mobile user agent
|
|
5902
|
+
*/
|
|
5903
|
+
detectDeviceType() {
|
|
5904
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
5905
|
+
return "desktop";
|
|
5906
|
+
}
|
|
5907
|
+
const width = window.innerWidth || window.screen?.width || 0;
|
|
5908
|
+
const isMobileWidth = width < 768;
|
|
5909
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
5910
|
+
const mobileKeywords = [
|
|
5911
|
+
"mobile",
|
|
5912
|
+
"android",
|
|
5913
|
+
"iphone",
|
|
5914
|
+
"ipad",
|
|
5915
|
+
"ipod",
|
|
5916
|
+
"blackberry",
|
|
5917
|
+
"windows phone",
|
|
5918
|
+
"webos"
|
|
5919
|
+
];
|
|
5920
|
+
const isMobileUserAgent = mobileKeywords.some(
|
|
5921
|
+
(keyword) => userAgent.includes(keyword)
|
|
5922
|
+
);
|
|
5923
|
+
return isMobileWidth || isMobileUserAgent ? "mobile" : "desktop";
|
|
5924
|
+
}
|
|
5895
5925
|
/**
|
|
5896
5926
|
* Normalize URL by removing query params and hash, and stripping www prefix
|
|
5897
5927
|
* This ensures heatmap data is aggregated by page, not by URL variations
|
|
@@ -5974,7 +6004,8 @@ var Grain = (() => {
|
|
|
5974
6004
|
sessionId,
|
|
5975
6005
|
pageUrl,
|
|
5976
6006
|
snapshot: JSON.stringify(snapshot2),
|
|
5977
|
-
timestamp: Date.now()
|
|
6007
|
+
timestamp: Date.now(),
|
|
6008
|
+
deviceType: this.deviceType
|
|
5978
6009
|
})
|
|
5979
6010
|
}
|
|
5980
6011
|
);
|
|
@@ -6102,7 +6133,8 @@ var Grain = (() => {
|
|
|
6102
6133
|
entryTimestamp: this.currentScrollState.entryTime,
|
|
6103
6134
|
exitTimestamp: currentTime,
|
|
6104
6135
|
pageHeight,
|
|
6105
|
-
viewportHeight
|
|
6136
|
+
viewportHeight,
|
|
6137
|
+
deviceType: this.deviceType
|
|
6106
6138
|
};
|
|
6107
6139
|
this.tracker.trackSystemEvent("_grain_heatmap_scroll", {
|
|
6108
6140
|
page_url: scrollData.pageUrl,
|
|
@@ -6113,6 +6145,7 @@ var Grain = (() => {
|
|
|
6113
6145
|
exit_timestamp: scrollData.exitTimestamp,
|
|
6114
6146
|
page_height: scrollData.pageHeight,
|
|
6115
6147
|
viewport_height: scrollData.viewportHeight,
|
|
6148
|
+
device_type: scrollData.deviceType,
|
|
6116
6149
|
is_split: true
|
|
6117
6150
|
// Flag to indicate periodic tracking, not final exit
|
|
6118
6151
|
}, { flush: true });
|
|
@@ -6140,7 +6173,8 @@ var Grain = (() => {
|
|
|
6140
6173
|
entryTimestamp: this.currentScrollState.entryTime,
|
|
6141
6174
|
exitTimestamp: currentTime,
|
|
6142
6175
|
pageHeight: document.documentElement.scrollHeight,
|
|
6143
|
-
viewportHeight: window.innerHeight
|
|
6176
|
+
viewportHeight: window.innerHeight,
|
|
6177
|
+
deviceType: this.deviceType
|
|
6144
6178
|
};
|
|
6145
6179
|
this.pendingScrolls.push(scrollData);
|
|
6146
6180
|
}
|
|
@@ -6189,7 +6223,8 @@ var Grain = (() => {
|
|
|
6189
6223
|
pageY,
|
|
6190
6224
|
elementTag,
|
|
6191
6225
|
elementText: elementText || void 0,
|
|
6192
|
-
timestamp: Date.now()
|
|
6226
|
+
timestamp: Date.now(),
|
|
6227
|
+
deviceType: this.deviceType
|
|
6193
6228
|
};
|
|
6194
6229
|
const isNavigationLink = element instanceof HTMLAnchorElement && element.href;
|
|
6195
6230
|
if (isNavigationLink) {
|
|
@@ -6205,7 +6240,8 @@ var Grain = (() => {
|
|
|
6205
6240
|
page_y: clickData.pageY,
|
|
6206
6241
|
element_tag: clickData.elementTag,
|
|
6207
6242
|
element_text: clickData.elementText,
|
|
6208
|
-
timestamp: clickData.timestamp
|
|
6243
|
+
timestamp: clickData.timestamp,
|
|
6244
|
+
device_type: clickData.deviceType
|
|
6209
6245
|
}, { flush: true });
|
|
6210
6246
|
} else {
|
|
6211
6247
|
this.pendingClicks.push(clickData);
|
|
@@ -6240,7 +6276,8 @@ var Grain = (() => {
|
|
|
6240
6276
|
entryTimestamp: this.currentScrollState.entryTime,
|
|
6241
6277
|
exitTimestamp: currentTime,
|
|
6242
6278
|
pageHeight,
|
|
6243
|
-
viewportHeight
|
|
6279
|
+
viewportHeight,
|
|
6280
|
+
deviceType: this.deviceType
|
|
6244
6281
|
};
|
|
6245
6282
|
this.pendingScrolls.push(scrollData);
|
|
6246
6283
|
}
|
|
@@ -6360,7 +6397,8 @@ var Grain = (() => {
|
|
|
6360
6397
|
page_y: clickData.pageY,
|
|
6361
6398
|
element_tag: clickData.elementTag,
|
|
6362
6399
|
element_text: clickData.elementText,
|
|
6363
|
-
timestamp: clickData.timestamp
|
|
6400
|
+
timestamp: clickData.timestamp,
|
|
6401
|
+
device_type: clickData.deviceType
|
|
6364
6402
|
});
|
|
6365
6403
|
}
|
|
6366
6404
|
this.pendingClicks = [];
|
|
@@ -6375,7 +6413,8 @@ var Grain = (() => {
|
|
|
6375
6413
|
entry_timestamp: scrollData.entryTimestamp,
|
|
6376
6414
|
exit_timestamp: scrollData.exitTimestamp,
|
|
6377
6415
|
page_height: scrollData.pageHeight,
|
|
6378
|
-
viewport_height: scrollData.viewportHeight
|
|
6416
|
+
viewport_height: scrollData.viewportHeight,
|
|
6417
|
+
device_type: scrollData.deviceType
|
|
6379
6418
|
});
|
|
6380
6419
|
}
|
|
6381
6420
|
this.pendingScrolls = [];
|
|
@@ -6403,7 +6442,8 @@ var Grain = (() => {
|
|
|
6403
6442
|
page_y: clickData.pageY,
|
|
6404
6443
|
element_tag: clickData.elementTag,
|
|
6405
6444
|
element_text: clickData.elementText,
|
|
6406
|
-
timestamp: clickData.timestamp
|
|
6445
|
+
timestamp: clickData.timestamp,
|
|
6446
|
+
device_type: clickData.deviceType
|
|
6407
6447
|
}, { flush: true });
|
|
6408
6448
|
}
|
|
6409
6449
|
this.pendingClicks = [];
|
|
@@ -6418,7 +6458,8 @@ var Grain = (() => {
|
|
|
6418
6458
|
entry_timestamp: scrollData.entryTimestamp,
|
|
6419
6459
|
exit_timestamp: scrollData.exitTimestamp,
|
|
6420
6460
|
page_height: scrollData.pageHeight,
|
|
6421
|
-
viewport_height: scrollData.viewportHeight
|
|
6461
|
+
viewport_height: scrollData.viewportHeight,
|
|
6462
|
+
device_type: scrollData.deviceType
|
|
6422
6463
|
}, { flush: true });
|
|
6423
6464
|
}
|
|
6424
6465
|
this.pendingScrolls = [];
|