@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/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",
@@ -135,11 +137,9 @@ function captureLandingAttribution(siteHostname) {
135
137
  const preservedReferer = storedReferer || cookieReferer;
136
138
  const currentReferer = document.referrer?.trim() || null;
137
139
  if (currentReferer && isExternalReferrerUrl(currentReferer, siteHostname)) {
138
- if (!storedReferer) {
139
- sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
140
- }
140
+ sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
141
141
  writeLandingRefererCookie(currentReferer, siteHostname);
142
- landingReferer = preservedReferer || currentReferer;
142
+ landingReferer = currentReferer;
143
143
  } else if (preservedReferer) {
144
144
  landingReferer = preservedReferer;
145
145
  if (!storedReferer) {
@@ -184,84 +184,174 @@ function getOrCreateSessionIdFromStorage() {
184
184
  return void 0;
185
185
  }
186
186
  }
187
- function wasEarlyBeaconSentForPath(path) {
188
- if (typeof window === "undefined") {
189
- return false;
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;
190
238
  }
191
- try {
192
- return sessionStorage.getItem(JMP_EARLY_BEACON_PATH_KEY) === path;
193
- } catch {
194
- return false;
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");
195
244
  }
245
+ return false;
196
246
  }
197
- function markEarlyBeaconSentForPath(path) {
198
- if (typeof window === "undefined") {
199
- return;
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 };
200
281
  }
282
+ if (lower.startsWith("geo:")) {
283
+ return { kind: "contact_click", channel: "maps", linkHost: null };
284
+ }
285
+ if (raw.startsWith("/") || raw.startsWith("?")) {
286
+ return null;
287
+ }
288
+ let url;
201
289
  try {
202
- sessionStorage.setItem(JMP_EARLY_BEACON_PATH_KEY, path);
290
+ url = new URL(raw);
203
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 };
204
301
  }
302
+ if (isMapsHost(host, pathname)) {
303
+ return { kind: "contact_click", channel: "maps", linkHost: host };
304
+ }
305
+ if (isBookingHost(host)) {
306
+ return { kind: "contact_click", channel: "booking", linkHost: host };
307
+ }
308
+ return null;
205
309
  }
