@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/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 wasEarlyBeaconSentForPath(path) {
186
- if (typeof window === "undefined") {
187
- 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;
188
238
  }
189
- try {
190
- return sessionStorage.getItem(JMP_EARLY_BEACON_PATH_KEY) === path;
191
- } catch {
192
- 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");
193
244
  }
245
+ return false;
194
246
  }
195
- function markEarlyBeaconSentForPath(path) {
196
- if (typeof window === "undefined") {
197
- 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 };
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
- sessionStorage.setItem(JMP_EARLY_BEACON_PATH_KEY, path);
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
- function sendEarlyPageViewBeacon(args) {
205
- 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") {
206
317
  return false;
207
318
  }
208
- const path = `${window.location.pathname}${window.location.search}` || "/";
209
- if (wasEarlyBeaconSentForPath(path)) {
319
+ try {
320
+ return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
321
+ } catch {
210
322
  return false;
211
323
  }
212
- const { landingReferer, utm } = captureLandingAttribution(window.location.hostname);
213
- const sessionId = getOrCreateSessionIdFromStorage();
214
- const metadata = {
215
- pageHostname: window.location.hostname,
216
- earlyBeacon: true,
217
- ...utm
218
- };
219
- if (landingReferer) {
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
- if (landingReferer) {
234
- headers["X-JMP-Visitor-Referer"] = landingReferer;
235
- }
236
- markEarlyBeaconSentForPath(path);
237
- void fetch(`${args.baseUrl.replace(/\/$/, "")}/api/events`, {
238
- method: "POST",
239
- headers,
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
- sessionStorage.removeItem(JMP_EARLY_BEACON_PATH_KEY);
341
+ localStorage.setItem(
342
+ JMP_TRACKING_CONSENT_STORAGE_KEY,
343
+ granted ? "granted" : "denied"
344
+ );
247
345
  } catch {
248
346
  }
249
- });
250
- return true;
251
- }
252
- function escapeInlineScript(value) {
253
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
254
- }
255
- function buildLandingCaptureInlineScript(args) {
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
- 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
+ });
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
- 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()) {
567
760
  captureLandingAttribution(window.location.hostname);
568
- sendEarlyPageViewBeacon({
569
- baseUrl,
570
- trackingKey: config.trackingKey
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
- const resolvedBase = baseUrl?.trim();
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 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
+ }
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