@jmp-technologies/analytics 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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",
@@ -89,11 +88,9 @@ function captureLandingAttribution(siteHostname) {
89
88
  const preservedReferer = storedReferer || cookieReferer;
90
89
  const currentReferer = document.referrer?.trim() || null;
91
90
  if (currentReferer && isExternalReferrerUrl(currentReferer, siteHostname)) {
92
- if (!storedReferer) {
93
- sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
94
- }
91
+ sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer);
95
92
  writeLandingRefererCookie(currentReferer, siteHostname);
96
- landingReferer = preservedReferer || currentReferer;
93
+ landingReferer = currentReferer;
97
94
  } else if (preservedReferer) {
98
95
  landingReferer = preservedReferer;
99
96
  if (!storedReferer) {
@@ -138,84 +135,175 @@ function getOrCreateSessionIdFromStorage() {
138
135
  return void 0;
139
136
  }
140
137
  }
141
- function wasEarlyBeaconSentForPath(path) {
142
- if (typeof window === "undefined") {
143
- return false;
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;
144
189
  }
145
- try {
146
- return sessionStorage.getItem(JMP_EARLY_BEACON_PATH_KEY) === path;
147
- } catch {
148
- return false;
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");
149
195
  }
196
+ return false;
150
197
  }
151
- function markEarlyBeaconSentForPath(path) {
152
- if (typeof window === "undefined") {
153
- return;
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" };
229
+ }
230
+ if (lower.startsWith("sms:") || lower.startsWith("smsto:")) {
231
+ return { kind: "contact_click", channel: "sms", linkHost: null };
154
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;
155
240
  try {
156
- sessionStorage.setItem(JMP_EARLY_BEACON_PATH_KEY, path);
241
+ url = new URL(raw);
157
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 };
158
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 };
258
+ }
259
+ return null;
159
260
  }
