@builtonveya/analytics-web 4.0.0 → 4.0.2
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 +39 -3
- package/dist/cjs/core/VeyaAnalyticsCore.js +70 -17
- package/dist/cjs/core/VeyaAnalyticsCore.js.map +1 -1
- package/dist/cjs/web/VeyaAnalyticsWeb.js +80 -11
- package/dist/cjs/web/VeyaAnalyticsWeb.js.map +1 -1
- package/dist/esm/core/VeyaAnalyticsCore.d.ts +22 -4
- package/dist/esm/core/VeyaAnalyticsCore.d.ts.map +1 -1
- package/dist/esm/core/VeyaAnalyticsCore.js +70 -17
- package/dist/esm/core/VeyaAnalyticsCore.js.map +1 -1
- package/dist/esm/web/VeyaAnalyticsWeb.d.ts +8 -1
- package/dist/esm/web/VeyaAnalyticsWeb.d.ts.map +1 -1
- package/dist/esm/web/VeyaAnalyticsWeb.js +80 -11
- package/dist/esm/web/VeyaAnalyticsWeb.js.map +1 -1
- package/dist/veya-analytics.js +116 -22
- package/dist/veya-analytics.js.map +2 -2
- package/dist/veya-analytics.min.js +2 -2
- package/dist/veya-analytics.min.js.map +3 -3
- package/package.json +2 -2
package/dist/veya-analytics.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @builtonveya/analytics-web v4.0.
|
|
1
|
+
/*! @builtonveya/analytics-web v4.0.2 — https://github.com/adam-3owl/veya-analytics-api */
|
|
2
2
|
"use strict";
|
|
3
3
|
var VeyaAnalyticsSDK = (() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -37,8 +37,7 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
37
37
|
tenantId: "",
|
|
38
38
|
storeId: "",
|
|
39
39
|
storeName: "",
|
|
40
|
-
endpoint: "https://analytics.
|
|
41
|
-
aiEndpoint: "https://analytics.veya.io/v1/classify",
|
|
40
|
+
endpoint: "https://analytics.builtonveya.com/v1/events",
|
|
42
41
|
batchSize: 10,
|
|
43
42
|
flushInterval: 5e3,
|
|
44
43
|
sessionTimeout: 30 * 60 * 1e3,
|
|
@@ -46,8 +45,8 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
46
45
|
autoDetect: true,
|
|
47
46
|
autoTrackProducts: true,
|
|
48
47
|
autoTrackCart: true,
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
// Opt-in: patches window.fetch and reads order/basket responses as placed orders
|
|
49
|
+
interceptOloApi: false,
|
|
51
50
|
confidenceThreshold: 0.7,
|
|
52
51
|
platform: "web"
|
|
53
52
|
};
|
|
@@ -65,6 +64,8 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
65
64
|
constructor() {
|
|
66
65
|
__publicField(this, "config");
|
|
67
66
|
__publicField(this, "initialized", false);
|
|
67
|
+
// The in-flight (or completed) init run, shared by every init() call — see init()
|
|
68
|
+
__publicField(this, "initPromise", null);
|
|
68
69
|
__publicField(this, "eventQueue", []);
|
|
69
70
|
__publicField(this, "flushTimer", null);
|
|
70
71
|
// Identifiers
|
|
@@ -95,11 +96,27 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
95
96
|
// ============================================================================
|
|
96
97
|
// INITIALIZATION
|
|
97
98
|
// ============================================================================
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Initialize the SDK. Safe to call more than once: a call made while another is still in
|
|
101
|
+
* flight shares that run (React StrictMode's double effects, or two call sites, can't set up
|
|
102
|
+
* listeners or send session_start twice), and a call after a successful init resolves at once.
|
|
103
|
+
* A failed init (e.g. a missing tenantSlug) can be retried with corrected options.
|
|
104
|
+
*
|
|
105
|
+
* Platform SDKs set their platform by overriding init() and passing it through, and do their
|
|
106
|
+
* own setup in onInitialized(), which runs exactly once.
|
|
107
|
+
*/
|
|
108
|
+
init(options) {
|
|
109
|
+
if (this.initPromise) {
|
|
110
|
+
if (this.initialized) this.log("warn", "SDK already initialized");
|
|
111
|
+
return this.initPromise;
|
|
102
112
|
}
|
|
113
|
+
this.initPromise = this.runInit(options).catch((error) => {
|
|
114
|
+
if (!this.initialized) this.initPromise = null;
|
|
115
|
+
throw error;
|
|
116
|
+
});
|
|
117
|
+
return this.initPromise;
|
|
118
|
+
}
|
|
119
|
+
async runInit(options) {
|
|
103
120
|
if (!options.tenantSlug && !options.tenantId) {
|
|
104
121
|
throw new Error("VeyaAnalytics: tenantSlug is required");
|
|
105
122
|
}
|
|
@@ -108,19 +125,30 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
108
125
|
this.config.tenantSlug = this.config.tenantId;
|
|
109
126
|
}
|
|
110
127
|
await this.initVisitor();
|
|
111
|
-
await this.initSession();
|
|
128
|
+
const isNewSession = await this.initSession();
|
|
112
129
|
this.deviceInfo = await this.getDeviceInfo();
|
|
113
130
|
this.startFlushTimer();
|
|
114
|
-
this.trackSessionStart();
|
|
115
131
|
this.initialized = true;
|
|
132
|
+
if (isNewSession) {
|
|
133
|
+
this.trackSessionStart();
|
|
134
|
+
}
|
|
116
135
|
this.log("info", "VeyaAnalytics initialized", {
|
|
117
136
|
tenantSlug: this.config.tenantSlug,
|
|
118
137
|
visitorId: this.visitorId,
|
|
119
138
|
sessionId: this.sessionId,
|
|
120
|
-
platform: this.config.platform
|
|
139
|
+
platform: this.config.platform,
|
|
140
|
+
newSession: isNewSession
|
|
121
141
|
});
|
|
142
|
+
try {
|
|
143
|
+
await this.onInitialized();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.log("error", "Platform setup failed", error);
|
|
146
|
+
}
|
|
122
147
|
return this;
|
|
123
148
|
}
|
|
149
|
+
/** Platform hook: runs exactly once per instance, after the core is initialized. */
|
|
150
|
+
async onInitialized() {
|
|
151
|
+
}
|
|
124
152
|
async initVisitor() {
|
|
125
153
|
if (!this.storage) {
|
|
126
154
|
this.visitorId = generateUUID();
|
|
@@ -134,10 +162,11 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
134
162
|
await this.storage.setItem("veya_visitor_id", this.visitorId);
|
|
135
163
|
}
|
|
136
164
|
}
|
|
165
|
+
/** Resolves true when a new session was started, false when a stored one was resumed. */
|
|
137
166
|
async initSession() {
|
|
138
167
|
if (!this.storage) {
|
|
139
168
|
this.sessionId = generateUUID();
|
|
140
|
-
return;
|
|
169
|
+
return true;
|
|
141
170
|
}
|
|
142
171
|
const stored = await this.storage.getItem("veya_session");
|
|
143
172
|
const now = Date.now();
|
|
@@ -148,13 +177,14 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
148
177
|
this.sessionId = sessionData.sessionId;
|
|
149
178
|
this.sessionData = { ...this.sessionData, ...sessionData.data };
|
|
150
179
|
await this.saveSession();
|
|
151
|
-
return;
|
|
180
|
+
return false;
|
|
152
181
|
}
|
|
153
182
|
} catch (e) {
|
|
154
183
|
}
|
|
155
184
|
}
|
|
156
185
|
this.sessionId = generateUUID();
|
|
157
186
|
await this.saveSession();
|
|
187
|
+
return true;
|
|
158
188
|
}
|
|
159
189
|
async saveSession() {
|
|
160
190
|
if (!this.storage) return;
|
|
@@ -247,7 +277,7 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
247
277
|
delete sanitized.referrer;
|
|
248
278
|
delete sanitized.funnel_step;
|
|
249
279
|
delete sanitized.funnel_step_number;
|
|
250
|
-
const piiFields = ["email", "phone", "password", "ssn", "credit_card", "cvv"];
|
|
280
|
+
const piiFields = ["email", "phone", "password", "ssn", "credit_card", "cvv", "address", "street", "postal_code", "zip"];
|
|
251
281
|
piiFields.forEach((field) => delete sanitized[field]);
|
|
252
282
|
return sanitized;
|
|
253
283
|
}
|
|
@@ -402,6 +432,19 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
402
432
|
...properties
|
|
403
433
|
});
|
|
404
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* The shopper chose or entered a payment method. Sends add_payment_info with
|
|
437
|
+
* { payment_method } at funnel step checkout_payment (4); the cart value and item count ride
|
|
438
|
+
* on the event itself, as on every event (matching the v1 bundle's addPaymentInfo).
|
|
439
|
+
*/
|
|
440
|
+
addPaymentInfo(paymentMethod, properties = {}) {
|
|
441
|
+
return this.track("add_payment_info", {
|
|
442
|
+
payment_method: paymentMethod,
|
|
443
|
+
funnel_step: "checkout_payment",
|
|
444
|
+
funnel_step_number: 4,
|
|
445
|
+
...properties
|
|
446
|
+
});
|
|
447
|
+
}
|
|
405
448
|
checkoutComplete(order, properties = {}) {
|
|
406
449
|
this.updateFunnelStep("confirmation");
|
|
407
450
|
const event = this.track("checkout_complete", {
|
|
@@ -728,6 +771,7 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
728
771
|
titlePatterns: []
|
|
729
772
|
}
|
|
730
773
|
};
|
|
774
|
+
var SCROLL_DEPTHS = [25, 50, 75, 100];
|
|
731
775
|
var VeyaAnalyticsWeb = class extends VeyaAnalyticsCore {
|
|
732
776
|
constructor() {
|
|
733
777
|
super();
|
|
@@ -735,11 +779,18 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
735
779
|
this.productTracker = null;
|
|
736
780
|
this.cartTracker = null;
|
|
737
781
|
this.networkInterceptor = null;
|
|
782
|
+
// Page-level state for time_on_page and scroll depth; both reset on every page view
|
|
783
|
+
this.pageStartedAt = Date.now();
|
|
784
|
+
this.scrollDepthsFired = /* @__PURE__ */ new Set();
|
|
785
|
+
this.scrollCheckPending = false;
|
|
738
786
|
this.storage = new LocalStorageAdapter();
|
|
739
787
|
}
|
|
740
|
-
|
|
741
|
-
options
|
|
742
|
-
|
|
788
|
+
init(options) {
|
|
789
|
+
return super.init({ ...options, platform: "web" });
|
|
790
|
+
}
|
|
791
|
+
// Runs exactly once, after the core is initialized (see VeyaAnalyticsCore.init)
|
|
792
|
+
async onInitialized() {
|
|
793
|
+
this.pageStartedAt = Date.now();
|
|
743
794
|
if (this.config.autoDetect) {
|
|
744
795
|
this.setupPageChangeDetection();
|
|
745
796
|
}
|
|
@@ -756,8 +807,9 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
756
807
|
this.networkInterceptor.init();
|
|
757
808
|
}
|
|
758
809
|
this.setupBrowserListeners();
|
|
759
|
-
this.
|
|
760
|
-
|
|
810
|
+
if (this.config.autoDetect) {
|
|
811
|
+
this.trackCurrentPage();
|
|
812
|
+
}
|
|
761
813
|
}
|
|
762
814
|
async getDeviceInfo() {
|
|
763
815
|
const ua = navigator.userAgent;
|
|
@@ -887,6 +939,13 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
887
939
|
...this.getUTMParams()
|
|
888
940
|
});
|
|
889
941
|
}
|
|
942
|
+
// Every page view (SDK-detected or sent by the app) starts a new page: time_on_page restarts and
|
|
943
|
+
// the scroll-depth thresholds can fire again.
|
|
944
|
+
pageView(properties = {}) {
|
|
945
|
+
this.pageStartedAt = Date.now();
|
|
946
|
+
this.scrollDepthsFired.clear();
|
|
947
|
+
return super.pageView(properties);
|
|
948
|
+
}
|
|
890
949
|
getUTMParams() {
|
|
891
950
|
const params = new URLSearchParams(window.location.search);
|
|
892
951
|
return {
|
|
@@ -903,13 +962,32 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
903
962
|
setupBrowserListeners() {
|
|
904
963
|
document.addEventListener("visibilitychange", () => {
|
|
905
964
|
if (document.visibilityState === "hidden") {
|
|
965
|
+
this.track("page_hidden", { time_on_page: this.timeOnPage() });
|
|
906
966
|
this.flush(true);
|
|
967
|
+
} else if (document.visibilityState === "visible") {
|
|
968
|
+
this.track("page_visible");
|
|
907
969
|
}
|
|
908
970
|
});
|
|
909
|
-
window.addEventListener("
|
|
910
|
-
this.
|
|
971
|
+
window.addEventListener("pagehide", (event) => {
|
|
972
|
+
this.track("page_unload", { time_on_page: this.timeOnPage(), persisted: event.persisted });
|
|
911
973
|
this.flush(true);
|
|
912
974
|
});
|
|
975
|
+
window.addEventListener("pageshow", (event) => {
|
|
976
|
+
if (!event.persisted) return;
|
|
977
|
+
this.pageStartedAt = Date.now();
|
|
978
|
+
this.scrollDepthsFired.clear();
|
|
979
|
+
if (this.config.autoDetect) {
|
|
980
|
+
this.trackCurrentPage();
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
window.addEventListener("scroll", () => {
|
|
984
|
+
if (this.scrollCheckPending) return;
|
|
985
|
+
this.scrollCheckPending = true;
|
|
986
|
+
setTimeout(() => {
|
|
987
|
+
this.scrollCheckPending = false;
|
|
988
|
+
this.checkScrollDepth();
|
|
989
|
+
}, 100);
|
|
990
|
+
}, { passive: true });
|
|
913
991
|
window.addEventListener("error", (e) => {
|
|
914
992
|
this.error("javascript", e.message, {
|
|
915
993
|
filename: e.filename,
|
|
@@ -922,6 +1000,22 @@ var VeyaAnalyticsSDK = (() => {
|
|
|
922
1000
|
this.error("promise_rejection", ((_a = e.reason) == null ? void 0 : _a.message) || String(e.reason));
|
|
923
1001
|
});
|
|
924
1002
|
}
|
|
1003
|
+
timeOnPage() {
|
|
1004
|
+
return Math.max(0, Date.now() - this.pageStartedAt);
|
|
1005
|
+
}
|
|
1006
|
+
// Fires every threshold at or below the current depth that hasn't fired yet on this page, so a
|
|
1007
|
+
// fast scroll that jumps past several thresholds still reports each of them once.
|
|
1008
|
+
checkScrollDepth() {
|
|
1009
|
+
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
|
|
1010
|
+
if (scrollable <= 0) return;
|
|
1011
|
+
const percent = Math.min(100, Math.round(window.scrollY / scrollable * 100));
|
|
1012
|
+
for (const depth of SCROLL_DEPTHS) {
|
|
1013
|
+
if (percent >= depth && !this.scrollDepthsFired.has(depth)) {
|
|
1014
|
+
this.scrollDepthsFired.add(depth);
|
|
1015
|
+
this.track("scroll_depth", { depth });
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
925
1019
|
// ============================================================================
|
|
926
1020
|
// FLUSH OVERRIDE FOR WEB
|
|
927
1021
|
// ============================================================================
|