206
- function sendEarlyPageViewBeacon(args) {
207
- if (typeof window === "undefined" || typeof fetch === "undefined") {
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") {
208
317
  return false;
209
318
  }
210
- const path = `${window.location.pathname}${window.location.search}` || "/";
211
- if (wasEarlyBeaconSentForPath(path)) {
319
+ try {
320
+ return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
321
+ } catch {
212
322
  return false;
213
323
  }
214
- const { landingReferer, utm } = captureLandingAttribution(window.location.hostname);
215
- const sessionId = getOrCreateSessionIdFromStorage();
216
- const metadata = {
217
- pageHostname: window.location.hostname,
218
- earlyBeacon: true,
219
- ...utm
220
- };
221
- if (landingReferer) {
222
- metadata.referer = landingReferer;
223
- }
224
- const payload = {
225
- type: "page_view",
226
- path,
227
- trackingKey: args.trackingKey,
228
- ...sessionId ? { sessionId } : {},
229
- metadata
230
- };
231
- const headers = {
232
- "Content-Type": "application/json",
233
- "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);
234
332
  };
235
- if (landingReferer) {
236
- headers["X-JMP-Visitor-Referer"] = landingReferer;
237
- }
238
- markEarlyBeaconSentForPath(path);
239
- void fetch(`${args.baseUrl.replace(/\/$/, "")}/api/events`, {
240
- method: "POST",
241
- headers,
242
- body: JSON.stringify(payload),
243
- keepalive: true,
244
- mode: "cors",
245
- credentials: "omit"
246
- }).catch(() => {
333
+ }
334
+ function setJmpTrackingConsent(granted) {
335
+ if (moduleTrackingConsentGranted === granted) {
336
+ return;
337
+ }
338
+ moduleTrackingConsentGranted = granted;
339
+ if (typeof window !== "undefined") {
247
340
  try {
248
- sessionStorage.removeItem(JMP_EARLY_BEACON_PATH_KEY);
341
+ localStorage.setItem(
342
+ JMP_TRACKING_CONSENT_STORAGE_KEY,
343
+ granted ? "granted" : "denied"
344
+ );
249
345
  } catch {
250
346
  }
251
- });
252
- return true;
253
- }
254
- function escapeInlineScript(value) {
255
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
256
- }
257
- function buildLandingCaptureInlineScript(args) {
258
- const baseUrl = escapeInlineScript(args.baseUrl.replace(/\/$/, ""));
259
- const trackingKey = escapeInlineScript(args.trackingKey);
260
- const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
261
- 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){}})();`;
347
+ if (granted) {
348
+ captureLandingAttribution(window.location.hostname);
349
+ }
350
+ }
351
+ for (const listener of trackingConsentListeners) {
352
+ listener();
353
+ }
262
354
  }
263
-
264
- // src/index.ts
265
355
  function captureAndGetLandingReferer() {
266
356
  if (typeof window === "undefined") {
267
357
  return null;
@@ -311,9 +401,16 @@ function createJmpAnalytics(config) {
311
401
  );
312
402
  }
313
403
  const fetchFn = resolvedFetch;
404
+ moduleTrackingConsentGranted = config.requireConsent ? readStoredTrackingConsent() : true;
405
+ function canSend() {
406
+ return moduleTrackingConsentGranted;
407
+ }
314
408
  let lastDedupePath = "";
315
409
  let lastDedupeAt = 0;
316
410
  async function send(body) {
411
+ if (!canSend()) {
412
+ return;
413
+ }
317
414
  const url = `${baseUrl}/api/events`;
318
415
  const headers = {
319
416
  "Content-Type": "application/json",
@@ -369,6 +466,9 @@ function createJmpAnalytics(config) {
369
466
  }
370
467
  }
371
468
  async function sendLead(body) {
469
+ if (!canSend()) {
470
+ return;
471
+ }
372
472
  const url = `${baseUrl}/api/leads`;
373
473
  const headers = {
374
474
  "Content-Type": "application/json",
@@ -431,6 +531,9 @@ function createJmpAnalytics(config) {
431
531
  return false;
432
532
  }
433
533
  function trackPageView(options) {
534
+ if (!canSend()) {
535
+ return Promise.resolve();
536
+ }
434
537
  const pathFromOptions = options?.path?.trim();
435
538
  let pathname = "/";
436
539
  let search = "";
@@ -446,9 +549,6 @@ function createJmpAnalytics(config) {
446
549
  search = window.location.search.replace(/^\?/, "");
447
550
  }
448
551
  const path = search ? `${pathname}?${search}` : pathname;
449
- if (wasEarlyBeaconSentForPath(path)) {
450
- return Promise.resolve();
451
- }
452
552
  if (shouldDedupePageView(pathname)) {
453
553
  return Promise.resolve();
454
554
  }
@@ -499,6 +599,20 @@ function createJmpAnalytics(config) {
499
599
  metadata: metadata ?? {}
500
600
  });
501
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
+ }
502
616
  function trackLead(options) {
503
617
  const path = options?.path ?? (typeof window !== "undefined" ? window.location.pathname : "/");
504
618
  const body = { path: path || "/" };
@@ -531,7 +645,20 @@ function createJmpAnalytics(config) {
531
645
  if (type === "call_click") {
532
646
  return trackCallClick(payload.path, payload.metadata);
533
647
  }
534
- return trackEmailClick(payload.path, payload.metadata);
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
+ });
535
662
  }
536
663
  function subscribeToSpaNavigation() {
537
664
  if (typeof window === "undefined") {
@@ -565,12 +692,75 @@ function createJmpAnalytics(config) {
565
692
  history.replaceState = replace;
566
693
  };
567
694
  }
568
- if (typeof window !== "undefined") {
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()) {
569
760
  captureLandingAttribution(window.location.hostname);
570
- sendEarlyPageViewBeacon({
571
- baseUrl,
572
- trackingKey: config.trackingKey
573
- });
761
+ }
762
+ if (typeof window !== "undefined" && config.autoTrackContactLinks && canSend()) {
763
+ subscribeContactLinkAutoTrack();
574
764
  }
575
765
  return {
576
766
  track,
@@ -578,8 +768,12 @@ function createJmpAnalytics(config) {
578
768
  trackFormSubmit,
579
769
  trackCallClick,
580
770
  trackEmailClick,
771
+ trackContactClick,
581
772
  trackLead,
582
- subscribeToSpaNavigation
773
+ subscribeToSpaNavigation,
774
+ subscribeContactLinkAutoTrack,
775
+ setTrackingConsent: setJmpTrackingConsent,
776
+ isTrackingConsentGranted: isJmpTrackingConsentGranted
583
777
  };
584
778
  }
585
779
  var DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 800;
@@ -592,11 +786,15 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
592
786
  const baseUrl = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
593
787
  const trackingKey = readProcessEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
594
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";
595
791
  return {
596
792
  baseUrl,
597
793
  trackingKey,
598
794
  pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
599
- ...overrides
795
+ ...overrides,
796
+ requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,
797
+ autoTrackContactLinks: overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv
600
798
  };
601
799
  }
602
800
  var jmpAnalyticsBrowserSingleton = null;
@@ -657,12 +855,9 @@ function JmpTrackedMailtoLink({
657
855
  // src/next.tsx
658
856
  var import_jsx_runtime2 = require("react/jsx-runtime");
659
857
  function JmpLandingCaptureScript({
660
- baseUrl = process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL,
661
858
  trackingKey = process.env.NEXT_PUBLIC_JMP_TRACKING_KEY
662
859
  } = {}) {
663
- const resolvedBase = baseUrl?.trim();
664
- const resolvedKey = trackingKey?.trim();
665
- if (!resolvedBase || !resolvedKey) {
860
+ if (!trackingKey?.trim()) {
666
861
  return null;
667
862
  }
668
863
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
@@ -671,10 +866,7 @@ function JmpLandingCaptureScript({
671
866
  id: "jmp-landing-capture",
672
867
  strategy: "beforeInteractive",
673
868
  dangerouslySetInnerHTML: {
674
- __html: buildLandingCaptureInlineScript({
675
- baseUrl: resolvedBase,
676
- trackingKey: resolvedKey
677
- })
869
+ __html: buildLandingCaptureInlineScript()
678
870
  }
679
871
  }
680
872
  );
@@ -693,7 +885,21 @@ function JmpNextPageViewTrackerInner() {
693
885
  function JmpNextPageViewTracker() {
694
886
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpNextPageViewTrackerInner, {}) });
695
887
  }
696
- function JmpNextAnalytics() {
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
+ }
697
903
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
698
904
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpLandingCaptureScript, {}),
699
905
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JmpNextPageViewTracker, {})
@@ -707,6 +913,9 @@ function JmpNextAnalytics() {
707
913
  JmpTrackedMailtoLink,
708
914
  JmpTrackedTelLink,
709
915
  buildLandingCaptureInlineScript,
916
+ isJmpTrackingConsentGranted,
917
+ setJmpTrackingConsent,
918
+ subscribeJmpTrackingConsent,
710
919
  useJmpAnalytics
711
920
  });
712
921
  //# sourceMappingURL=next.cjs.map