160
- function sendEarlyPageViewBeacon(args) {
161
- if (typeof window === "undefined" || typeof fetch === "undefined") {
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") {
162
269
  return false;
163
270
  }
164
- const path = `${window.location.pathname}${window.location.search}` || "/";
165
- if (wasEarlyBeaconSentForPath(path)) {
271
+ try {
272
+ return localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === "granted";
273
+ } catch {
166
274
  return false;
167
275
  }
168
- const { landingReferer, utm } = captureLandingAttribution(window.location.hostname);
169
- const sessionId = getOrCreateSessionIdFromStorage();
170
- const metadata = {
171
- pageHostname: window.location.hostname,
172
- earlyBeacon: true,
173
- ...utm
174
- };
175
- if (landingReferer) {
176
- metadata.referer = landingReferer;
177
- }
178
- const payload = {
179
- type: "page_view",
180
- path,
181
- trackingKey: args.trackingKey,
182
- ...sessionId ? { sessionId } : {},
183
- metadata
184
- };
185
- const headers = {
186
- "Content-Type": "application/json",
187
- "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);
188
284
  };
189
- if (landingReferer) {
190
- headers["X-JMP-Visitor-Referer"] = landingReferer;
285
+ }
286
+ function setJmpTrackingConsent(granted) {
287
+ if (moduleTrackingConsentGranted === granted) {
288
+ return;
191
289
  }
192
- markEarlyBeaconSentForPath(path);
193
- void fetch(`${args.baseUrl.replace(/\/$/, "")}/api/events`, {
194
- method: "POST",
195
- headers,
196
- body: JSON.stringify(payload),
197
- keepalive: true,
198
- mode: "cors",
199
- credentials: "omit"
200
- }).catch(() => {
290
+ moduleTrackingConsentGranted = granted;
291
+ if (typeof window !== "undefined") {
201
292
  try {
202
- sessionStorage.removeItem(JMP_EARLY_BEACON_PATH_KEY);
293
+ localStorage.setItem(
294
+ JMP_TRACKING_CONSENT_STORAGE_KEY,
295
+ granted ? "granted" : "denied"
296
+ );
203
297
  } catch {
204
298
  }
205
- });
206
- return true;
207
- }
208
- function escapeInlineScript(value) {
209
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
210
- }
211
- function buildLandingCaptureInlineScript(args) {
212
- const baseUrl = escapeInlineScript(args.baseUrl.replace(/\/$/, ""));
213
- const trackingKey = escapeInlineScript(args.trackingKey);
214
- const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC);
215
- 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){}})();`;
299
+ if (granted) {
300
+ captureLandingAttribution(window.location.hostname);
301
+ }
302
+ }
303
+ for (const listener of trackingConsentListeners) {
304
+ listener();
305
+ }
216
306
  }
217
-
218
- // src/index.ts
219
307
  function captureAndGetLandingReferer() {
220
308
  if (typeof window === "undefined") {
221
309
  return null;
@@ -290,9 +378,16 @@ function createJmpAnalytics(config) {
290
378
  );
291
379
  }
292
380
  const fetchFn = resolvedFetch;
381
+ moduleTrackingConsentGranted = config.requireConsent ? readStoredTrackingConsent() : true;
382
+ function canSend() {
383
+ return moduleTrackingConsentGranted;
384
+ }
293
385
  let lastDedupePath = "";
294
386
  let lastDedupeAt = 0;
295
387
  async function send(body) {
388
+ if (!canSend()) {
389
+ return;
390
+ }
296
391
  const url = `${baseUrl}/api/events`;
297
392
  const headers = {
298
393
  "Content-Type": "application/json",
@@ -348,6 +443,9 @@ function createJmpAnalytics(config) {
348
443
  }
349
444
  }
350
445
  async function sendLead(body) {
446
+ if (!canSend()) {
447
+ return;
448
+ }
351
449
  const url = `${baseUrl}/api/leads`;
352
450
  const headers = {
353
451
  "Content-Type": "application/json",
@@ -410,6 +508,9 @@ function createJmpAnalytics(config) {
410
508
  return false;
411
509
  }
412
510
  function trackPageView(options) {
511
+ if (!canSend()) {
512
+ return Promise.resolve();
513
+ }
413
514
  const pathFromOptions = options?.path?.trim();
414
515
  let pathname = "/";
415
516
  let search = "";
@@ -425,9 +526,6 @@ function createJmpAnalytics(config) {
425
526
  search = window.location.search.replace(/^\?/, "");
426
527
  }
427
528
  const path = search ? `${pathname}?${search}` : pathname;
428
- if (wasEarlyBeaconSentForPath(path)) {
429
- return Promise.resolve();
430
- }
431
529
  if (shouldDedupePageView(pathname)) {
432
530
  return Promise.resolve();
433
531
  }
@@ -478,6 +576,20 @@ function createJmpAnalytics(config) {
478
576
  metadata: metadata ?? {}
479
577
  });
480
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
+ }
481
593
  function trackLead(options) {
482
594
  const path = options?.path ?? (typeof window !== "undefined" ? window.location.pathname : "/");
483
595
  const body = { path: path || "/" };
@@ -510,7 +622,20 @@ function createJmpAnalytics(config) {
510
622
  if (type === "call_click") {
511
623
  return trackCallClick(payload.path, payload.metadata);
512
624
  }
513
- return trackEmailClick(payload.path, payload.metadata);
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
+ });
514
639
  }
515
640
  function subscribeToSpaNavigation() {
516
641
  if (typeof window === "undefined") {
@@ -544,12 +669,75 @@ function createJmpAnalytics(config) {
544
669
  history.replaceState = replace;
545
670
  };
546
671
  }
547
- if (typeof window !== "undefined") {
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()) {
548
737
  captureLandingAttribution(window.location.hostname);
549
- sendEarlyPageViewBeacon({
550
- baseUrl,
551
- trackingKey: config.trackingKey
552
- });
738
+ }
739
+ if (typeof window !== "undefined" && config.autoTrackContactLinks && canSend()) {
740
+ subscribeContactLinkAutoTrack();
553
741
  }
554
742
  return {
555
743
  track,
@@ -557,8 +745,12 @@ function createJmpAnalytics(config) {
557
745
  trackFormSubmit,
558
746
  trackCallClick,
559
747
  trackEmailClick,
748
+ trackContactClick,
560
749
  trackLead,
561
- subscribeToSpaNavigation
750
+ subscribeToSpaNavigation,
751
+ subscribeContactLinkAutoTrack,
752
+ setTrackingConsent: setJmpTrackingConsent,
753
+ isTrackingConsentGranted: isJmpTrackingConsentGranted
562
754
  };
563
755
  }
564
756
  async function trackJmpServerPageView(config, options = {}) {
@@ -681,7 +873,10 @@ async function registerJmpContentWrappers(config) {
681
873
  "Content-Type": "application/json",
682
874
  "X-JMP-Tracking-Key": config.trackingKey
683
875
  },
684
- body: JSON.stringify({ wrappers })
876
+ body: JSON.stringify({
877
+ wrappers,
878
+ sdkVersion: JMP_ANALYTICS_SDK_VERSION
879
+ })
685
880
  });
686
881
  const text = await res.text();
687
882
  if (!res.ok) {
@@ -779,11 +974,15 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
779
974
  const baseUrl = readProcessEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
780
975
  const trackingKey = readProcessEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
781
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";
782
979
  return {
783
980
  baseUrl,
784
981
  trackingKey,
785
982
  pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
786
- ...overrides
983
+ ...overrides,
984
+ requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,
985
+ autoTrackContactLinks: overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv
787
986
  };
788
987
  }
789
988
  function getJmpServerContentConfigFromEnv(overrides) {
@@ -816,8 +1015,14 @@ function createJmpContentClientFromServerEnv(overrides) {
816
1015
  }
817
1016
 
818
1017
  export {
819
- sendEarlyPageViewBeacon,
820
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,
821
1026
  createJmpAnalytics,
822
1027
  trackJmpServerPageView,
823
1028
  getJmpBlogPosts,
@@ -837,4 +1042,4 @@ export {
837
1042
  getOrCreateJmpAnalyticsFromBrowserEnv,
838
1043
  createJmpContentClientFromServerEnv
839
1044
  };
840
- //# sourceMappingURL=chunk-AEQGPTDY.js.map
1045
+ //# sourceMappingURL=chunk-SOHYQ5GT.js.map