@jmp-technologies/analytics 0.1.17 → 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-MUHLIN7P.js → chunk-SOHYQ5GT.js} +282 -75
- package/dist/chunk-SOHYQ5GT.js.map +1 -0
- package/dist/{chunk-3ELQETAA.js → chunk-W7CQ5VG2.js} +2 -2
- package/dist/index.cjs +288 -75
- 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 +293 -82
- 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 +261 -65
- 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-MUHLIN7P.js.map +0 -1
- /package/dist/{chunk-3ELQETAA.js.map → chunk-W7CQ5VG2.js.map} +0 -0
package/dist/next.cjs
CHANGED
|
@@ -37,6 +37,9 @@ __export(next_exports, {
|
|
|
37
37
|
JmpTrackedMailtoLink: () => JmpTrackedMailtoLink,
|
|
38
38
|
JmpTrackedTelLink: () => JmpTrackedTelLink,
|
|
39
39
|
buildLandingCaptureInlineScript: () => buildLandingCaptureInlineScript,
|
|
40
|
+
isJmpTrackingConsentGranted: () => isJmpTrackingConsentGranted,
|
|
41
|
+
setJmpTrackingConsent: () => setJmpTrackingConsent,
|
|
42
|
+
subscribeJmpTrackingConsent: () => subscribeJmpTrackingConsent,
|
|
40
43
|
useJmpAnalytics: () => useJmpAnalytics
|
|
41
44
|
});
|
|
42
45
|
module.exports = __toCommonJS(next_exports);
|
|
@@ -49,7 +52,6 @@ var JMP_SESSION_ID_KEY = "jmp_analytics_sid";
|
|
|
49
52
|
var JMP_LANDING_REFERER_KEY = "jmp_analytics_landing_referer";
|
|
50
53
|
var JMP_LANDING_REFERER_COOKIE = "jmp_lr";
|
|
51
54
|
var JMP_UTM_SESSION_KEY = "jmp_analytics_utm";
|
|
52
|
-
var JMP_EARLY_BEACON_PATH_KEY = "jmp_analytics_early_beacon_path";
|
|
53
55
|
var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
|
|
54
56
|
var JMP_UTM_PARAM_KEYS = [
|
|
55
57
|
"utm_source",
|
|
@@ -182,84 +184,174 @@ function getOrCreateSessionIdFromStorage() {
|
|
|
182
184
|
return void 0;
|
|
183
185
|
}
|
|
184
186
|
}
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
function buildLandingCaptureInlineScript() {
|
|
188
|
+
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
189
|
+
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){}})();`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/contact-link-classifier.ts
|
|
193
|
+
var BOOKING_LINK_HOSTS = [
|
|
194
|
+
"calendly.com",
|
|
195
|
+
"cal.com",
|
|
196
|
+
"acuityscheduling.com",
|
|
197
|
+
"calendar.google.com",
|
|
198
|
+
"calendar.app.google",
|
|
199
|
+
"bookings.microsoft.com",
|
|
200
|
+
"outlook.office.com",
|
|
201
|
+
"outlook.office365.com",
|
|
202
|
+
"book.ms",
|
|
203
|
+
"setmore.com",
|
|
204
|
+
"simplybook.me",
|
|
205
|
+
"oncehub.com",
|
|
206
|
+
"scheduleonce.com",
|
|
207
|
+
"youcanbook.me",
|
|
208
|
+
"savvycal.com",
|
|
209
|
+
"tidycal.com",
|
|
210
|
+
"zohobookings.com",
|
|
211
|
+
"square.site",
|
|
212
|
+
"squareup.com",
|
|
213
|
+
"meetings.hubspot.com",
|
|
214
|
+
"jobber.com",
|
|
215
|
+
"housecallpro.com",
|
|
216
|
+
"servicetitan.com",
|
|
217
|
+
"thryv.com",
|
|
218
|
+
"honeybook.com",
|
|
219
|
+
"dubsado.com",
|
|
220
|
+
"fresha.com",
|
|
221
|
+
"booksy.com",
|
|
222
|
+
"vagaro.com",
|
|
223
|
+
"mindbodyonline.com",
|
|
224
|
+
"mindbody.io",
|
|
225
|
+
"janeapp.com",
|
|
226
|
+
"cliniko.com",
|
|
227
|
+
"practicebetter.io"
|
|
228
|
+
];
|
|
229
|
+
var WHATSAPP_HOSTS = ["wa.me", "api.whatsapp.com", "whatsapp.com"];
|
|
230
|
+
function hostnameMatches(host, pattern) {
|
|
231
|
+
const h = host.toLowerCase();
|
|
232
|
+
const p = pattern.toLowerCase();
|
|
233
|
+
return h === p || h.endsWith(`.${p}`);
|
|
234
|
+
}
|
|
235
|
+
function isMapsHost(host, pathname) {
|
|
236
|
+
if (hostnameMatches(host, "maps.apple.com")) {
|
|
237
|
+
return true;
|
|
188
238
|
}
|
|
189
|
-
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
239
|
+
if (hostnameMatches(host, "maps.app.goo.gl")) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
if (hostnameMatches(host, "google.com") || hostnameMatches(host, "google.co")) {
|
|
243
|
+
return pathname === "/maps" || pathname.startsWith("/maps/") || pathname.startsWith("/local");
|
|
193
244
|
}
|
|
245
|
+
return false;
|
|
194
246
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
247
|
+
function isWhatsAppHost(host, pathname) {
|
|
248
|
+
for (const pattern of WHATSAPP_HOSTS) {
|
|
249
|
+
if (!hostnameMatches(host, pattern)) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (pattern === "whatsapp.com") {
|
|
253
|
+
return pathname.startsWith("/send");
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
function isBookingHost(host) {
|
|
260
|
+
for (const pattern of BOOKING_LINK_HOSTS) {
|
|
261
|
+
if (hostnameMatches(host, pattern)) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function classifyContactHref(href) {
|
|
268
|
+
const raw = href.trim();
|
|
269
|
+
if (!raw || raw.startsWith("#") || raw.startsWith("javascript:")) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
const lower = raw.toLowerCase();
|
|
273
|
+
if (lower.startsWith("tel:")) {
|
|
274
|
+
return { kind: "call" };
|
|
275
|
+
}
|
|
276
|
+
if (lower.startsWith("mailto:")) {
|
|
277
|
+
return { kind: "email" };
|
|
278
|
+
}
|
|
279
|
+
if (lower.startsWith("sms:") || lower.startsWith("smsto:")) {
|
|
280
|
+
return { kind: "contact_click", channel: "sms", linkHost: null };
|
|
281
|
+
}
|
|
282
|
+
if (lower.startsWith("geo:")) {
|
|
283
|
+
return { kind: "contact_click", channel: "maps", linkHost: null };
|
|
198
284
|
}
|
|
285
|
+
if (raw.startsWith("/") || raw.startsWith("?")) {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
let url;
|
|
199
289
|
try {
|
|
200
|
-
|
|
290
|
+
url = new URL(raw);
|
|
201
291
|
} catch {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
const host = url.hostname.toLowerCase();
|
|
298
|
+
const pathname = url.pathname.toLowerCase();
|
|
299
|
+
if (isWhatsAppHost(host, pathname)) {
|
|
300
|
+
return { kind: "contact_click", channel: "whatsapp", linkHost: host };
|
|
301
|
+
}
|
|
302
|
+
if (isMapsHost(host, pathname)) {
|
|
303
|
+
return { kind: "contact_click", channel: "maps", linkHost: host };
|
|
202
304
|
}
|
|
305
|
+
if (isBookingHost(host)) {
|
|
306
|
+
return { kind: "contact_click", channel: "booking", linkHost: host };
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
203
309
|
}
|
|
204
|
-
|
|
205
|
-
|
|
310
|
+
|
|
311
|
+
// src/index.ts
|
|
312
|
+
var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
|
|
313
|
+
var moduleTrackingConsentGranted = true;
|
|
314
|
+
var trackingConsentListeners = /* @__PURE__ */ new Set();
|
|
315
|
+
function readStoredTrackingConsent() {
|
|
316
|
+
if (typeof window === "undefined") {
|
|
206
317
|
return false;
|
|
207
318
|
}
|
|
208
|
-
|
|
209
|
-
|
|
319
|
+
try {
|
|
320
|
+
return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
|
|
321
|
+
} catch {
|
|
210
322
|
return false;
|
|
211
323
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
metadata.referer = landingReferer;
|
|
221
|
-
}
|
|
222
|
-
const payload = {
|
|
223
|
-
type: "page_view",
|
|
224
|
-
path,
|
|
225
|
-
trackingKey: args.trackingKey,
|
|
226
|
-
...sessionId ? { sessionId } : {},
|
|
227
|
-
metadata
|
|
228
|
-
};
|
|
229
|
-
const headers = {
|
|
230
|
-
"Content-Type": "application/json",
|
|
231
|
-
"X-JMP-Tracking-Key": args.trackingKey
|
|
324
|
+
}
|
|
325
|
+
function isJmpTrackingConsentGranted() {
|
|
326
|
+
return moduleTrackingConsentGranted;
|
|
327
|
+
}
|
|
328
|
+
function subscribeJmpTrackingConsent(listener) {
|
|
329
|
+
trackingConsentListeners.add(listener);
|
|
330
|
+
return () => {
|
|
331
|
+
trackingConsentListeners.delete(listener);
|
|
232
332
|
};
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
body: JSON.stringify(payload),
|
|
241
|
-
keepalive: true,
|
|
242
|
-
mode: "cors",
|
|
243
|
-
credentials: "omit"
|
|
244
|
-
}).catch(() => {
|
|
333
|
+
}
|
|
334
|
+
function setJmpTrackingConsent(granted) {
|
|
335
|
+
if (moduleTrackingConsentGranted === granted) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
moduleTrackingConsentGranted = granted;
|
|
339
|
+
if (typeof window !== "undefined") {
|
|
245
340
|
try {
|
|
246
|
-
|
|
341
|
+
localStorage.setItem(
|
|
342
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
343
|
+
granted ? "granted" : "denied"
|
|
344
|
+
);
|
|
247
345
|
} catch {
|
|
248
346
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const baseUrl = escapeInlineScript(args.baseUrl.replace(/\/$/, ""));
|
|
257
|
-
const trackingKey = escapeInlineScript(args.trackingKey);
|
|
258
|
-
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
259
|
-
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)){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)}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){}})();`;
|
|
347
|
+
if (granted) {
|
|
348
|
+
captureLandingAttribution(window.location.hostname);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
for (const listener of trackingConsentListeners) {
|
|
352
|
+
listener();
|
|
353
|
+
}
|
|
260
354
|
}
|
|
261
|
-
|
|
262
|
-
// src/index.ts
|
|
263
355
|
function captureAndGetLandingReferer() {
|
|
264
356
|
if (typeof window === "undefined") {
|
|
265
357
|
return null;
|
|
@@ -309,9 +401,16 @@ function createJmpAnalytics(config) {
|
|
|
309
401
|
);
|
|
310
402
|
}
|
|
311
403
|
const fetchFn = resolvedFetch;
|
|
404
|
+
moduleTrackingConsentGranted = config.requireConsent ? readStoredTrackingConsent() : true;
|
|
405
|
+
function canSend() {
|
|
406
|
+
return moduleTrackingConsentGranted;
|
|
407
|
+
}
|
|
312
408
|
let lastDedupePath = "";
|
|
313
409
|
let lastDedupeAt = 0;
|
|
314
410
|
async function send(body) {
|
|
411
|
+
if (!canSend()) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
315
414
|
const url = `${baseUrl}/api/events`;
|
|
316
415
|
const headers = {
|
|
317
416
|
"Content-Type": "application/json",
|
|
@@ -367,6 +466,9 @@ function createJmpAnalytics(config) {
|
|
|
367
466
|
}
|
|
368
467
|
}
|
|
369
468
|
async function sendLead(body) {
|
|
469
|
+
if (!canSend()) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
370
472
|
const url = `${baseUrl}/api/leads`;
|
|
371
473
|
const headers = {
|
|
372
474
|
"Content-Type": "application/json",
|
|
@@ -429,6 +531,9 @@ function createJmpAnalytics(config) {
|
|
|
429
531
|
return false;
|
|
430
532
|
}
|
|
431
533
|
function trackPageView(options) {
|
|
534
|
+
if (!canSend()) {
|
|
535
|
+
return Promise.resolve();
|
|
536
|
+
}
|
|
432
537
|
const pathFromOptions = options?.path?.trim();
|
|
433
538
|
let pathname = "/";
|
|
434
539
|
let search = "";
|
|
@@ -444,9 +549,6 @@ function createJmpAnalytics(config) {
|
|
|
444
549
|
search = window.location.search.replace(/^\?/, "");
|
|
445
550
|
}
|
|
446
551
|
const path = search ? `${pathname}?${search}` : pathname;
|
|
447
|
-
if (wasEarlyBeaconSentForPath(path)) {
|
|
448
|
-
return Promise.resolve();
|
|
449
|
-
}
|
|
450
552
|
if (shouldDedupePageView(pathname)) {
|
|
451
553
|
return Promise.resolve();
|
|
452
554
|
}
|
|
@@ -497,6 +599,20 @@ function createJmpAnalytics(config) {
|
|
|
497
599
|
metadata: metadata ?? {}
|
|
498
600
|
});
|
|
499
601
|
}
|
|
602
|
+
function trackContactClick(path, options) {
|
|
603
|
+
const metadata = {
|
|
604
|
+
...options.metadata && typeof options.metadata === "object" ? options.metadata : {},
|
|
605
|
+
channel: options.channel
|
|
606
|
+
};
|
|
607
|
+
if (options.linkHost) {
|
|
608
|
+
metadata.linkHost = options.linkHost;
|
|
609
|
+
}
|
|
610
|
+
return send({
|
|
611
|
+
type: "contact_click",
|
|
612
|
+
path: path || "/",
|
|
613
|
+
metadata
|
|
614
|
+
});
|
|
615
|
+
}
|
|
500
616
|
function trackLead(options) {
|
|
501
617
|
const path = options?.path ?? (typeof window !== "undefined" ? window.location.pathname : "/");
|
|
502
618
|
const body = { path: path || "/" };
|
|
@@ -529,7 +645,20 @@ function createJmpAnalytics(config) {
|
|
|
529
645
|
if (type === "call_click") {
|
|
530
646
|
return trackCallClick(payload.path, payload.metadata);
|
|
531
647
|
}
|
|
532
|
-
|
|
648
|
+
if (type === "email_click") {
|
|
649
|
+
return trackEmailClick(payload.path, payload.metadata);
|
|
650
|
+
}
|
|
651
|
+
const meta = payload.metadata ?? {};
|
|
652
|
+
const channel = typeof meta.channel === "string" ? meta.channel : "";
|
|
653
|
+
const linkHost = typeof meta.linkHost === "string" ? meta.linkHost : null;
|
|
654
|
+
if (channel !== "sms" && channel !== "whatsapp" && channel !== "maps" && channel !== "booking") {
|
|
655
|
+
return Promise.resolve();
|
|
656
|
+
}
|
|
657
|
+
return trackContactClick(payload.path, {
|
|
658
|
+
channel,
|
|
659
|
+
linkHost,
|
|
660
|
+
metadata: meta
|
|
661
|
+
});
|
|
533
662
|
}
|
|
534
663
|
function subscribeToSpaNavigation() {
|
|
535
664
|
if (typeof window === "undefined") {
|
|
@@ -563,12 +692,75 @@ function createJmpAnalytics(config) {
|
|
|
563
692
|
history.replaceState = replace;
|
|
564
693
|
};
|
|
565
694
|
}
|
|
566
|
-
|
|
695
|
+
let lastContactClickKey = "";
|
|
696
|
+
let lastContactClickAt = 0;
|
|
697
|
+
function subscribeContactLinkAutoTrack() {
|
|
698
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
699
|
+
return () => {
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
const handler = (event) => {
|
|
703
|
+
if (!canSend()) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const target = event.target;
|
|
707
|
+
if (!(target instanceof Element)) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const anchor = target.closest("a[href]");
|
|
711
|
+
if (!(anchor instanceof HTMLAnchorElement)) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (anchor.closest("[data-jmp-no-track]")) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
718
|
+
const classified = classifyContactHref(href);
|
|
719
|
+
if (!classified) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const path = window.location.pathname;
|
|
723
|
+
if (classified.kind === "call") {
|
|
724
|
+
if (dedupeContactClick(`call_click:${path}`)) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
void trackCallClick(path);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (classified.kind === "email") {
|
|
731
|
+
if (dedupeContactClick(`email_click:${path}`)) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
void trackEmailClick(path);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
if (dedupeContactClick(`contact_click:${classified.channel}:${path}`)) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
void trackContactClick(path, {
|
|
741
|
+
channel: classified.channel,
|
|
742
|
+
linkHost: classified.linkHost
|
|
743
|
+
});
|
|
744
|
+
};
|
|
745
|
+
document.addEventListener("click", handler, { capture: true });
|
|
746
|
+
return () => {
|
|
747
|
+
document.removeEventListener("click", handler, { capture: true });
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function dedupeContactClick(key) {
|
|
751
|
+
const now = Date.now();
|
|
752
|
+
if (key === lastContactClickKey && now - lastContactClickAt < 1e3) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
lastContactClickKey = key;
|
|
756
|
+
lastContactClickAt = now;
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
if (typeof window !== "undefined" && canSend()) {
|
|
567
760
|
captureLandingAttribution(window.location.hostname);
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
});
|
|
761
|
+
}
|
|
762
|
+
if (typeof window !== "undefined" && config.autoTrackContactLinks && canSend()) {
|
|
763
|
+
subscribeContactLinkAutoTrack();
|
|
572
764
|
}
|
|
573
765
|
return {
|
|
574
766
|
track,
|
|
@@ -576,8 +768,12 @@ function createJmpAnalytics(config) {
|
|
|
576
768
|
trackFormSubmit,
|
|
577
769
|
trackCallClick,
|
|
578
770
|
trackEmailClick,
|
|
771
|
+
trackContactClick,
|
|
579
772
|
trackLead,
|
|
580
|
-
subscribeToSpaNavigation
|
|
773
|
+
subscribeToSpaNavigation,
|
|
774
|
+
subscribeContactLinkAutoTrack,
|
|
775
|
+
setTrackingConsent: setJmpTrackingConsent,
|
|
776
|
+
isTrackingConsentGranted: isJmpTrackingConsentGranted
|
|
581
777
|
};
|
|
582
778
|
}
|
|
583
779
|
var DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 800;
|
|
@@ -590,11 +786,15 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
|
590
786
|
const baseUrl = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
591
787
|
const trackingKey = readProcessEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
592
788
|
if (!baseUrl || !trackingKey) return null;
|
|
789
|
+
const requireConsentFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT") === "true";
|
|
790
|
+
const autoTrackContactLinksFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS") === "true";
|
|
593
791
|
return {
|
|
594
792
|
baseUrl,
|
|
595
793
|
trackingKey,
|
|
596
794
|
pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
597
|
-
...overrides
|
|
795
|
+
...overrides,
|
|
796
|
+
requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,
|
|
797
|
+
autoTrackContactLinks: overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv
|
|
598
798
|
};
|
|
599
799
|
}
|
|
600
800
|
var jmpAnalyticsBrowserSingleton = null;
|
|
@@ -655,12 +855,9 @@ function JmpTrackedMailtoLink({
|
|
|
655
855
|
// src/next.tsx
|
|
656
856
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
657
857
|
function JmpLandingCaptureScript({
|
|
658
|
-
baseUrl = process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL,
|
|
659
858
|
trackingKey = process.env.NEXT_PUBLIC_JMP_TRACKING_KEY
|
|
660
859
|
} = {}) {
|
|
661
|
-
|
|
662
|
-
const resolvedKey = trackingKey?.trim();
|
|
663
|
-
if (!resolvedBase || !resolvedKey) {
|
|
860
|
+
if (!trackingKey?.trim()) {
|
|
664
861
|
return null;
|
|
665
862
|
}
|
|
666
863
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -669,10 +866,7 @@ function JmpLandingCaptureScript({
|
|
|
669
866
|
id: "jmp-landing-capture",
|
|
670
867
|
strategy: "beforeInteractive",
|
|
671
868
|
dangerouslySetInnerHTML: {
|
|
672
|
-
__html: buildLandingCaptureInlineScript(
|
|
673
|
-
baseUrl: resolvedBase,
|
|
674
|
-
trackingKey: resolvedKey
|
|
675
|
-
})
|
|
869
|
+
__html: buildLandingCaptureInlineScript()
|
|
676
870
|
}
|
|
677
871
|
}
|
|
678
872
|
);
|
|
@@ -691,7 +885,21 @@ function JmpNextPageViewTrackerInner() {
|
|
|
691
885
|
function JmpNextPageViewTracker() {
|
|
692
886
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpNextPageViewTrackerInner, {}) });
|
|
693
887
|
}
|
|
694
|
-
function
|
|
888
|
+
function useJmpTrackingActive(deferUntilConsent) {
|
|
889
|
+
const consentGranted = (0, import_react2.useSyncExternalStore)(
|
|
890
|
+
subscribeJmpTrackingConsent,
|
|
891
|
+
() => isJmpTrackingConsentGranted(),
|
|
892
|
+
() => false
|
|
893
|
+
);
|
|
894
|
+
return !deferUntilConsent || consentGranted;
|
|
895
|
+
}
|
|
896
|
+
function JmpNextAnalytics({
|
|
897
|
+
deferUntilConsent = process.env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT === "true"
|
|
898
|
+
} = {}) {
|
|
899
|
+
const active = useJmpTrackingActive(deferUntilConsent);
|
|
900
|
+
if (!active) {
|
|
901
|
+
return null;
|
|
902
|
+
}
|
|
695
903
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
696
904
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpLandingCaptureScript, {}),
|
|
697
905
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpNextPageViewTracker, {})
|
|
@@ -705,6 +913,9 @@ function JmpNextAnalytics() {
|
|
|
705
913
|
JmpTrackedMailtoLink,
|
|
706
914
|
JmpTrackedTelLink,
|
|
707
915
|
buildLandingCaptureInlineScript,
|
|
916
|
+
isJmpTrackingConsentGranted,
|
|
917
|
+
setJmpTrackingConsent,
|
|
918
|
+
subscribeJmpTrackingConsent,
|
|
708
919
|
useJmpAnalytics
|
|
709
920
|
});
|
|
710
921
|
//# sourceMappingURL=next.cjs.map
|