@dotcms/analytics 1.2.3 → 1.2.4-next.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 +495 -535
- package/lib/core/dot-analytics.content.js +25 -21
- package/lib/core/plugin/impression/dot-analytics.impression-tracker.js +13 -21
- package/lib/core/shared/constants/dot-analytics.constants.d.ts +19 -0
- package/lib/core/shared/constants/dot-analytics.constants.js +18 -15
- package/lib/core/shared/http/dot-analytics.http.d.ts +1 -1
- package/lib/core/shared/http/dot-analytics.http.js +19 -17
- package/lib/core/shared/models/event.model.d.ts +12 -0
- package/lib/core/shared/queue/dot-analytics.queue.utils.d.ts +4 -0
- package/lib/core/shared/queue/dot-analytics.queue.utils.js +122 -41
- package/lib/core/shared/utils/dot-analytics.utils.d.ts +1 -0
- package/lib/core/shared/utils/dot-analytics.utils.js +113 -76
- package/lib/react/hook/useContentAnalytics.d.ts +1 -2
- package/lib/react/hook/useContentAnalytics.js +35 -23
- package/lib/react/hook/useRouterTracker.d.ts +1 -1
- package/lib/react/hook/useRouterTracker.js +11 -13
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ANALYTICS_JS_DEFAULT_PROPERTIES as
|
|
2
|
-
import { DotLogger as
|
|
3
|
-
function
|
|
1
|
+
import { ANALYTICS_JS_DEFAULT_PROPERTIES as p, SESSION_STORAGE_KEY as g, DEFAULT_SESSION_TIMEOUT_MINUTES as T, USER_ID_KEY as f, DEFAULT_IMPRESSION_MUTATION_OBSERVER_DEBOUNCE_MS as I, EXPECTED_UTM_KEYS as D, CONTENTLET_CLASS as h } from "../constants/dot-analytics.constants.js";
|
|
2
|
+
import { DotLogger as y } from "../dot-analytics.logger.js";
|
|
3
|
+
function P(t) {
|
|
4
4
|
const e = [];
|
|
5
5
|
return t.siteAuth?.trim() || e.push('"siteAuth"'), t.server?.trim() || e.push('"server"'), e.length > 0 ? e : null;
|
|
6
6
|
}
|
|
@@ -8,7 +8,7 @@ let d = null, u = null;
|
|
|
8
8
|
const l = (t) => {
|
|
9
9
|
const e = Date.now(), n = Math.random().toString(36).substr(2, 9), s = Math.random().toString(36).substr(2, 9);
|
|
10
10
|
return `${t}_${e}_${n}${s}`;
|
|
11
|
-
},
|
|
11
|
+
}, w = {
|
|
12
12
|
getItem: (t) => {
|
|
13
13
|
try {
|
|
14
14
|
return localStorage.getItem(t);
|
|
@@ -19,20 +19,49 @@ const l = (t) => {
|
|
|
19
19
|
setItem: (t, e) => {
|
|
20
20
|
try {
|
|
21
21
|
localStorage.setItem(t, e);
|
|
22
|
+
} catch (n) {
|
|
23
|
+
throw console.warn(`DotCMS Analytics [Core]: Could not save ${t} to localStorage`), n;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}, R = {
|
|
27
|
+
getItem: (t) => {
|
|
28
|
+
try {
|
|
29
|
+
return sessionStorage.getItem(t);
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
setItem: (t, e) => {
|
|
35
|
+
try {
|
|
36
|
+
sessionStorage.setItem(t, e);
|
|
37
|
+
} catch (n) {
|
|
38
|
+
throw console.warn(`DotCMS Analytics [Core]: Could not save ${t} to sessionStorage`), n;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
removeItem: (t) => {
|
|
42
|
+
try {
|
|
43
|
+
sessionStorage.removeItem(t);
|
|
22
44
|
} catch {
|
|
23
|
-
console.warn(`DotCMS Analytics [Core]: Could not
|
|
45
|
+
console.warn(`DotCMS Analytics [Core]: Could not remove ${t} from sessionStorage`);
|
|
24
46
|
}
|
|
25
47
|
}
|
|
26
|
-
},
|
|
27
|
-
let t =
|
|
28
|
-
|
|
29
|
-
|
|
48
|
+
}, E = () => {
|
|
49
|
+
let t = w.getItem(f);
|
|
50
|
+
if (!t) {
|
|
51
|
+
t = l("user");
|
|
52
|
+
try {
|
|
53
|
+
w.setItem(f, t);
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return t;
|
|
58
|
+
}, C = (t) => {
|
|
30
59
|
const e = new Date(t), n = /* @__PURE__ */ new Date(), s = new Date(
|
|
31
60
|
e.getUTCFullYear(),
|
|
32
61
|
e.getUTCMonth(),
|
|
33
62
|
e.getUTCDate()
|
|
34
|
-
),
|
|
35
|
-
return s.getTime() !==
|
|
63
|
+
), o = new Date(n.getUTCFullYear(), n.getUTCMonth(), n.getUTCDate());
|
|
64
|
+
return s.getTime() !== o.getTime();
|
|
36
65
|
}, v = () => {
|
|
37
66
|
const t = Date.now();
|
|
38
67
|
if (typeof window > "u")
|
|
@@ -40,16 +69,16 @@ const l = (t) => {
|
|
|
40
69
|
try {
|
|
41
70
|
const e = sessionStorage.getItem(g);
|
|
42
71
|
if (e) {
|
|
43
|
-
const { sessionId:
|
|
44
|
-
if (
|
|
72
|
+
const { sessionId: o, startTime: r, lastActivity: c } = JSON.parse(e), a = !C(r), i = t - c < T * 60 * 1e3;
|
|
73
|
+
if (a && i)
|
|
45
74
|
return sessionStorage.setItem(
|
|
46
75
|
g,
|
|
47
76
|
JSON.stringify({
|
|
48
|
-
sessionId:
|
|
49
|
-
startTime:
|
|
77
|
+
sessionId: o,
|
|
78
|
+
startTime: r,
|
|
50
79
|
lastActivity: t
|
|
51
80
|
})
|
|
52
|
-
),
|
|
81
|
+
), o;
|
|
53
82
|
}
|
|
54
83
|
const n = l("session"), s = {
|
|
55
84
|
sessionId: n,
|
|
@@ -60,58 +89,58 @@ const l = (t) => {
|
|
|
60
89
|
} catch {
|
|
61
90
|
return l("session_fallback");
|
|
62
91
|
}
|
|
63
|
-
},
|
|
64
|
-
const e = v(), n =
|
|
92
|
+
}, x = (t) => {
|
|
93
|
+
const e = v(), n = E(), s = A();
|
|
65
94
|
return {
|
|
66
95
|
site_auth: t.siteAuth,
|
|
67
96
|
session_id: e,
|
|
68
97
|
user_id: n,
|
|
69
98
|
device: s
|
|
70
99
|
};
|
|
71
|
-
},
|
|
100
|
+
}, _ = () => d || (d = {
|
|
72
101
|
user_language: navigator.language,
|
|
73
102
|
doc_encoding: document.characterSet || document.charset,
|
|
74
103
|
screen_resolution: typeof screen < "u" && screen.width && screen.height ? `${screen.width}x${screen.height}` : ""
|
|
75
|
-
}, d),
|
|
76
|
-
const t =
|
|
104
|
+
}, d), A = () => {
|
|
105
|
+
const t = _(), e = window.innerWidth || document.documentElement.clientWidth || 0, n = window.innerHeight || document.documentElement.clientHeight || 0;
|
|
77
106
|
return {
|
|
78
107
|
screen_resolution: t.screen_resolution ?? "",
|
|
79
108
|
language: t.user_language ?? "",
|
|
80
109
|
viewport_width: String(e),
|
|
81
110
|
viewport_height: String(n)
|
|
82
111
|
};
|
|
83
|
-
},
|
|
112
|
+
}, b = (t) => {
|
|
84
113
|
const e = t.search;
|
|
85
114
|
if (u && u.search === e)
|
|
86
115
|
return u.params;
|
|
87
116
|
const n = new URLSearchParams(e), s = {};
|
|
88
|
-
return D.forEach((
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
const
|
|
92
|
-
s[
|
|
117
|
+
return D.forEach((o) => {
|
|
118
|
+
const r = n.get(o);
|
|
119
|
+
if (r) {
|
|
120
|
+
const c = o.replace("utm_", "");
|
|
121
|
+
s[c] = r;
|
|
93
122
|
}
|
|
94
123
|
}), u = { search: e, params: s }, s;
|
|
95
124
|
}, O = () => {
|
|
96
125
|
try {
|
|
97
|
-
const t = (/* @__PURE__ */ new Date()).getTimezoneOffset(), e = t > 0 ? "-" : "+", n = Math.abs(t), s = Math.floor(n / 60),
|
|
98
|
-
return `${e}${s.toString().padStart(2, "0")}:${
|
|
126
|
+
const t = (/* @__PURE__ */ new Date()).getTimezoneOffset(), e = t > 0 ? "-" : "+", n = Math.abs(t), s = Math.floor(n / 60), o = n % 60;
|
|
127
|
+
return `${e}${s.toString().padStart(2, "0")}:${o.toString().padStart(2, "0")}`;
|
|
99
128
|
} catch {
|
|
100
129
|
return "+00:00";
|
|
101
130
|
}
|
|
102
|
-
},
|
|
131
|
+
}, M = () => {
|
|
103
132
|
try {
|
|
104
|
-
const t = /* @__PURE__ */ new Date(), e = O(), n = t.getFullYear(), s = (t.getMonth() + 1).toString().padStart(2, "0"),
|
|
105
|
-
return `${n}-${s}-${
|
|
133
|
+
const t = /* @__PURE__ */ new Date(), e = O(), n = t.getFullYear(), s = (t.getMonth() + 1).toString().padStart(2, "0"), o = t.getDate().toString().padStart(2, "0"), r = t.getHours().toString().padStart(2, "0"), c = t.getMinutes().toString().padStart(2, "0"), a = t.getSeconds().toString().padStart(2, "0");
|
|
134
|
+
return `${n}-${s}-${o}T${r}:${c}:${a}${e}`;
|
|
106
135
|
} catch {
|
|
107
136
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
108
137
|
}
|
|
109
|
-
},
|
|
110
|
-
const n =
|
|
111
|
-
Object.keys(
|
|
112
|
-
|
|
138
|
+
}, Y = (t, e = typeof window < "u" ? window.location : {}) => {
|
|
139
|
+
const n = M(), s = _(), { properties: o } = t, r = {};
|
|
140
|
+
Object.keys(o).forEach((i) => {
|
|
141
|
+
p.includes(i) || (r[i] = o[i]);
|
|
113
142
|
});
|
|
114
|
-
const
|
|
143
|
+
const c = {
|
|
115
144
|
url: e.href,
|
|
116
145
|
doc_encoding: s.doc_encoding,
|
|
117
146
|
doc_hash: e.hash,
|
|
@@ -119,28 +148,28 @@ const l = (t) => {
|
|
|
119
148
|
doc_search: e.search,
|
|
120
149
|
doc_host: e.hostname,
|
|
121
150
|
doc_path: e.pathname,
|
|
122
|
-
title:
|
|
123
|
-
},
|
|
151
|
+
title: o.title ?? document?.title
|
|
152
|
+
}, a = b(e);
|
|
124
153
|
return {
|
|
125
154
|
...t,
|
|
126
|
-
page:
|
|
127
|
-
...Object.keys(
|
|
155
|
+
page: c,
|
|
156
|
+
...Object.keys(a).length > 0 && { utm: a },
|
|
128
157
|
// Only include custom if there are user-provided properties
|
|
129
|
-
...Object.keys(
|
|
158
|
+
...Object.keys(r).length > 0 && { custom: r },
|
|
130
159
|
local_time: n
|
|
131
160
|
};
|
|
132
161
|
};
|
|
133
|
-
function
|
|
162
|
+
function L(t, e) {
|
|
134
163
|
let n = 0;
|
|
135
164
|
return (...s) => {
|
|
136
|
-
const
|
|
137
|
-
|
|
165
|
+
const o = Date.now();
|
|
166
|
+
o - n >= e && (t(...s), n = o);
|
|
138
167
|
};
|
|
139
168
|
}
|
|
140
|
-
function
|
|
169
|
+
function B(t) {
|
|
141
170
|
return t.dataset.dotIdentifier || null;
|
|
142
171
|
}
|
|
143
|
-
function
|
|
172
|
+
function F(t) {
|
|
144
173
|
return {
|
|
145
174
|
identifier: t.dataset.dotIdentifier || "",
|
|
146
175
|
inode: t.dataset.dotInode || "",
|
|
@@ -149,51 +178,59 @@ function Y(t) {
|
|
|
149
178
|
baseType: t.dataset.dotBasetype || ""
|
|
150
179
|
};
|
|
151
180
|
}
|
|
152
|
-
const
|
|
153
|
-
const n =
|
|
181
|
+
const z = 100, N = () => typeof window < "u" && typeof document < "u", H = () => Array.from(document.querySelectorAll(`.${h}`)), J = (t, e = I) => {
|
|
182
|
+
const n = L(t, e), s = new MutationObserver((r) => {
|
|
154
183
|
r.some((a) => a.addedNodes.length === 0 && a.removedNodes.length === 0 ? !1 : [
|
|
155
184
|
...Array.from(a.addedNodes),
|
|
156
185
|
...Array.from(a.removedNodes)
|
|
157
|
-
].some((
|
|
158
|
-
if (
|
|
186
|
+
].some((m) => {
|
|
187
|
+
if (m.nodeType !== Node.ELEMENT_NODE)
|
|
159
188
|
return !1;
|
|
160
|
-
const S =
|
|
189
|
+
const S = m;
|
|
161
190
|
return S.classList?.contains(h) ? !0 : S.querySelector?.(`.${h}`) !== null;
|
|
162
191
|
})) && n();
|
|
163
|
-
});
|
|
164
|
-
return s.observe(
|
|
192
|
+
}), o = document.body || document.documentElement;
|
|
193
|
+
return o ? s.observe(o, {
|
|
165
194
|
childList: !0,
|
|
166
195
|
subtree: !0,
|
|
167
196
|
attributes: !1,
|
|
168
197
|
characterData: !1
|
|
198
|
+
}) : window.addEventListener("DOMContentLoaded", () => {
|
|
199
|
+
document.body && s.observe(document.body, {
|
|
200
|
+
childList: !0,
|
|
201
|
+
subtree: !0,
|
|
202
|
+
attributes: !1,
|
|
203
|
+
characterData: !1
|
|
204
|
+
});
|
|
169
205
|
}), s;
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
},
|
|
206
|
+
}, K = (t) => {
|
|
207
|
+
N() && (window.addEventListener("beforeunload", t), window.addEventListener("pagehide", t));
|
|
208
|
+
}, j = (t, e) => {
|
|
173
209
|
const n = e.logLevel ?? (e.debug ? "debug" : "warn");
|
|
174
|
-
return new
|
|
175
|
-
},
|
|
210
|
+
return new y("Analytics", t, n);
|
|
211
|
+
}, W = (t, e, n) => [
|
|
176
212
|
t.impressions && e(t),
|
|
177
213
|
t.clicks && n(t)
|
|
178
214
|
].filter(Boolean);
|
|
179
215
|
export {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
216
|
+
z as INITIAL_SCAN_DELAY_MS,
|
|
217
|
+
J as createContentletObserver,
|
|
218
|
+
j as createPluginLogger,
|
|
219
|
+
L as createThrottle,
|
|
220
|
+
Y as enrichPagePayloadOptimized,
|
|
221
|
+
F as extractContentletData,
|
|
222
|
+
B as extractContentletIdentifier,
|
|
223
|
+
b as extractUTMParameters,
|
|
224
|
+
H as findContentlets,
|
|
189
225
|
l as generateSecureId,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
226
|
+
x as getAnalyticsContext,
|
|
227
|
+
A as getDeviceDataForContext,
|
|
228
|
+
W as getEnhancedTrackingPlugins,
|
|
229
|
+
M as getLocalTime,
|
|
194
230
|
v as getSessionId,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
E as getUserId,
|
|
232
|
+
N as isBrowser,
|
|
233
|
+
R as safeSessionStorage,
|
|
234
|
+
K as setupPluginCleanup,
|
|
235
|
+
P as validateAnalyticsConfig
|
|
199
236
|
};
|
|
@@ -51,7 +51,6 @@ import { DotCMSAnalytics, DotCMSAnalyticsConfig } from '../../core/shared/models
|
|
|
51
51
|
* @param config.server - The URL of your DotCMS Analytics server
|
|
52
52
|
* @param config.siteKey - Your unique site key for authentication
|
|
53
53
|
* @param config.debug - Optional. Set to true to see analytics events in the console
|
|
54
|
-
* @returns Object with `track()` and `
|
|
55
|
-
* @throws {Error} If the configuration is invalid (missing server or siteKey)
|
|
54
|
+
* @returns Object with `track()`, `pageView()`, and `conversion()` methods for analytics tracking
|
|
56
55
|
*/
|
|
57
56
|
export declare const useContentAnalytics: (config: DotCMSAnalyticsConfig) => DotCMSAnalytics;
|
|
@@ -1,35 +1,47 @@
|
|
|
1
|
-
import { useMemo as
|
|
1
|
+
import { useMemo as c, useCallback as r } from "react";
|
|
2
2
|
import { getUVEState as l } from "../../../uve/src/lib/core/core.utils.js";
|
|
3
3
|
import "../../../uve/src/internal/constants.js";
|
|
4
|
-
import { initializeAnalytics as
|
|
5
|
-
const
|
|
6
|
-
|
|
4
|
+
import { initializeAnalytics as u } from "../internal/utils.js";
|
|
5
|
+
const A = {
|
|
6
|
+
track: () => {
|
|
7
|
+
},
|
|
8
|
+
pageView: () => {
|
|
9
|
+
},
|
|
10
|
+
conversion: () => {
|
|
11
|
+
}
|
|
12
|
+
}, v = (i) => {
|
|
13
|
+
const t = c(() => {
|
|
14
|
+
const e = u(i);
|
|
15
|
+
return e || (l() ? console.warn(
|
|
16
|
+
"DotCMS Analytics [React]: Analytics is not initialized because the site is inside the UVE editor. All tracking calls will be ignored."
|
|
17
|
+
) : console.error(
|
|
18
|
+
"DotCMS Analytics [React]: Failed to initialize. Please verify the required configuration (server and siteAuth)."
|
|
19
|
+
)), e;
|
|
20
|
+
}, [i.server, i.siteAuth]);
|
|
7
21
|
if (!t)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
(r, n = {}) => {
|
|
13
|
-
e || t.track(r, n);
|
|
22
|
+
return A;
|
|
23
|
+
const o = r(
|
|
24
|
+
(e, n = {}) => {
|
|
25
|
+
t.track(e, n);
|
|
14
26
|
},
|
|
15
|
-
[t
|
|
16
|
-
),
|
|
17
|
-
(
|
|
18
|
-
|
|
27
|
+
[t]
|
|
28
|
+
), s = r(
|
|
29
|
+
(e = {}) => {
|
|
30
|
+
t.pageView(e);
|
|
19
31
|
},
|
|
20
|
-
[t
|
|
21
|
-
),
|
|
22
|
-
(
|
|
23
|
-
|
|
32
|
+
[t]
|
|
33
|
+
), a = r(
|
|
34
|
+
(e, n = {}) => {
|
|
35
|
+
t.conversion(e, n);
|
|
24
36
|
},
|
|
25
|
-
[t
|
|
37
|
+
[t]
|
|
26
38
|
);
|
|
27
39
|
return {
|
|
28
|
-
track:
|
|
29
|
-
pageView:
|
|
30
|
-
conversion:
|
|
40
|
+
track: o,
|
|
41
|
+
pageView: s,
|
|
42
|
+
conversion: a
|
|
31
43
|
};
|
|
32
44
|
};
|
|
33
45
|
export {
|
|
34
|
-
|
|
46
|
+
v as useContentAnalytics
|
|
35
47
|
};
|
|
@@ -2,7 +2,7 @@ import { DotCMSAnalytics } from '../../core/shared/models';
|
|
|
2
2
|
/**
|
|
3
3
|
* Tracks page views on route changes using Next.js App Router signals.
|
|
4
4
|
* - Fires a single pageView per unique path+search.
|
|
5
|
-
* -
|
|
5
|
+
* - Automatically disabled inside UVE editor (analytics instance is null).
|
|
6
6
|
* - Requires Next.js App Router; no SPA fallback.
|
|
7
7
|
*
|
|
8
8
|
* @param analytics Analytics singleton instance; if null, does nothing
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { usePathname as
|
|
2
|
-
import { useRef as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
function l(t, e = !1) {
|
|
7
|
-
const r = c(null), o = s(), n = u();
|
|
1
|
+
import { usePathname as f, useSearchParams as u } from "next/navigation";
|
|
2
|
+
import { useRef as i, useEffect as a } from "react";
|
|
3
|
+
const m = (e, t) => `${e}${t?.toString() ? "?" + t.toString() : ""}`;
|
|
4
|
+
function R(e, t = !1) {
|
|
5
|
+
const r = i(null), n = f(), o = u();
|
|
8
6
|
a(() => {
|
|
9
|
-
if (!
|
|
10
|
-
const
|
|
11
|
-
|
|
7
|
+
if (!e) return;
|
|
8
|
+
const c = (s) => {
|
|
9
|
+
s !== r.current && (r.current = s, e.pageView());
|
|
12
10
|
};
|
|
13
|
-
|
|
14
|
-
}, [
|
|
11
|
+
t && console.info("DotCMS Analytics [React]: using Next.js App Router tracking"), c(m(n, o));
|
|
12
|
+
}, [e, n, o, t]);
|
|
15
13
|
}
|
|
16
14
|
export {
|
|
17
|
-
|
|
15
|
+
R as useRouterTracker
|
|
18
16
|
};
|