@jmp-technologies/analytics 0.1.16 → 0.1.18
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 +3 -1
- package/dist/{chunk-AEQGPTDY.js → chunk-SOHYQ5GT.js} +284 -79
- package/dist/chunk-SOHYQ5GT.js.map +1 -0
- package/dist/{chunk-P4IKTSPX.js → chunk-W7CQ5VG2.js} +2 -2
- package/dist/index.cjs +290 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -14
- package/dist/index.d.ts +70 -14
- package/dist/index.js +15 -3
- package/dist/next.cjs +295 -86
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +13 -6
- package/dist/next.d.ts +13 -6
- package/dist/next.js +27 -13
- package/dist/next.js.map +1 -1
- package/dist/react.cjs +263 -69
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +2 -2
- package/docs/legal-and-privacy.md +1 -0
- package/package.json +1 -1
- package/dist/chunk-AEQGPTDY.js.map +0 -1
- /package/dist/{chunk-P4IKTSPX.js.map → chunk-W7CQ5VG2.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -20,8 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
BOOKING_LINK_HOSTS: () => BOOKING_LINK_HOSTS,
|
|
23
24
|
DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS: () => DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
25
|
+
JMP_ANALYTICS_SDK_VERSION: () => JMP_ANALYTICS_SDK_VERSION,
|
|
26
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY: () => JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
24
27
|
buildLandingCaptureInlineScript: () => buildLandingCaptureInlineScript,
|
|
28
|
+
classifyContactHref: () => classifyContactHref,
|
|
25
29
|
createJmpAnalytics: () => createJmpAnalytics,
|
|
26
30
|
createJmpContentClient: () => createJmpContentClient,
|
|
27
31
|
createJmpContentClientFromServerEnv: () => createJmpContentClientFromServerEnv,
|
|
@@ -36,9 +40,11 @@ __export(index_exports, {
|
|
|
36
40
|
getOrCreateJmpAnalyticsFromBrowserEnv: () => getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
37
41
|
isJmpBrowserAnalyticsEnvConfigured: () => isJmpBrowserAnalyticsEnvConfigured,
|
|
38
42
|
isJmpServerContentEnvConfigured: () => isJmpServerContentEnvConfigured,
|
|
43
|
+
isJmpTrackingConsentGranted: () => isJmpTrackingConsentGranted,
|
|
39
44
|
registerJmpContentWrappers: () => registerJmpContentWrappers,
|
|
40
45
|
registerJmpTrustCapabilities: () => registerJmpTrustCapabilities,
|
|
41
|
-
|
|
46
|
+
setJmpTrackingConsent: () => setJmpTrackingConsent,
|
|
47
|
+
subscribeJmpTrackingConsent: () => subscribeJmpTrackingConsent,
|
|
42
48
|
trackJmpServerPageView: () => trackJmpServerPageView
|
|
43
49
|
});
|
|
44
50
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -48,7 +54,6 @@ var JMP_SESSION_ID_KEY = "jmp_analytics_sid";
|
|
|
48
54
|
var JMP_LANDING_REFERER_KEY = "jmp_analytics_landing_referer";
|
|
49
55
|
var JMP_LANDING_REFERER_COOKIE = "jmp_lr";
|
|
50
56
|
var JMP_UTM_SESSION_KEY = "jmp_analytics_utm";
|
|
51
|
-
var JMP_EARLY_BEACON_PATH_KEY = "jmp_analytics_early_beacon_path";
|
|
52
57
|
var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
|
|
53
58
|
var JMP_UTM_PARAM_KEYS = [
|
|
54
59
|
"utm_source",
|
|
@@ -134,11 +139,9 @@ function captureLandingAttribution(siteHostname) {
|
|
|
134
139
|
const preservedReferer = storedReferer || cookieReferer;
|
|
135
140
|
const currentReferer = document.referrer?.trim() || null;
|
|
136
141
|
if (currentReferer && isExternalReferrerUrl(currentReferer, siteHostname)) {
|
|
137
|
-
|
|
138
|
-
sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
|
|
139
|
-
}
|
|
142
|
+
sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
|
|
140
143
|
writeLandingRefererCookie(currentReferer, siteHostname);
|
|
141
|
-
landingReferer =
|
|
144
|
+
landingReferer = currentReferer;
|
|
142
145
|
} else if (preservedReferer) {
|
|
143
146
|
landingReferer = preservedReferer;
|
|
144
147
|
if (!storedReferer) {
|
|
@@ -183,84 +186,175 @@ function getOrCreateSessionIdFromStorage() {
|
|
|
183
186
|
return void 0;
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
|
-
function
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
function buildLandingCaptureInlineScript() {
|
|
190
|
+
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
191
|
+
return `(function(){try{var h=location.hostname;var ref=document.referrer||'';function rh(u){try{return new URL(u).hostname.replace(/^www\\./i,'').toLowerCase()}catch(e){try{return new URL('https://'+u).hostname.replace(/^www\\./i,'').toLowerCase()}catch(e2){return null}}}function ext(r){var x=rh(r);if(!x)return false;var s=h.replace(/^www\\./i,'').toLowerCase();return x!==s&&x.slice(-('.'+s).length)!==('.'+s)}function apexDom(hn){var s=hn.replace(/^www\\./i,'').toLowerCase();if(!s||s==='localhost'||/\\.local$/i.test(s)||s.indexOf('.')<0)return null;return s}function readCk(hn){var apex=apexDom(hn);if(!apex)return '';var pre='${JMP_LANDING_REFERER_COOKIE}=';var parts=document.cookie.split(';');for(var i=0;i<parts.length;i++){var t=parts[i].trim();if(t.indexOf(pre)===0){try{return decodeURIComponent(t.slice(pre.length)).trim()}catch(e){return ''}}}return ''}function writeCk(r,hn){var apex=apexDom(hn);if(!apex)return;var sec=location.protocol==='https:'?'; Secure':'';document.cookie='${JMP_LANDING_REFERER_COOKIE}='+encodeURIComponent(r.slice(0,2048))+'; Domain=.'+apex+'; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax'+sec}var stored=sessionStorage.getItem('${JMP_LANDING_REFERER_KEY}')||'';var ck=readCk(h);var preserved=stored||ck;var lr='';if(ref&&ext(ref)){sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',ref);writeCk(ref,h);lr=ref}else{lr=preserved||'';if(lr&&!stored)sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',lr)}var sid=sessionStorage.getItem('${JMP_SESSION_ID_KEY}');if(!sid&&crypto&&crypto.randomUUID){sid=crypto.randomUUID();sessionStorage.setItem('${JMP_SESSION_ID_KEY}',sid)}try{var sp=new URLSearchParams(location.search);var utm={};var updated=false;['utm_source','utm_medium','utm_campaign','utm_content','utm_term'].forEach(function(n){var v=sp.get(n);if(v){utm[n]=v;updated=true}});if(updated)sessionStorage.setItem('${JMP_UTM_SESSION_KEY}',JSON.stringify(utm))}catch(e){}}catch(e){}})();`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/contact-link-classifier.ts
|
|
195
|
+
var BOOKING_LINK_HOSTS = [
|
|
196
|
+
"calendly.com",
|
|
197
|
+
"cal.com",
|
|
198
|
+
"acuityscheduling.com",
|
|
199
|
+
"calendar.google.com",
|
|
200
|
+
"calendar.app.google",
|
|
201
|
+
"bookings.microsoft.com",
|
|
202
|
+
"outlook.office.com",
|
|
203
|
+
"outlook.office365.com",
|
|
204
|
+
"book.ms",
|
|
205
|
+
"setmore.com",
|
|
206
|
+
"simplybook.me",
|
|
207
|
+
"oncehub.com",
|
|
208
|
+
"scheduleonce.com",
|
|
209
|
+
"youcanbook.me",
|
|
210
|
+
"savvycal.com",
|
|
211
|
+
"tidycal.com",
|
|
212
|
+
"zohobookings.com",
|
|
213
|
+
"square.site",
|
|
214
|
+
"squareup.com",
|
|
215
|
+
"meetings.hubspot.com",
|
|
216
|
+
"jobber.com",
|
|
217
|
+
"housecallpro.com",
|
|
218
|
+
"servicetitan.com",
|
|
219
|
+
"thryv.com",
|
|
220
|
+
"honeybook.com",
|
|
221
|
+
"dubsado.com",
|
|
222
|
+
"fresha.com",
|
|
223
|
+
"booksy.com",
|
|
224
|
+
"vagaro.com",
|
|
225
|
+
"mindbodyonline.com",
|
|
226
|
+
"mindbody.io",
|
|
227
|
+
"janeapp.com",
|
|
228
|
+
"cliniko.com",
|
|
229
|
+
"practicebetter.io"
|
|
230
|
+
];
|
|
231
|
+
var WHATSAPP_HOSTS = ["wa.me", "api.whatsapp.com", "whatsapp.com"];
|
|
232
|
+
function hostnameMatches(host, pattern) {
|
|
233
|
+
const h = host.toLowerCase();
|
|
234
|
+
const p = pattern.toLowerCase();
|
|
235
|
+
return h === p || h.endsWith(`.${p}`);
|
|
236
|
+
}
|
|
237
|
+
function isMapsHost(host, pathname) {
|
|
238
|
+
if (hostnameMatches(host, "maps.apple.com")) {
|
|
239
|
+
return true;
|
|
189
240
|
}
|
|
190
|
-
|
|
191
|
-
return
|
|
192
|
-
}
|
|
193
|
-
|
|
241
|
+
if (hostnameMatches(host, "maps.app.goo.gl")) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (hostnameMatches(host, "google.com") || hostnameMatches(host, "google.co")) {
|
|
245
|
+
return pathname === "/maps" || pathname.startsWith("/maps/") || pathname.startsWith("/local");
|
|
194
246
|
}
|
|
247
|
+
return false;
|
|
195
248
|
}
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
249
|
+
function isWhatsAppHost(host, pathname) {
|
|
250
|
+
for (const pattern of WHATSAPP_HOSTS) {
|
|
251
|
+
if (!hostnameMatches(host, pattern)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (pattern === "whatsapp.com") {
|
|
255
|
+
return pathname.startsWith("/send");
|
|
256
|
+
}
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
function isBookingHost(host) {
|
|
262
|
+
for (const pattern of BOOKING_LINK_HOSTS) {
|
|
263
|
+
if (hostnameMatches(host, pattern)) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
function classifyContactHref(href) {
|
|
270
|
+
const raw = href.trim();
|
|
271
|
+
if (!raw || raw.startsWith("#") || raw.startsWith("javascript:")) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const lower = raw.toLowerCase();
|
|
275
|
+
if (lower.startsWith("tel:")) {
|
|
276
|
+
return { kind: "call" };
|
|
277
|
+
}
|
|
278
|
+
if (lower.startsWith("mailto:")) {
|
|
279
|
+
return { kind: "email" };
|
|
280
|
+
}
|
|
281
|
+
if (lower.startsWith("sms:") || lower.startsWith("smsto:")) {
|
|
282
|
+
return { kind: "contact_click", channel: "sms", linkHost: null };
|
|
199
283
|
}
|
|
284
|
+
if (lower.startsWith("geo:")) {
|
|
285
|
+
return { kind: "contact_click", channel: "maps", linkHost: null };
|
|
286
|
+
}
|
|
287
|
+
if (raw.startsWith("/") || raw.startsWith("?")) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
let url;
|
|
200
291
|
try {
|
|
201
|
-
|
|
292
|
+
url = new URL(raw);
|
|
202
293
|
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
const host = url.hostname.toLowerCase();
|
|
300
|
+
const pathname = url.pathname.toLowerCase();
|
|
301
|
+
if (isWhatsAppHost(host, pathname)) {
|
|
302
|
+
return { kind: "contact_click", channel: "whatsapp", linkHost: host };
|
|
203
303
|
}
|
|
304
|
+
if (isMapsHost(host, pathname)) {
|
|
305
|
+
return { kind: "contact_click", channel: "maps", linkHost: host };
|
|
306
|
+
}
|
|
307
|
+
if (isBookingHost(host)) {
|
|
308
|
+
return { kind: "contact_click", channel: "booking", linkHost: host };
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
204
311
|
}
|
|
205
|
-
|
|
206
|
-
|
|
312
|
+
|
|
313
|
+
// src/index.ts
|
|
314
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.18";
|
|
315
|
+
var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
|
|
316
|
+
var moduleTrackingConsentGranted = true;
|
|
317
|
+
var trackingConsentListeners = /* @__PURE__ */ new Set();
|
|
318
|
+
function readStoredTrackingConsent() {
|
|
319
|
+
if (typeof window === "undefined") {
|
|
207
320
|
return false;
|
|
208
321
|
}
|
|
209
|
-
|
|
210
|
-
|
|
322
|
+
try {
|
|
323
|
+
return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
|
|
324
|
+
} catch {
|
|
211
325
|
return false;
|
|
212
326
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
metadata.referer = landingReferer;
|
|
222
|
-
}
|
|
223
|
-
const payload = {
|
|
224
|
-
type: "page_view",
|
|
225
|
-
path,
|
|
226
|
-
trackingKey: args.trackingKey,
|
|
227
|
-
...sessionId ? { sessionId } : {},
|
|
228
|
-
metadata
|
|
229
|
-
};
|
|
230
|
-
const headers = {
|
|
231
|
-
"Content-Type": "application/json",
|
|
232
|
-
"X-JMP-Tracking-Key": args.trackingKey
|
|
327
|
+
}
|
|
328
|
+
function isJmpTrackingConsentGranted() {
|
|
329
|
+
return moduleTrackingConsentGranted;
|
|
330
|
+
}
|
|
331
|
+
function subscribeJmpTrackingConsent(listener) {
|
|
332
|
+
trackingConsentListeners.add(listener);
|
|
333
|
+
return () => {
|
|
334
|
+
trackingConsentListeners.delete(listener);
|
|
233
335
|
};
|
|
234
|
-
|
|
235
|
-
|
|
336
|
+
}
|
|
337
|
+
function setJmpTrackingConsent(granted) {
|
|
338
|
+
if (moduleTrackingConsentGranted === granted) {
|
|
339
|
+
return;
|
|
236
340
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
method: "POST",
|
|
240
|
-
headers,
|
|
241
|
-
body: JSON.stringify(payload),
|
|
242
|
-
keepalive: true,
|
|
243
|
-
mode: "cors",
|
|
244
|
-
credentials: "omit"
|
|
245
|
-
}).catch(() => {
|
|
341
|
+
moduleTrackingConsentGranted = granted;
|
|
342
|
+
if (typeof window !== "undefined") {
|
|
246
343
|
try {
|
|
247
|
-
|
|
344
|
+
localStorage.setItem(
|
|
345
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
346
|
+
granted ? "granted" : "denied"
|
|
347
|
+
);
|
|
248
348
|
} catch {
|
|
249
349
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const baseUrl = escapeInlineScript(args.baseUrl.replace(/\/$/, ""));
|
|
258
|
-
const trackingKey = escapeInlineScript(args.trackingKey);
|
|
259
|
-
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
260
|
-
return `(function(){try{var k='${trackingKey}',b='${baseUrl}';if(!k||!b)return;var p=location.pathname+location.search||'/';var sentKey='${JMP_EARLY_BEACON_PATH_KEY}';if(sessionStorage.getItem(sentKey)===p)return;var h=location.hostname;var ref=document.referrer||'';function rh(u){try{return new URL(u).hostname.replace(/^www\\./i,'').toLowerCase()}catch(e){try{return new URL('https://'+u).hostname.replace(/^www\\./i,'').toLowerCase()}catch(e2){return null}}}function ext(r){var x=rh(r);if(!x)return false;var s=h.replace(/^www\\./i,'').toLowerCase();return x!==s&&x.slice(-('.'+s).length)!==('.'+s)}function apexDom(hn){var s=hn.replace(/^www\\./i,'').toLowerCase();if(!s||s==='localhost'||/\\.local$/i.test(s)||s.indexOf('.')<0)return null;return s}function readCk(hn){var apex=apexDom(hn);if(!apex)return '';var pre='${JMP_LANDING_REFERER_COOKIE}=';var parts=document.cookie.split(';');for(var i=0;i<parts.length;i++){var t=parts[i].trim();if(t.indexOf(pre)===0){try{return decodeURIComponent(t.slice(pre.length)).trim()}catch(e){return ''}}}return ''}function writeCk(r,hn){var apex=apexDom(hn);if(!apex)return;var sec=location.protocol==='https:'?'; Secure':'';document.cookie='${JMP_LANDING_REFERER_COOKIE}='+encodeURIComponent(r.slice(0,2048))+'; Domain=.'+apex+'; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax'+sec}var stored=sessionStorage.getItem('${JMP_LANDING_REFERER_KEY}')||'';var ck=readCk(h);var preserved=stored||ck;var lr='';if(ref&&ext(ref)){if(!stored)sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',ref);writeCk(ref,h);lr=preserved||ref}else{lr=preserved||'';if(lr&&!stored)sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',lr)}var sid=sessionStorage.getItem('${JMP_SESSION_ID_KEY}');if(!sid&&crypto&&crypto.randomUUID){sid=crypto.randomUUID();sessionStorage.setItem('${JMP_SESSION_ID_KEY}',sid)}var md={pageHostname:h,earlyBeacon:true};try{var sp=new URLSearchParams(location.search);['utm_source','utm_medium','utm_campaign','utm_content','utm_term'].forEach(function(n){var v=sp.get(n);if(v)md[n]=v})}catch(e){}if(lr)md.referer=lr;var body=JSON.stringify({type:'page_view',path:p,trackingKey:k,sessionId:sid||undefined,metadata:md});var hd={'Content-Type':'application/json','X-JMP-Tracking-Key':k};if(lr)hd['X-JMP-Visitor-Referer']=lr;sessionStorage.setItem(sentKey,p);fetch(b+'/api/events',{method:'POST',headers:hd,body:body,keepalive:true,mode:'cors',credentials:'omit'}).catch(function(){sessionStorage.removeItem(sentKey)})}catch(e){}})();`;
|
|
350
|
+
if (granted) {
|
|
351
|
+
captureLandingAttribution(window.location.hostname);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
for (const listener of trackingConsentListeners) {
|
|
355
|
+
listener();
|
|
356
|
+
}
|
|
261
357
|
}
|
|
262
|
-
|
|
263
|
-
// src/index.ts
|
|
264
358
|
function captureAndGetLandingReferer() {
|
|
265
359
|
if (typeof window === "undefined") {
|
|
266
360
|
return null;
|
|
@@ -335,9 +429,16 @@ function createJmpAnalytics(config) {
|
|
|
335
429
|
);
|
|
336
430
|
}
|
|
337
431
|
const fetchFn = resolvedFetch;
|
|
432
|
+
moduleTrackingConsentGranted = config.requireConsent ? readStoredTrackingConsent() : true;
|
|
433
|
+
function canSend() {
|
|
434
|
+
return moduleTrackingConsentGranted;
|
|
435
|
+
}
|
|
338
436
|
let lastDedupePath = "";
|
|
339
437
|
let lastDedupeAt = 0;
|
|
340
438
|
async function send(body) {
|
|
439
|
+
if (!canSend()) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
341
442
|
const url = `${baseUrl}/api/events`;
|
|
342
443
|
const headers = {
|
|
343
444
|
"Content-Type": "application/json",
|
|
@@ -393,6 +494,9 @@ function createJmpAnalytics(config) {
|
|
|
393
494
|
}
|
|
394
495
|
}
|
|
395
496
|
async function sendLead(body) {
|
|
497
|
+
if (!canSend()) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
396
500
|
const url = `${baseUrl}/api/leads`;
|
|
397
501
|
const headers = {
|
|
398
502
|
"Content-Type": "application/json",
|
|
@@ -455,6 +559,9 @@ function createJmpAnalytics(config) {
|
|
|
455
559
|
return false;
|
|
456
560
|
}
|
|
457
561
|
function trackPageView(options) {
|
|
562
|
+
if (!canSend()) {
|
|
563
|
+
return Promise.resolve();
|
|
564
|
+
}
|
|
458
565
|
const pathFromOptions = options?.path?.trim();
|
|
459
566
|
let pathname = "/";
|
|
460
567
|
let search = "";
|
|
@@ -470,9 +577,6 @@ function createJmpAnalytics(config) {
|
|
|
470
577
|
search = window.location.search.replace(/^\?/, "");
|
|
471
578
|
}
|
|
472
579
|
const path = search ? `${pathname}?${search}` : pathname;
|
|
473
|
-
if (wasEarlyBeaconSentForPath(path)) {
|
|
474
|
-
return Promise.resolve();
|
|
475
|
-
}
|
|
476
580
|
if (shouldDedupePageView(pathname)) {
|
|
477
581
|
return Promise.resolve();
|
|
478
582
|
}
|
|
@@ -523,6 +627,20 @@ function createJmpAnalytics(config) {
|
|
|
523
627
|
metadata: metadata ?? {}
|
|
524
628
|
});
|
|
525
629
|
}
|
|
630
|
+
function trackContactClick(path, options) {
|
|
631
|
+
const metadata = {
|
|
632
|
+
...options.metadata && typeof options.metadata === "object" ? options.metadata : {},
|
|
633
|
+
channel: options.channel
|
|
634
|
+
};
|
|
635
|
+
if (options.linkHost) {
|
|
636
|
+
metadata.linkHost = options.linkHost;
|
|
637
|
+
}
|
|
638
|
+
return send({
|
|
639
|
+
type: "contact_click",
|
|
640
|
+
path: path || "/",
|
|
641
|
+
metadata
|
|
642
|
+
});
|
|
643
|
+
}
|
|
526
644
|
function trackLead(options) {
|
|
527
645
|
const path = options?.path ?? (typeof window !== "undefined" ? window.location.pathname : "/");
|
|
528
646
|
const body = { path: path || "/" };
|
|
@@ -555,7 +673,20 @@ function createJmpAnalytics(config) {
|
|
|
555
673
|
if (type === "call_click") {
|
|
556
674
|
return trackCallClick(payload.path, payload.metadata);
|
|
557
675
|
}
|
|
558
|
-
|
|
676
|
+
if (type === "email_click") {
|
|
677
|
+
return trackEmailClick(payload.path, payload.metadata);
|
|
678
|
+
}
|
|
679
|
+
const meta = payload.metadata ?? {};
|
|
680
|
+
const channel = typeof meta.channel === "string" ? meta.channel : "";
|
|
681
|
+
const linkHost = typeof meta.linkHost === "string" ? meta.linkHost : null;
|
|
682
|
+
if (channel !== "sms" && channel !== "whatsapp" && channel !== "maps" && channel !== "booking") {
|
|
683
|
+
return Promise.resolve();
|
|
684
|
+
}
|
|
685
|
+
return trackContactClick(payload.path, {
|
|
686
|
+
channel,
|
|
687
|
+
linkHost,
|
|
688
|
+
metadata: meta
|
|
689
|
+
});
|
|
559
690
|
}
|
|
560
691
|
function subscribeToSpaNavigation() {
|
|
561
692
|
if (typeof window === "undefined") {
|
|
@@ -589,12 +720,75 @@ function createJmpAnalytics(config) {
|
|
|
589
720
|
history.replaceState = replace;
|
|
590
721
|
};
|
|
591
722
|
}
|
|
592
|
-
|
|
723
|
+
let lastContactClickKey = "";
|
|
724
|
+
let lastContactClickAt = 0;
|
|
725
|
+
function subscribeContactLinkAutoTrack() {
|
|
726
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
727
|
+
return () => {
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
const handler = (event) => {
|
|
731
|
+
if (!canSend()) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
const target = event.target;
|
|
735
|
+
if (!(target instanceof Element)) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const anchor = target.closest("a[href]");
|
|
739
|
+
if (!(anchor instanceof HTMLAnchorElement)) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (anchor.closest("[data-jmp-no-track]")) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
746
|
+
const classified = classifyContactHref(href);
|
|
747
|
+
if (!classified) {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const path = window.location.pathname;
|
|
751
|
+
if (classified.kind === "call") {
|
|
752
|
+
if (dedupeContactClick(`call_click:${path}`)) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
void trackCallClick(path);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (classified.kind === "email") {
|
|
759
|
+
if (dedupeContactClick(`email_click:${path}`)) {
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
void trackEmailClick(path);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (dedupeContactClick(`contact_click:${classified.channel}:${path}`)) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
void trackContactClick(path, {
|
|
769
|
+
channel: classified.channel,
|
|
770
|
+
linkHost: classified.linkHost
|
|
771
|
+
});
|
|
772
|
+
};
|
|
773
|
+
document.addEventListener("click", handler, { capture: true });
|
|
774
|
+
return () => {
|
|
775
|
+
document.removeEventListener("click", handler, { capture: true });
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function dedupeContactClick(key) {
|
|
779
|
+
const now = Date.now();
|
|
780
|
+
if (key === lastContactClickKey && now - lastContactClickAt < 1e3) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
lastContactClickKey = key;
|
|
784
|
+
lastContactClickAt = now;
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
if (typeof window !== "undefined" && canSend()) {
|
|
593
788
|
captureLandingAttribution(window.location.hostname);
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
});
|
|
789
|
+
}
|
|
790
|
+
if (typeof window !== "undefined" && config.autoTrackContactLinks && canSend()) {
|
|
791
|
+
subscribeContactLinkAutoTrack();
|
|
598
792
|
}
|
|
599
793
|
return {
|
|
600
794
|
track,
|
|
@@ -602,8 +796,12 @@ function createJmpAnalytics(config) {
|
|
|
602
796
|
trackFormSubmit,
|
|
603
797
|
trackCallClick,
|
|
604
798
|
trackEmailClick,
|
|
799
|
+
trackContactClick,
|
|
605
800
|
trackLead,
|
|
606
|
-
subscribeToSpaNavigation
|
|
801
|
+
subscribeToSpaNavigation,
|
|
802
|
+
subscribeContactLinkAutoTrack,
|
|
803
|
+
setTrackingConsent: setJmpTrackingConsent,
|
|
804
|
+
isTrackingConsentGranted: isJmpTrackingConsentGranted
|
|
607
805
|
};
|
|
608
806
|
}
|
|
609
807
|
async function trackJmpServerPageView(config, options = {}) {
|
|
@@ -726,7 +924,10 @@ async function registerJmpContentWrappers(config) {
|
|
|
726
924
|
"Content-Type": "application/json",
|
|
727
925
|
"X-JMP-Tracking-Key": config.trackingKey
|
|
728
926
|
},
|
|
729
|
-
body: JSON.stringify({
|
|
927
|
+
body: JSON.stringify({
|
|
928
|
+
wrappers,
|
|
929
|
+
sdkVersion: JMP_ANALYTICS_SDK_VERSION
|
|
930
|
+
})
|
|
730
931
|
});
|
|
731
932
|
const text = await res.text();
|
|
732
933
|
if (!res.ok) {
|
|
@@ -824,11 +1025,15 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
|
824
1025
|
const baseUrl = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
825
1026
|
const trackingKey = readProcessEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
826
1027
|
if (!baseUrl || !trackingKey) return null;
|
|
1028
|
+
const requireConsentFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT") === "true";
|
|
1029
|
+
const autoTrackContactLinksFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS") === "true";
|
|
827
1030
|
return {
|
|
828
1031
|
baseUrl,
|
|
829
1032
|
trackingKey,
|
|
830
1033
|
pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
831
|
-
...overrides
|
|
1034
|
+
...overrides,
|
|
1035
|
+
requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,
|
|
1036
|
+
autoTrackContactLinks: overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv
|
|
832
1037
|
};
|
|
833
1038
|
}
|
|
834
1039
|
function getJmpServerContentConfigFromEnv(overrides) {
|
|
@@ -861,8 +1066,12 @@ function createJmpContentClientFromServerEnv(overrides) {
|
|
|
861
1066
|
}
|
|
862
1067
|
// Annotate the CommonJS export names for ESM import in node:
|
|
863
1068
|
0 && (module.exports = {
|
|
1069
|
+
BOOKING_LINK_HOSTS,
|
|
864
1070
|
DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
1071
|
+
JMP_ANALYTICS_SDK_VERSION,
|
|
1072
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
865
1073
|
buildLandingCaptureInlineScript,
|
|
1074
|
+
classifyContactHref,
|
|
866
1075
|
createJmpAnalytics,
|
|
867
1076
|
createJmpContentClient,
|
|
868
1077
|
createJmpContentClientFromServerEnv,
|
|
@@ -877,9 +1086,11 @@ function createJmpContentClientFromServerEnv(overrides) {
|
|
|
877
1086
|
getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
878
1087
|
isJmpBrowserAnalyticsEnvConfigured,
|
|
879
1088
|
isJmpServerContentEnvConfigured,
|
|
1089
|
+
isJmpTrackingConsentGranted,
|
|
880
1090
|
registerJmpContentWrappers,
|
|
881
1091
|
registerJmpTrustCapabilities,
|
|
882
|
-
|
|
1092
|
+
setJmpTrackingConsent,
|
|
1093
|
+
subscribeJmpTrackingConsent,
|
|
883
1094
|
trackJmpServerPageView
|
|
884
1095
|
});
|
|
885
1096
|
//# sourceMappingURL=index.cjs.map
|