@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/README.md
CHANGED
|
@@ -73,6 +73,8 @@ import {
|
|
|
73
73
|
|
|
74
74
|
Or call **`trackEmailClick(path)`** / **`trackCallClick(path)`** from `useJmpAnalytics()`.
|
|
75
75
|
|
|
76
|
+
For **SMS / WhatsApp / maps / scheduling** link taps, call **`trackContactClick(path, { channel, linkHost })`** — or set **`autoTrackContactLinks: true`** in your config (or **`NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS=true`**) to register one delegated `click` listener that classifies outbound links for you. Auto-tracking is **off by default**; per-link opt-out via `data-jmp-no-track` on the `<a>` (or any ancestor).
|
|
77
|
+
|
|
76
78
|
**Hooks:** `useJmpAnalytics()` from `@jmp-technologies/analytics/next` or `@jmp-technologies/analytics/react` for forms and custom events.
|
|
77
79
|
|
|
78
80
|
---
|
|
@@ -243,7 +245,7 @@ When present, `category` is an optional section label you can use to group FAQs
|
|
|
243
245
|
|
|
244
246
|
**Tracking events**
|
|
245
247
|
|
|
246
|
-
- `trackPageView`, `trackFormSubmit`, `trackCallClick`, `trackEmailClick` (since **0.1.10**), `trackLead`
|
|
248
|
+
- `trackPageView`, `trackFormSubmit`, `trackCallClick`, `trackEmailClick` (since **0.1.10**), `trackContactClick` (since **0.1.18** — SMS, WhatsApp, maps, scheduling), `trackLead`
|
|
247
249
|
|
|
248
250
|
**Content**
|
|
249
251
|
|
|
@@ -3,7 +3,6 @@ var JMP_SESSION_ID_KEY = "jmp_analytics_sid";
|
|
|
3
3
|
var JMP_LANDING_REFERER_KEY = "jmp_analytics_landing_referer";
|
|
4
4
|
var JMP_LANDING_REFERER_COOKIE = "jmp_lr";
|
|
5
5
|
var JMP_UTM_SESSION_KEY = "jmp_analytics_utm";
|
|
6
|
-
var JMP_EARLY_BEACON_PATH_KEY = "jmp_analytics_early_beacon_path";
|
|
7
6
|
var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
|
|
8
7
|
var JMP_UTM_PARAM_KEYS = [
|
|
9
8
|
"utm_source",
|
|
@@ -136,84 +135,175 @@ function getOrCreateSessionIdFromStorage() {
|
|
|
136
135
|
return void 0;
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
function buildLandingCaptureInlineScript() {
|
|
139
|
+
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
140
|
+
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){}})();`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/contact-link-classifier.ts
|
|
144
|
+
var BOOKING_LINK_HOSTS = [
|
|
145
|
+
"calendly.com",
|
|
146
|
+
"cal.com",
|
|
147
|
+
"acuityscheduling.com",
|
|
148
|
+
"calendar.google.com",
|
|
149
|
+
"calendar.app.google",
|
|
150
|
+
"bookings.microsoft.com",
|
|
151
|
+
"outlook.office.com",
|
|
152
|
+
"outlook.office365.com",
|
|
153
|
+
"book.ms",
|
|
154
|
+
"setmore.com",
|
|
155
|
+
"simplybook.me",
|
|
156
|
+
"oncehub.com",
|
|
157
|
+
"scheduleonce.com",
|
|
158
|
+
"youcanbook.me",
|
|
159
|
+
"savvycal.com",
|
|
160
|
+
"tidycal.com",
|
|
161
|
+
"zohobookings.com",
|
|
162
|
+
"square.site",
|
|
163
|
+
"squareup.com",
|
|
164
|
+
"meetings.hubspot.com",
|
|
165
|
+
"jobber.com",
|
|
166
|
+
"housecallpro.com",
|
|
167
|
+
"servicetitan.com",
|
|
168
|
+
"thryv.com",
|
|
169
|
+
"honeybook.com",
|
|
170
|
+
"dubsado.com",
|
|
171
|
+
"fresha.com",
|
|
172
|
+
"booksy.com",
|
|
173
|
+
"vagaro.com",
|
|
174
|
+
"mindbodyonline.com",
|
|
175
|
+
"mindbody.io",
|
|
176
|
+
"janeapp.com",
|
|
177
|
+
"cliniko.com",
|
|
178
|
+
"practicebetter.io"
|
|
179
|
+
];
|
|
180
|
+
var WHATSAPP_HOSTS = ["wa.me", "api.whatsapp.com", "whatsapp.com"];
|
|
181
|
+
function hostnameMatches(host, pattern) {
|
|
182
|
+
const h = host.toLowerCase();
|
|
183
|
+
const p = pattern.toLowerCase();
|
|
184
|
+
return h === p || h.endsWith(`.${p}`);
|
|
185
|
+
}
|
|
186
|
+
function isMapsHost(host, pathname) {
|
|
187
|
+
if (hostnameMatches(host, "maps.apple.com")) {
|
|
188
|
+
return true;
|
|
142
189
|
}
|
|
143
|
-
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
|
-
|
|
190
|
+
if (hostnameMatches(host, "maps.app.goo.gl")) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (hostnameMatches(host, "google.com") || hostnameMatches(host, "google.co")) {
|
|
194
|
+
return pathname === "/maps" || pathname.startsWith("/maps/") || pathname.startsWith("/local");
|
|
147
195
|
}
|
|
196
|
+
return false;
|
|
148
197
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
198
|
+
function isWhatsAppHost(host, pathname) {
|
|
199
|
+
for (const pattern of WHATSAPP_HOSTS) {
|
|
200
|
+
if (!hostnameMatches(host, pattern)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (pattern === "whatsapp.com") {
|
|
204
|
+
return pathname.startsWith("/send");
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
function isBookingHost(host) {
|
|
211
|
+
for (const pattern of BOOKING_LINK_HOSTS) {
|
|
212
|
+
if (hostnameMatches(host, pattern)) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
function classifyContactHref(href) {
|
|
219
|
+
const raw = href.trim();
|
|
220
|
+
if (!raw || raw.startsWith("#") || raw.startsWith("javascript:")) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const lower = raw.toLowerCase();
|
|
224
|
+
if (lower.startsWith("tel:")) {
|
|
225
|
+
return { kind: "call" };
|
|
226
|
+
}
|
|
227
|
+
if (lower.startsWith("mailto:")) {
|
|
228
|
+
return { kind: "email" };
|
|
152
229
|
}
|
|
230
|
+
if (lower.startsWith("sms:") || lower.startsWith("smsto:")) {
|
|
231
|
+
return { kind: "contact_click", channel: "sms", linkHost: null };
|
|
232
|
+
}
|
|
233
|
+
if (lower.startsWith("geo:")) {
|
|
234
|
+
return { kind: "contact_click", channel: "maps", linkHost: null };
|
|
235
|
+
}
|
|
236
|
+
if (raw.startsWith("/") || raw.startsWith("?")) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
let url;
|
|
153
240
|
try {
|
|
154
|
-
|
|
241
|
+
url = new URL(raw);
|
|
155
242
|
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const host = url.hostname.toLowerCase();
|
|
249
|
+
const pathname = url.pathname.toLowerCase();
|
|
250
|
+
if (isWhatsAppHost(host, pathname)) {
|
|
251
|
+
return { kind: "contact_click", channel: "whatsapp", linkHost: host };
|
|
252
|
+
}
|
|
253
|
+
if (isMapsHost(host, pathname)) {
|
|
254
|
+
return { kind: "contact_click", channel: "maps", linkHost: host };
|
|
255
|
+
}
|
|
256
|
+
if (isBookingHost(host)) {
|
|
257
|
+
return { kind: "contact_click", channel: "booking", linkHost: host };
|
|
156
258
|
}
|
|
259
|
+
return null;
|
|
157
260
|
}
|
|
158
|
-
|
|
159
|
-
|
|
261
|
+
|
|
262
|
+
// src/index.ts
|
|
263
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.18";
|
|
264
|
+
var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
|
|
265
|
+
var moduleTrackingConsentGranted = true;
|
|
266
|
+
var trackingConsentListeners = /* @__PURE__ */ new Set();
|
|
267
|
+
function readStoredTrackingConsent() {
|
|
268
|
+
if (typeof window === "undefined") {
|
|
160
269
|
return false;
|
|
161
270
|
}
|
|
162
|
-
|
|
163
|
-
|
|
271
|
+
try {
|
|
272
|
+
return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
|
|
273
|
+
} catch {
|
|
164
274
|
return false;
|
|
165
275
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
metadata.referer = landingReferer;
|
|
175
|
-
}
|
|
176
|
-
const payload = {
|
|
177
|
-
type: "page_view",
|
|
178
|
-
path,
|
|
179
|
-
trackingKey: args.trackingKey,
|
|
180
|
-
...sessionId ? { sessionId } : {},
|
|
181
|
-
metadata
|
|
182
|
-
};
|
|
183
|
-
const headers = {
|
|
184
|
-
"Content-Type": "application/json",
|
|
185
|
-
"X-JMP-Tracking-Key": args.trackingKey
|
|
276
|
+
}
|
|
277
|
+
function isJmpTrackingConsentGranted() {
|
|
278
|
+
return moduleTrackingConsentGranted;
|
|
279
|
+
}
|
|
280
|
+
function subscribeJmpTrackingConsent(listener) {
|
|
281
|
+
trackingConsentListeners.add(listener);
|
|
282
|
+
return () => {
|
|
283
|
+
trackingConsentListeners.delete(listener);
|
|
186
284
|
};
|
|
187
|
-
|
|
188
|
-
|
|
285
|
+
}
|
|
286
|
+
function setJmpTrackingConsent(granted) {
|
|
287
|
+
if (moduleTrackingConsentGranted === granted) {
|
|
288
|
+
return;
|
|
189
289
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
method: "POST",
|
|
193
|
-
headers,
|
|
194
|
-
body: JSON.stringify(payload),
|
|
195
|
-
keepalive: true,
|
|
196
|
-
mode: "cors",
|
|
197
|
-
credentials: "omit"
|
|
198
|
-
}).catch(() => {
|
|
290
|
+
moduleTrackingConsentGranted = granted;
|
|
291
|
+
if (typeof window !== "undefined") {
|
|
199
292
|
try {
|
|
200
|
-
|
|
293
|
+
localStorage.setItem(
|
|
294
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
295
|
+
granted ? "granted" : "denied"
|
|
296
|
+
);
|
|
201
297
|
} catch {
|
|
202
298
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const baseUrl = escapeInlineScript(args.baseUrl.replace(/\/$/, ""));
|
|
211
|
-
const trackingKey = escapeInlineScript(args.trackingKey);
|
|
212
|
-
const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
|
|
213
|
-
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){}})();`;
|
|
299
|
+
if (granted) {
|
|
300
|
+
captureLandingAttribution(window.location.hostname);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const listener of trackingConsentListeners) {
|
|
304
|
+
listener();
|
|
305
|
+
}
|
|
214
306
|
}
|
|
215
|
-
|
|
216
|
-
// src/index.ts
|
|
217
307
|
function captureAndGetLandingReferer() {
|
|
218
308
|
if (typeof window === "undefined") {
|
|
219
309
|
return null;
|
|
@@ -288,9 +378,16 @@ function createJmpAnalytics(config) {
|
|
|
288
378
|
);
|
|
289
379
|
}
|
|
290
380
|
const fetchFn = resolvedFetch;
|
|
381
|
+
moduleTrackingConsentGranted = config.requireConsent ? readStoredTrackingConsent() : true;
|
|
382
|
+
function canSend() {
|
|
383
|
+
return moduleTrackingConsentGranted;
|
|
384
|
+
}
|
|
291
385
|
let lastDedupePath = "";
|
|
292
386
|
let lastDedupeAt = 0;
|
|
293
387
|
async function send(body) {
|
|
388
|
+
if (!canSend()) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
294
391
|
const url = `${baseUrl}/api/events`;
|
|
295
392
|
const headers = {
|
|
296
393
|
"Content-Type": "application/json",
|
|
@@ -346,6 +443,9 @@ function createJmpAnalytics(config) {
|
|
|
346
443
|
}
|
|
347
444
|
}
|
|
348
445
|
async function sendLead(body) {
|
|
446
|
+
if (!canSend()) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
349
449
|
const url = `${baseUrl}/api/leads`;
|
|
350
450
|
const headers = {
|
|
351
451
|
"Content-Type": "application/json",
|
|
@@ -408,6 +508,9 @@ function createJmpAnalytics(config) {
|
|
|
408
508
|
return false;
|
|
409
509
|
}
|
|
410
510
|
function trackPageView(options) {
|
|
511
|
+
if (!canSend()) {
|
|
512
|
+
return Promise.resolve();
|
|
513
|
+
}
|
|
411
514
|
const pathFromOptions = options?.path?.trim();
|
|
412
515
|
let pathname = "/";
|
|
413
516
|
let search = "";
|
|
@@ -423,9 +526,6 @@ function createJmpAnalytics(config) {
|
|
|
423
526
|
search = window.location.search.replace(/^\?/, "");
|
|
424
527
|
}
|
|
425
528
|
const path = search ? `${pathname}?${search}` : pathname;
|
|
426
|
-
if (wasEarlyBeaconSentForPath(path)) {
|
|
427
|
-
return Promise.resolve();
|
|
428
|
-
}
|
|
429
529
|
if (shouldDedupePageView(pathname)) {
|
|
430
530
|
return Promise.resolve();
|
|
431
531
|
}
|
|
@@ -476,6 +576,20 @@ function createJmpAnalytics(config) {
|
|
|
476
576
|
metadata: metadata ?? {}
|
|
477
577
|
});
|
|
478
578
|
}
|
|
579
|
+
function trackContactClick(path, options) {
|
|
580
|
+
const metadata = {
|
|
581
|
+
...options.metadata && typeof options.metadata === "object" ? options.metadata : {},
|
|
582
|
+
channel: options.channel
|
|
583
|
+
};
|
|
584
|
+
if (options.linkHost) {
|
|
585
|
+
metadata.linkHost = options.linkHost;
|
|
586
|
+
}
|
|
587
|
+
return send({
|
|
588
|
+
type: "contact_click",
|
|
589
|
+
path: path || "/",
|
|
590
|
+
metadata
|
|
591
|
+
});
|
|
592
|
+
}
|
|
479
593
|
function trackLead(options) {
|
|
480
594
|
const path = options?.path ?? (typeof window !== "undefined" ? window.location.pathname : "/");
|
|
481
595
|
const body = { path: path || "/" };
|
|
@@ -508,7 +622,20 @@ function createJmpAnalytics(config) {
|
|
|
508
622
|
if (type === "call_click") {
|
|
509
623
|
return trackCallClick(payload.path, payload.metadata);
|
|
510
624
|
}
|
|
511
|
-
|
|
625
|
+
if (type === "email_click") {
|
|
626
|
+
return trackEmailClick(payload.path, payload.metadata);
|
|
627
|
+
}
|
|
628
|
+
const meta = payload.metadata ?? {};
|
|
629
|
+
const channel = typeof meta.channel === "string" ? meta.channel : "";
|
|
630
|
+
const linkHost = typeof meta.linkHost === "string" ? meta.linkHost : null;
|
|
631
|
+
if (channel !== "sms" && channel !== "whatsapp" && channel !== "maps" && channel !== "booking") {
|
|
632
|
+
return Promise.resolve();
|
|
633
|
+
}
|
|
634
|
+
return trackContactClick(payload.path, {
|
|
635
|
+
channel,
|
|
636
|
+
linkHost,
|
|
637
|
+
metadata: meta
|
|
638
|
+
});
|
|
512
639
|
}
|
|
513
640
|
function subscribeToSpaNavigation() {
|
|
514
641
|
if (typeof window === "undefined") {
|
|
@@ -542,12 +669,75 @@ function createJmpAnalytics(config) {
|
|
|
542
669
|
history.replaceState = replace;
|
|
543
670
|
};
|
|
544
671
|
}
|
|
545
|
-
|
|
672
|
+
let lastContactClickKey = "";
|
|
673
|
+
let lastContactClickAt = 0;
|
|
674
|
+
function subscribeContactLinkAutoTrack() {
|
|
675
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
676
|
+
return () => {
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
const handler = (event) => {
|
|
680
|
+
if (!canSend()) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const target = event.target;
|
|
684
|
+
if (!(target instanceof Element)) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const anchor = target.closest("a[href]");
|
|
688
|
+
if (!(anchor instanceof HTMLAnchorElement)) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (anchor.closest("[data-jmp-no-track]")) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
695
|
+
const classified = classifyContactHref(href);
|
|
696
|
+
if (!classified) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const path = window.location.pathname;
|
|
700
|
+
if (classified.kind === "call") {
|
|
701
|
+
if (dedupeContactClick(`call_click:${path}`)) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
void trackCallClick(path);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (classified.kind === "email") {
|
|
708
|
+
if (dedupeContactClick(`email_click:${path}`)) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
void trackEmailClick(path);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (dedupeContactClick(`contact_click:${classified.channel}:${path}`)) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
void trackContactClick(path, {
|
|
718
|
+
channel: classified.channel,
|
|
719
|
+
linkHost: classified.linkHost
|
|
720
|
+
});
|
|
721
|
+
};
|
|
722
|
+
document.addEventListener("click", handler, { capture: true });
|
|
723
|
+
return () => {
|
|
724
|
+
document.removeEventListener("click", handler, { capture: true });
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
function dedupeContactClick(key) {
|
|
728
|
+
const now = Date.now();
|
|
729
|
+
if (key === lastContactClickKey && now - lastContactClickAt < 1e3) {
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
732
|
+
lastContactClickKey = key;
|
|
733
|
+
lastContactClickAt = now;
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
if (typeof window !== "undefined" && canSend()) {
|
|
546
737
|
captureLandingAttribution(window.location.hostname);
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
});
|
|
738
|
+
}
|
|
739
|
+
if (typeof window !== "undefined" && config.autoTrackContactLinks && canSend()) {
|
|
740
|
+
subscribeContactLinkAutoTrack();
|
|
551
741
|
}
|
|
552
742
|
return {
|
|
553
743
|
track,
|
|
@@ -555,8 +745,12 @@ function createJmpAnalytics(config) {
|
|
|
555
745
|
trackFormSubmit,
|
|
556
746
|
trackCallClick,
|
|
557
747
|
trackEmailClick,
|
|
748
|
+
trackContactClick,
|
|
558
749
|
trackLead,
|
|
559
|
-
subscribeToSpaNavigation
|
|
750
|
+
subscribeToSpaNavigation,
|
|
751
|
+
subscribeContactLinkAutoTrack,
|
|
752
|
+
setTrackingConsent: setJmpTrackingConsent,
|
|
753
|
+
isTrackingConsentGranted: isJmpTrackingConsentGranted
|
|
560
754
|
};
|
|
561
755
|
}
|
|
562
756
|
async function trackJmpServerPageView(config, options = {}) {
|
|
@@ -679,7 +873,10 @@ async function registerJmpContentWrappers(config) {
|
|
|
679
873
|
"Content-Type": "application/json",
|
|
680
874
|
"X-JMP-Tracking-Key": config.trackingKey
|
|
681
875
|
},
|
|
682
|
-
body: JSON.stringify({
|
|
876
|
+
body: JSON.stringify({
|
|
877
|
+
wrappers,
|
|
878
|
+
sdkVersion: JMP_ANALYTICS_SDK_VERSION
|
|
879
|
+
})
|
|
683
880
|
});
|
|
684
881
|
const text = await res.text();
|
|
685
882
|
if (!res.ok) {
|
|
@@ -777,11 +974,15 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
|
777
974
|
const baseUrl = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
778
975
|
const trackingKey = readProcessEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
779
976
|
if (!baseUrl || !trackingKey) return null;
|
|
977
|
+
const requireConsentFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT") === "true";
|
|
978
|
+
const autoTrackContactLinksFromEnv = readProcessEnv("NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS") === "true";
|
|
780
979
|
return {
|
|
781
980
|
baseUrl,
|
|
782
981
|
trackingKey,
|
|
783
982
|
pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
784
|
-
...overrides
|
|
983
|
+
...overrides,
|
|
984
|
+
requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,
|
|
985
|
+
autoTrackContactLinks: overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv
|
|
785
986
|
};
|
|
786
987
|
}
|
|
787
988
|
function getJmpServerContentConfigFromEnv(overrides) {
|
|
@@ -814,8 +1015,14 @@ function createJmpContentClientFromServerEnv(overrides) {
|
|
|
814
1015
|
}
|
|
815
1016
|
|
|
816
1017
|
export {
|
|
817
|
-
sendEarlyPageViewBeacon,
|
|
818
1018
|
buildLandingCaptureInlineScript,
|
|
1019
|
+
BOOKING_LINK_HOSTS,
|
|
1020
|
+
classifyContactHref,
|
|
1021
|
+
JMP_ANALYTICS_SDK_VERSION,
|
|
1022
|
+
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
1023
|
+
isJmpTrackingConsentGranted,
|
|
1024
|
+
subscribeJmpTrackingConsent,
|
|
1025
|
+
setJmpTrackingConsent,
|
|
819
1026
|
createJmpAnalytics,
|
|
820
1027
|
trackJmpServerPageView,
|
|
821
1028
|
getJmpBlogPosts,
|
|
@@ -835,4 +1042,4 @@ export {
|
|
|
835
1042
|
getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
836
1043
|
createJmpContentClientFromServerEnv
|
|
837
1044
|
};
|
|
838
|
-
//# sourceMappingURL=chunk-
|
|
1045
|
+
//# sourceMappingURL=chunk-SOHYQ5GT.js.map
|