@coframe/sdk 1.1.40 → 1.1.42

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.
@@ -1105,6 +1105,9 @@ let waitingForCookies = false;
1105
1105
  const setWaitingForCookies = (value) => {
1106
1106
  waitingForCookies = value;
1107
1107
  };
1108
+ function isWaitingForCookies() {
1109
+ return waitingForCookies;
1110
+ }
1108
1111
  let frameActivated = false;
1109
1112
  const setFrameActivated = (value) => {
1110
1113
  frameActivated = value;
@@ -1125,7 +1128,7 @@ function warnEventsNotSent() {
1125
1128
  }
1126
1129
  }
1127
1130
 
1128
- const SDK_VERSION = '2.8.0';
1131
+ const SDK_VERSION = '2.9.0';
1129
1132
  const queuedEvents = [];
1130
1133
  const queuedMonitoringEvents = [];
1131
1134
  const queuedSessions = [];
@@ -1230,7 +1233,7 @@ function flushQueuedEvents(projectId) {
1230
1233
  queuedSessions.length = 0;
1231
1234
  }
1232
1235
  }
1233
- function queueEvent(coframe, sessionInfo) {
1236
+ function queueEvent(coframe, sessionInfo, heatmap) {
1234
1237
  const { projectId, sessionId, eventType, orgId, userToken } = sessionInfo;
1235
1238
  const data = {
1236
1239
  type: eventType,
@@ -1242,13 +1245,19 @@ function queueEvent(coframe, sessionInfo) {
1242
1245
  user_token: userToken,
1243
1246
  };
1244
1247
  const seg = sessionInfo.personalizationHeaders;
1245
- const metadata = seg ? { personalization_headers: { ...seg } } : {};
1246
- if (eventType === 'page_view') {
1247
- data.content = { universal_selector: {}, metadata };
1248
- }
1249
- else {
1250
- data.content = { metadata };
1251
- }
1248
+ const metadata = seg
1249
+ ? { personalization_headers: { ...seg } }
1250
+ : {};
1251
+ if (heatmap === null || heatmap === void 0 ? void 0 : heatmap.hm)
1252
+ metadata.hm = heatmap.hm;
1253
+ data.content =
1254
+ eventType === 'page_view'
1255
+ ? {
1256
+ universal_selector: {},
1257
+ metadata,
1258
+ screen_size: { width: window.innerWidth, height: window.innerHeight },
1259
+ }
1260
+ : { metadata, ...heatmap === null || heatmap === void 0 ? void 0 : heatmap.content };
1252
1261
  queueEventForBatchedSending(coframe, data);
1253
1262
  }
1254
1263
  function queueVariantViewEvent(coframe, { projectId, sessionId, orgId, userToken, experimentId, variantId, }) {
@@ -1263,7 +1272,7 @@ function queueVariantViewEvent(coframe, { projectId, sessionId, orgId, userToken
1263
1272
  user_token: userToken,
1264
1273
  });
1265
1274
  }
1266
- function sendPageEngagementEvent(coframe, eventType, event, { projectId, sessionId, duration = 0, userToken, personalizationHeaders, }) {
1275
+ function sendPageEngagementEvent(coframe, eventType, event, { projectId, sessionId, orgId, duration = 0, userToken, personalizationHeaders, collect, }) {
1267
1276
  var _a;
1268
1277
  if (event
1269
1278
  .composedPath()
@@ -1286,6 +1295,7 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
1286
1295
  session_id: sessionId,
1287
1296
  time: new Date(),
1288
1297
  url: getCurrentPageUrl(),
1298
+ org_id: orgId,
1289
1299
  user_token: userToken,
1290
1300
  content: {
1291
1301
  universal_selector: getSelector(targetElement, {
@@ -1308,7 +1318,10 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
1308
1318
  }),
1309
1319
  },
1310
1320
  };
1311
- queueEventForBatchedSending(coframe, data, Boolean(metricIds === null || metricIds === void 0 ? void 0 : metricIds.length));
1321
+ const isConversion = Boolean(metricIds === null || metricIds === void 0 ? void 0 : metricIds.length);
1322
+ if (!(collect === null || collect === void 0 ? void 0 : collect(data, realEventTarget, event, isConversion))) {
1323
+ queueEventForBatchedSending(coframe, data, isConversion);
1324
+ }
1312
1325
  const processingDuration = performance.now() - startTime;
1313
1326
  if (coframe.status) {
1314
1327
  if (!coframe.status.events) {
@@ -3382,6 +3395,235 @@ function notifyEventsFlushed() {
3382
3395
  }
3383
3396
  }
3384
3397
 
3398
+ const DEFAULT_BLOCK_SELECTOR = '[data-cf-block],.cf-block';
3399
+ const INTERACTIVE_SELECTOR = 'a,button,input,select,textarea,label,summary,[href],[onclick],[contenteditable],[tabindex]:not([tabindex="-1"]),[role=button],[role=link],[role=tab],[role=checkbox],[role=menuitem]';
3400
+ const HOLD_MS = 1000;
3401
+ const RAGE_WINDOW_MS = 700;
3402
+ const RAGE_RADIUS_PX = 30;
3403
+ const RAGE_CLICKS = 3;
3404
+ let enabled = false;
3405
+ let allPages = false;
3406
+ let coframe = null;
3407
+ let blockSelector = DEFAULT_BLOCK_SELECTOR;
3408
+ const held = [];
3409
+ let recent = [];
3410
+ let lastActivity = 0;
3411
+ let observer = null;
3412
+ let pageView = '';
3413
+ let maxDepth = 0;
3414
+ let engagedMs = 0;
3415
+ let visibleSince = null;
3416
+ let navigated = false;
3417
+ function meta(name) {
3418
+ const tag = document.querySelector(`meta[name="coframe:${name}"]`);
3419
+ return (tag === null || tag === void 0 ? void 0 : tag.getAttribute('content')) || undefined;
3420
+ }
3421
+ function heatmapActive() {
3422
+ return enabled && (allPages || !!meta('page'));
3423
+ }
3424
+ function pageFields(withHeight) {
3425
+ const fields = {
3426
+ page: meta('page'),
3427
+ ver: meta('version'),
3428
+ variant: meta('variant'),
3429
+ row: meta('row'),
3430
+ };
3431
+ if (withHeight)
3432
+ fields.doc_h = document.documentElement.scrollHeight;
3433
+ return fields;
3434
+ }
3435
+ function round3(value) {
3436
+ return Math.round(Math.min(1, Math.max(0, value)) * 1000) / 1000;
3437
+ }
3438
+ function markActivity() {
3439
+ lastActivity = Date.now();
3440
+ }
3441
+ function viewportBottom() {
3442
+ return Math.round(window.scrollY + window.innerHeight);
3443
+ }
3444
+ function restartCounters(depth) {
3445
+ maxDepth = depth;
3446
+ engagedMs = 0;
3447
+ visibleSince = document.hidden ? null : Date.now();
3448
+ }
3449
+ function syncPageView() {
3450
+ if (!coframe || coframe.sessionId === pageView)
3451
+ return;
3452
+ pageView = coframe.sessionId;
3453
+ if (navigated)
3454
+ navigated = false;
3455
+ else
3456
+ restartCounters(viewportBottom());
3457
+ }
3458
+ function onScroll() {
3459
+ markActivity();
3460
+ syncPageView();
3461
+ maxDepth = Math.max(maxDepth, viewportBottom());
3462
+ }
3463
+ function onVisibility() {
3464
+ if (document.hidden) {
3465
+ if (visibleSince !== null)
3466
+ engagedMs += Date.now() - visibleSince;
3467
+ visibleSince = null;
3468
+ releaseHeldClicks();
3469
+ }
3470
+ else if (visibleSince === null) {
3471
+ visibleSince = Date.now();
3472
+ }
3473
+ }
3474
+ function readBlockSelector(selector) {
3475
+ if (typeof selector !== 'string' || !selector)
3476
+ return DEFAULT_BLOCK_SELECTOR;
3477
+ try {
3478
+ document.createElement('div').matches(selector);
3479
+ return selector;
3480
+ }
3481
+ catch (_a) {
3482
+ return DEFAULT_BLOCK_SELECTOR;
3483
+ }
3484
+ }
3485
+ function startHeatmaps(target, project) {
3486
+ var _a, _b;
3487
+ const settings = (_a = project === null || project === void 0 ? void 0 : project.settings) === null || _a === void 0 ? void 0 : _a.heatmaps;
3488
+ if (enabled || !(settings === null || settings === void 0 ? void 0 : settings.enabled))
3489
+ return;
3490
+ enabled = true;
3491
+ allPages = !!settings.all_pages;
3492
+ blockSelector = readBlockSelector((_b = project.settings.session_replay) === null || _b === void 0 ? void 0 : _b.block_selector);
3493
+ coframe = target;
3494
+ syncPageView();
3495
+ document.addEventListener('scroll', onScroll, {
3496
+ capture: true,
3497
+ passive: true,
3498
+ });
3499
+ document.addEventListener('visibilitychange', onVisibility);
3500
+ window.addEventListener('pagehide', releaseHeldClicks);
3501
+ window.addEventListener('beforeunload', releaseHeldClicks);
3502
+ }
3503
+ function leaveFields() {
3504
+ if (!heatmapActive())
3505
+ return undefined;
3506
+ syncPageView();
3507
+ if (navigated)
3508
+ return undefined;
3509
+ return {
3510
+ content: {
3511
+ scroll_depth: Math.max(maxDepth, viewportBottom()),
3512
+ 'duration-ms': Math.round(engagedMs + (visibleSince === null ? 0 : Date.now() - visibleSince)),
3513
+ },
3514
+ hm: pageFields(true),
3515
+ };
3516
+ }
3517
+ function pageLeaveFields() {
3518
+ if (!enabled)
3519
+ return undefined;
3520
+ const fields = leaveFields();
3521
+ restartCounters(0);
3522
+ navigated = true;
3523
+ return fields;
3524
+ }
3525
+ function watchMutations() {
3526
+ if (observer || typeof MutationObserver !== 'function')
3527
+ return;
3528
+ observer = new MutationObserver(markActivity);
3529
+ observer.observe(document.documentElement, {
3530
+ attributes: true,
3531
+ characterData: true,
3532
+ childList: true,
3533
+ subtree: true,
3534
+ });
3535
+ }
3536
+ function settle(click) {
3537
+ const index = held.indexOf(click);
3538
+ if (index < 0)
3539
+ return;
3540
+ held.splice(index, 1);
3541
+ if (click.hm.kind !== 'rage') {
3542
+ const dead = click.candidate &&
3543
+ lastActivity < click.t &&
3544
+ document.activeElement === click.focused &&
3545
+ location.href === click.href;
3546
+ click.hm.kind = dead ? 'dead' : 'click';
3547
+ }
3548
+ if (coframe)
3549
+ queueEventForBatchedSending(coframe, click.data);
3550
+ if (observer && !held.some((h) => h.candidate)) {
3551
+ observer.disconnect();
3552
+ observer = null;
3553
+ }
3554
+ }
3555
+ function releaseHeldClicks() {
3556
+ for (const click of held.splice(0)) {
3557
+ if (click.hm.kind === undefined)
3558
+ click.hm.kind = null;
3559
+ if (coframe)
3560
+ queueEventForBatchedSending(coframe, click.data);
3561
+ }
3562
+ if (observer) {
3563
+ observer.disconnect();
3564
+ observer = null;
3565
+ }
3566
+ }
3567
+ function copyKey(node, id) {
3568
+ const items = [];
3569
+ for (let at = node; at; at = at.parentElement) {
3570
+ const item = at.getAttribute('data-el-item');
3571
+ if (item)
3572
+ items.unshift(item);
3573
+ }
3574
+ return items.length ? `${id}~${items.join('.')}` : id;
3575
+ }
3576
+ function collectClick(data, target, event, isConversion) {
3577
+ if (!target.closest || target.closest(blockSelector))
3578
+ return false;
3579
+ const content = data.content;
3580
+ const position = content.position;
3581
+ const hm = pageFields(true);
3582
+ const anchor = target.closest('[data-el]');
3583
+ if (anchor) {
3584
+ const id = anchor.getAttribute('data-el');
3585
+ hm.el = id ? copyKey(anchor, id) : undefined;
3586
+ const rect = anchor.getBoundingClientRect();
3587
+ if (rect.width > 0 && rect.height > 0) {
3588
+ hm.fx = round3((event.clientX - rect.left) / rect.width);
3589
+ hm.fy = round3((event.clientY - rect.top) / rect.height);
3590
+ }
3591
+ }
3592
+ content.metadata = {
3593
+ ...content.metadata,
3594
+ hm,
3595
+ };
3596
+ const now = Date.now();
3597
+ const click = {
3598
+ data,
3599
+ hm,
3600
+ x: position.x,
3601
+ y: position.y,
3602
+ t: now,
3603
+ candidate: !target.closest(INTERACTIVE_SELECTOR),
3604
+ focused: document.activeElement,
3605
+ href: location.href,
3606
+ };
3607
+ recent = recent.filter((r) => now - r.t <= RAGE_WINDOW_MS);
3608
+ recent.push(click);
3609
+ const cluster = recent.filter((r) => Math.abs(r.x - click.x) <= RAGE_RADIUS_PX &&
3610
+ Math.abs(r.y - click.y) <= RAGE_RADIUS_PX);
3611
+ if (cluster.length >= RAGE_CLICKS) {
3612
+ for (const r of cluster)
3613
+ r.hm.kind = 'rage';
3614
+ }
3615
+ if (isConversion) {
3616
+ if (hm.kind === undefined)
3617
+ hm.kind = null;
3618
+ return false;
3619
+ }
3620
+ held.push(click);
3621
+ if (click.candidate)
3622
+ watchMutations();
3623
+ setTimeout(() => settle(click), HOLD_MS);
3624
+ return true;
3625
+ }
3626
+
3385
3627
  function startSession(Coframe, cookiesEnabled, executionStartTime, personalizationHeaders, sessionContext, pageUrl = getCurrentPageUrl()) {
3386
3628
  const sessionPayload = [
3387
3629
  Coframe,
@@ -3408,7 +3650,7 @@ function startSession(Coframe, cookiesEnabled, executionStartTime, personalizati
3408
3650
  orgId: Coframe.orgId,
3409
3651
  userToken: Coframe.userToken,
3410
3652
  personalizationHeaders,
3411
- });
3653
+ }, heatmapActive() ? { hm: pageFields(false) } : undefined);
3412
3654
  }
3413
3655
  function reportInitTiming(Coframe, project, integrationStartTime, executionStartTime) {
3414
3656
  var _a;
@@ -3641,20 +3883,15 @@ function setupListeners(Coframe, executionStartTime) {
3641
3883
  sendPageEngagementEvent(Coframe, 'click', event, {
3642
3884
  projectId: Coframe.projectId,
3643
3885
  sessionId: Coframe.sessionId,
3886
+ orgId: Coframe.orgId,
3644
3887
  userToken: Coframe.userToken,
3645
3888
  personalizationHeaders: Coframe.personalizationHeaders,
3889
+ collect: heatmapActive() ? collectClick : undefined,
3646
3890
  });
3647
3891
  };
3648
3892
  document.addEventListener('click', handleClick, true);
3649
3893
  const handleEventFlush = debounce((eventType) => {
3650
- queueEvent(Coframe, {
3651
- projectId: Coframe.projectId,
3652
- sessionId: Coframe.sessionId,
3653
- eventType: eventType,
3654
- orgId: Coframe.orgId,
3655
- userToken: Coframe.userToken,
3656
- personalizationHeaders: Coframe.personalizationHeaders,
3657
- });
3894
+ queueLeaveEvent(Coframe, eventType, eventType === 'tab_show' ? undefined : leaveFields());
3658
3895
  flushQueuedEvents(Coframe.projectId);
3659
3896
  notifyEventsFlushed();
3660
3897
  }, 1);
@@ -3666,11 +3903,27 @@ function setupListeners(Coframe, executionStartTime) {
3666
3903
  handleEventFlush(eventType);
3667
3904
  });
3668
3905
  }
3906
+ function queueLeaveEvent(Coframe, eventType, fields) {
3907
+ queueEvent(Coframe, {
3908
+ projectId: Coframe.projectId,
3909
+ sessionId: Coframe.sessionId,
3910
+ eventType,
3911
+ orgId: Coframe.orgId,
3912
+ userToken: Coframe.userToken,
3913
+ personalizationHeaders: Coframe.personalizationHeaders,
3914
+ }, fields);
3915
+ }
3916
+ function sendPageLeave(Coframe) {
3917
+ const fields = pageLeaveFields();
3918
+ if (fields)
3919
+ queueLeaveEvent(Coframe, 'page_leave', fields);
3920
+ }
3669
3921
  function setupTracking(Coframe, projectResult, previewVariantId, executionStartTime, nonce, waitForCookiesEnabled, onConsentChange) {
3670
3922
  var _a, _b;
3671
3923
  const logger = Coframe.logger;
3672
3924
  const { project } = projectResult;
3673
3925
  setTrackOnlyActivatedFrames(!!((_a = project === null || project === void 0 ? void 0 : project.settings) === null || _a === void 0 ? void 0 : _a.track_only_activated_frames));
3926
+ startHeatmaps(Coframe, project);
3674
3927
  const analytics = createTreatmentAnalytics(Coframe, previewVariantId);
3675
3928
  setupListeners(Coframe, executionStartTime);
3676
3929
  const managedAnalyticsCallback = (_b = project === null || project === void 0 ? void 0 : project.settings) === null || _b === void 0 ? void 0 : _b.analytics_callback;
@@ -3786,6 +4039,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
3786
4039
  let navigationAbortController = null;
3787
4040
  observeUrlChanges(false, async (newPageUrl, _oldPageUrl) => {
3788
4041
  var _a;
4042
+ sendPageLeave(Coframe);
3789
4043
  if (navigationAbortController)
3790
4044
  navigationAbortController.abort();
3791
4045
  navigationAbortController = new AbortController();
@@ -3934,11 +4188,90 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
3934
4188
  setupFlushInterval(Coframe);
3935
4189
  }
3936
4190
 
4191
+ function readClientCommand() {
4192
+ try {
4193
+ const cmd = findLastCmd((c) => typeof c.cookiesEnabled === 'boolean');
4194
+ if (!cmd)
4195
+ return undefined;
4196
+ return cmd.cookiesEnabled === true ? 'granted' : 'denied';
4197
+ }
4198
+ catch (_a) {
4199
+ return undefined;
4200
+ }
4201
+ }
4202
+ function readOneTrust() {
4203
+ var _a;
4204
+ try {
4205
+ const { OnetrustActiveGroups: groups, OneTrust } = window;
4206
+ if (typeof groups !== 'string' && OneTrust === undefined)
4207
+ return undefined;
4208
+ if (typeof groups === 'string' && groups.split(',').indexOf('C0002') !== -1)
4209
+ return 'granted';
4210
+ return ((_a = OneTrust === null || OneTrust === void 0 ? void 0 : OneTrust.IsAlertBoxClosed) === null || _a === void 0 ? void 0 : _a.call(OneTrust)) === true ? 'denied' : 'pending';
4211
+ }
4212
+ catch (_b) {
4213
+ return undefined;
4214
+ }
4215
+ }
4216
+ function readCookiebot() {
4217
+ var _a;
4218
+ try {
4219
+ const { Cookiebot } = window;
4220
+ if (Cookiebot === undefined)
4221
+ return undefined;
4222
+ if (((_a = Cookiebot.consent) === null || _a === void 0 ? void 0 : _a.statistics) === true)
4223
+ return 'granted';
4224
+ return Cookiebot.hasResponse === true ? 'denied' : 'pending';
4225
+ }
4226
+ catch (_b) {
4227
+ return undefined;
4228
+ }
4229
+ }
4230
+ function readConsentMode() {
4231
+ var _a;
4232
+ try {
4233
+ const { dataLayer } = window;
4234
+ if (!Array.isArray(dataLayer))
4235
+ return undefined;
4236
+ let update;
4237
+ let defaultGranted = false;
4238
+ let defaultDenied = false;
4239
+ for (let i = 0; i < dataLayer.length; i++) {
4240
+ const entry = dataLayer[i];
4241
+ if (entry === null ||
4242
+ typeof entry !== 'object' ||
4243
+ entry[0] !== 'consent' ||
4244
+ (entry[1] !== 'default' && entry[1] !== 'update')) {
4245
+ continue;
4246
+ }
4247
+ const storage = (_a = entry[2]) === null || _a === void 0 ? void 0 : _a.analytics_storage;
4248
+ if (storage !== 'granted' && storage !== 'denied')
4249
+ continue;
4250
+ if (entry[1] === 'update')
4251
+ update = storage;
4252
+ else if (storage === 'denied')
4253
+ defaultDenied = true;
4254
+ else
4255
+ defaultGranted = true;
4256
+ }
4257
+ if (update !== undefined)
4258
+ return update;
4259
+ if (defaultDenied)
4260
+ return 'pending';
4261
+ return defaultGranted ? 'granted' : undefined;
4262
+ }
4263
+ catch (_b) {
4264
+ return undefined;
4265
+ }
4266
+ }
4267
+
3937
4268
  let startRequested = false;
3938
4269
  let replayScriptUrl;
3939
4270
  const COMPILED_REPLAY_SCRIPT_URL = `${"https://edge.cofra.me"}/replay/latest.js`;
3940
4271
  const CONSENT_POLL_MS = 100;
3941
4272
  const CONSENT_WAIT_MS = 5000;
4273
+ const CONSENT_DETECT_WAIT_MS = 10000;
4274
+ const EXPLICIT_CONSENT_WAIT_MS = 60000;
3942
4275
  function configureReplayScriptUrl(url) {
3943
4276
  replayScriptUrl = (url === null || url === void 0 ? void 0 : url.trim()) || undefined;
3944
4277
  }
@@ -3949,8 +4282,25 @@ function readReplayConsent() {
3949
4282
  return { state: 'denied', reason: 'gpc' };
3950
4283
  }
3951
4284
  const shopify = window.Shopify;
3952
- if (shopify === undefined)
3953
- return { state: 'allowed', source: 'none' };
4285
+ if (shopify === undefined) {
4286
+ const readers = [
4287
+ [readClientCommand, 'client'],
4288
+ [readOneTrust, 'onetrust'],
4289
+ [readCookiebot, 'cookiebot'],
4290
+ [readConsentMode, 'consent_mode'],
4291
+ ];
4292
+ for (let i = 0; i < readers.length; i++) {
4293
+ const [read, source] = readers[i];
4294
+ const signal = read();
4295
+ if (signal === 'granted')
4296
+ return { state: 'allowed', source };
4297
+ if (signal === 'denied')
4298
+ return { state: 'denied', reason: 'consent_denied' };
4299
+ if (signal === 'pending')
4300
+ return { state: 'pending', detected: true };
4301
+ }
4302
+ return { state: 'pending', detected: isWaitingForCookies() };
4303
+ }
3954
4304
  const customerPrivacy = shopify.customerPrivacy;
3955
4305
  const analyticsProcessingAllowed = customerPrivacy === null || customerPrivacy === void 0 ? void 0 : customerPrivacy.analyticsProcessingAllowed;
3956
4306
  if (typeof analyticsProcessingAllowed === 'function') {
@@ -4052,11 +4402,14 @@ function startReplayIfEnabled(coframe, project, nonce) {
4052
4402
  const settings = (_a = project.settings) === null || _a === void 0 ? void 0 : _a.session_replay;
4053
4403
  if ((settings === null || settings === void 0 ? void 0 : settings.enabled) !== true ||
4054
4404
  typeof CompressionStream !== 'function' ||
4055
- !shouldSendEvents() ||
4405
+ !shouldSendEvents({
4406
+ ignoreConsent: window.Shopify === undefined,
4407
+ }) ||
4056
4408
  startRequested) {
4057
4409
  return;
4058
4410
  }
4059
4411
  startRequested = true;
4412
+ const isShopify = window.Shopify !== undefined;
4060
4413
  let waited = 0;
4061
4414
  const decide = () => {
4062
4415
  var _a;
@@ -4067,7 +4420,12 @@ function startReplayIfEnabled(coframe, project, nonce) {
4067
4420
  else if (consent.state === 'denied') {
4068
4421
  reportReplaySkipped(coframe, consent.reason);
4069
4422
  }
4070
- else if (waited >= CONSENT_WAIT_MS) {
4423
+ else if (!isShopify &&
4424
+ consent.detected !== true &&
4425
+ waited >= CONSENT_DETECT_WAIT_MS) {
4426
+ reportReplaySkipped(coframe, 'consent_not_configured');
4427
+ }
4428
+ else if (waited >= (isShopify ? CONSENT_WAIT_MS : EXPLICIT_CONSENT_WAIT_MS)) {
4071
4429
  reportReplaySkipped(coframe, 'consent_unavailable');
4072
4430
  }
4073
4431
  else {
@@ -1103,6 +1103,9 @@ let waitingForCookies = false;
1103
1103
  const setWaitingForCookies = (value) => {
1104
1104
  waitingForCookies = value;
1105
1105
  };
1106
+ function isWaitingForCookies() {
1107
+ return waitingForCookies;
1108
+ }
1106
1109
  let frameActivated = false;
1107
1110
  const setFrameActivated = (value) => {
1108
1111
  frameActivated = value;
@@ -1123,7 +1126,7 @@ function warnEventsNotSent() {
1123
1126
  }
1124
1127
  }
1125
1128
 
1126
- const SDK_VERSION = '2.8.0';
1129
+ const SDK_VERSION = '2.9.0';
1127
1130
  const queuedEvents = [];
1128
1131
  const queuedMonitoringEvents = [];
1129
1132
  const queuedSessions = [];
@@ -1228,7 +1231,7 @@ function flushQueuedEvents(projectId) {
1228
1231
  queuedSessions.length = 0;
1229
1232
  }
1230
1233
  }
1231
- function queueEvent(coframe, sessionInfo) {
1234
+ function queueEvent(coframe, sessionInfo, heatmap) {
1232
1235
  const { projectId, sessionId, eventType, orgId, userToken } = sessionInfo;
1233
1236
  const data = {
1234
1237
  type: eventType,
@@ -1240,13 +1243,19 @@ function queueEvent(coframe, sessionInfo) {
1240
1243
  user_token: userToken,
1241
1244
  };
1242
1245
  const seg = sessionInfo.personalizationHeaders;
1243
- const metadata = seg ? { personalization_headers: { ...seg } } : {};
1244
- if (eventType === 'page_view') {
1245
- data.content = { universal_selector: {}, metadata };
1246
- }
1247
- else {
1248
- data.content = { metadata };
1249
- }
1246
+ const metadata = seg
1247
+ ? { personalization_headers: { ...seg } }
1248
+ : {};
1249
+ if (heatmap === null || heatmap === void 0 ? void 0 : heatmap.hm)
1250
+ metadata.hm = heatmap.hm;
1251
+ data.content =
1252
+ eventType === 'page_view'
1253
+ ? {
1254
+ universal_selector: {},
1255
+ metadata,
1256
+ screen_size: { width: window.innerWidth, height: window.innerHeight },
1257
+ }
1258
+ : { metadata, ...heatmap === null || heatmap === void 0 ? void 0 : heatmap.content };
1250
1259
  queueEventForBatchedSending(coframe, data);
1251
1260
  }
1252
1261
  function queueVariantViewEvent(coframe, { projectId, sessionId, orgId, userToken, experimentId, variantId, }) {
@@ -1261,7 +1270,7 @@ function queueVariantViewEvent(coframe, { projectId, sessionId, orgId, userToken
1261
1270
  user_token: userToken,
1262
1271
  });
1263
1272
  }
1264
- function sendPageEngagementEvent(coframe, eventType, event, { projectId, sessionId, duration = 0, userToken, personalizationHeaders, }) {
1273
+ function sendPageEngagementEvent(coframe, eventType, event, { projectId, sessionId, orgId, duration = 0, userToken, personalizationHeaders, collect, }) {
1265
1274
  var _a;
1266
1275
  if (event
1267
1276
  .composedPath()
@@ -1284,6 +1293,7 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
1284
1293
  session_id: sessionId,
1285
1294
  time: new Date(),
1286
1295
  url: getCurrentPageUrl(),
1296
+ org_id: orgId,
1287
1297
  user_token: userToken,
1288
1298
  content: {
1289
1299
  universal_selector: getSelector(targetElement, {
@@ -1306,7 +1316,10 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
1306
1316
  }),
1307
1317
  },
1308
1318
  };
1309
- queueEventForBatchedSending(coframe, data, Boolean(metricIds === null || metricIds === void 0 ? void 0 : metricIds.length));
1319
+ const isConversion = Boolean(metricIds === null || metricIds === void 0 ? void 0 : metricIds.length);
1320
+ if (!(collect === null || collect === void 0 ? void 0 : collect(data, realEventTarget, event, isConversion))) {
1321
+ queueEventForBatchedSending(coframe, data, isConversion);
1322
+ }
1310
1323
  const processingDuration = performance.now() - startTime;
1311
1324
  if (coframe.status) {
1312
1325
  if (!coframe.status.events) {
@@ -3380,6 +3393,235 @@ function notifyEventsFlushed() {
3380
3393
  }
3381
3394
  }
3382
3395
 
3396
+ const DEFAULT_BLOCK_SELECTOR = '[data-cf-block],.cf-block';
3397
+ const INTERACTIVE_SELECTOR = 'a,button,input,select,textarea,label,summary,[href],[onclick],[contenteditable],[tabindex]:not([tabindex="-1"]),[role=button],[role=link],[role=tab],[role=checkbox],[role=menuitem]';
3398
+ const HOLD_MS = 1000;
3399
+ const RAGE_WINDOW_MS = 700;
3400
+ const RAGE_RADIUS_PX = 30;
3401
+ const RAGE_CLICKS = 3;
3402
+ let enabled = false;
3403
+ let allPages = false;
3404
+ let coframe = null;
3405
+ let blockSelector = DEFAULT_BLOCK_SELECTOR;
3406
+ const held = [];
3407
+ let recent = [];
3408
+ let lastActivity = 0;
3409
+ let observer = null;
3410
+ let pageView = '';
3411
+ let maxDepth = 0;
3412
+ let engagedMs = 0;
3413
+ let visibleSince = null;
3414
+ let navigated = false;
3415
+ function meta(name) {
3416
+ const tag = document.querySelector(`meta[name="coframe:${name}"]`);
3417
+ return (tag === null || tag === void 0 ? void 0 : tag.getAttribute('content')) || undefined;
3418
+ }
3419
+ function heatmapActive() {
3420
+ return enabled && (allPages || !!meta('page'));
3421
+ }
3422
+ function pageFields(withHeight) {
3423
+ const fields = {
3424
+ page: meta('page'),
3425
+ ver: meta('version'),
3426
+ variant: meta('variant'),
3427
+ row: meta('row'),
3428
+ };
3429
+ if (withHeight)
3430
+ fields.doc_h = document.documentElement.scrollHeight;
3431
+ return fields;
3432
+ }
3433
+ function round3(value) {
3434
+ return Math.round(Math.min(1, Math.max(0, value)) * 1000) / 1000;
3435
+ }
3436
+ function markActivity() {
3437
+ lastActivity = Date.now();
3438
+ }
3439
+ function viewportBottom() {
3440
+ return Math.round(window.scrollY + window.innerHeight);
3441
+ }
3442
+ function restartCounters(depth) {
3443
+ maxDepth = depth;
3444
+ engagedMs = 0;
3445
+ visibleSince = document.hidden ? null : Date.now();
3446
+ }
3447
+ function syncPageView() {
3448
+ if (!coframe || coframe.sessionId === pageView)
3449
+ return;
3450
+ pageView = coframe.sessionId;
3451
+ if (navigated)
3452
+ navigated = false;
3453
+ else
3454
+ restartCounters(viewportBottom());
3455
+ }
3456
+ function onScroll() {
3457
+ markActivity();
3458
+ syncPageView();
3459
+ maxDepth = Math.max(maxDepth, viewportBottom());
3460
+ }
3461
+ function onVisibility() {
3462
+ if (document.hidden) {
3463
+ if (visibleSince !== null)
3464
+ engagedMs += Date.now() - visibleSince;
3465
+ visibleSince = null;
3466
+ releaseHeldClicks();
3467
+ }
3468
+ else if (visibleSince === null) {
3469
+ visibleSince = Date.now();
3470
+ }
3471
+ }
3472
+ function readBlockSelector(selector) {
3473
+ if (typeof selector !== 'string' || !selector)
3474
+ return DEFAULT_BLOCK_SELECTOR;
3475
+ try {
3476
+ document.createElement('div').matches(selector);
3477
+ return selector;
3478
+ }
3479
+ catch (_a) {
3480
+ return DEFAULT_BLOCK_SELECTOR;
3481
+ }
3482
+ }
3483
+ function startHeatmaps(target, project) {
3484
+ var _a, _b;
3485
+ const settings = (_a = project === null || project === void 0 ? void 0 : project.settings) === null || _a === void 0 ? void 0 : _a.heatmaps;
3486
+ if (enabled || !(settings === null || settings === void 0 ? void 0 : settings.enabled))
3487
+ return;
3488
+ enabled = true;
3489
+ allPages = !!settings.all_pages;
3490
+ blockSelector = readBlockSelector((_b = project.settings.session_replay) === null || _b === void 0 ? void 0 : _b.block_selector);
3491
+ coframe = target;
3492
+ syncPageView();
3493
+ document.addEventListener('scroll', onScroll, {
3494
+ capture: true,
3495
+ passive: true,
3496
+ });
3497
+ document.addEventListener('visibilitychange', onVisibility);
3498
+ window.addEventListener('pagehide', releaseHeldClicks);
3499
+ window.addEventListener('beforeunload', releaseHeldClicks);
3500
+ }
3501
+ function leaveFields() {
3502
+ if (!heatmapActive())
3503
+ return undefined;
3504
+ syncPageView();
3505
+ if (navigated)
3506
+ return undefined;
3507
+ return {
3508
+ content: {
3509
+ scroll_depth: Math.max(maxDepth, viewportBottom()),
3510
+ 'duration-ms': Math.round(engagedMs + (visibleSince === null ? 0 : Date.now() - visibleSince)),
3511
+ },
3512
+ hm: pageFields(true),
3513
+ };
3514
+ }
3515
+ function pageLeaveFields() {
3516
+ if (!enabled)
3517
+ return undefined;
3518
+ const fields = leaveFields();
3519
+ restartCounters(0);
3520
+ navigated = true;
3521
+ return fields;
3522
+ }
3523
+ function watchMutations() {
3524
+ if (observer || typeof MutationObserver !== 'function')
3525
+ return;
3526
+ observer = new MutationObserver(markActivity);
3527
+ observer.observe(document.documentElement, {
3528
+ attributes: true,
3529
+ characterData: true,
3530
+ childList: true,
3531
+ subtree: true,
3532
+ });
3533
+ }
3534
+ function settle(click) {
3535
+ const index = held.indexOf(click);
3536
+ if (index < 0)
3537
+ return;
3538
+ held.splice(index, 1);
3539
+ if (click.hm.kind !== 'rage') {
3540
+ const dead = click.candidate &&
3541
+ lastActivity < click.t &&
3542
+ document.activeElement === click.focused &&
3543
+ location.href === click.href;
3544
+ click.hm.kind = dead ? 'dead' : 'click';
3545
+ }
3546
+ if (coframe)
3547
+ queueEventForBatchedSending(coframe, click.data);
3548
+ if (observer && !held.some((h) => h.candidate)) {
3549
+ observer.disconnect();
3550
+ observer = null;
3551
+ }
3552
+ }
3553
+ function releaseHeldClicks() {
3554
+ for (const click of held.splice(0)) {
3555
+ if (click.hm.kind === undefined)
3556
+ click.hm.kind = null;
3557
+ if (coframe)
3558
+ queueEventForBatchedSending(coframe, click.data);
3559
+ }
3560
+ if (observer) {
3561
+ observer.disconnect();
3562
+ observer = null;
3563
+ }
3564
+ }
3565
+ function copyKey(node, id) {
3566
+ const items = [];
3567
+ for (let at = node; at; at = at.parentElement) {
3568
+ const item = at.getAttribute('data-el-item');
3569
+ if (item)
3570
+ items.unshift(item);
3571
+ }
3572
+ return items.length ? `${id}~${items.join('.')}` : id;
3573
+ }
3574
+ function collectClick(data, target, event, isConversion) {
3575
+ if (!target.closest || target.closest(blockSelector))
3576
+ return false;
3577
+ const content = data.content;
3578
+ const position = content.position;
3579
+ const hm = pageFields(true);
3580
+ const anchor = target.closest('[data-el]');
3581
+ if (anchor) {
3582
+ const id = anchor.getAttribute('data-el');
3583
+ hm.el = id ? copyKey(anchor, id) : undefined;
3584
+ const rect = anchor.getBoundingClientRect();
3585
+ if (rect.width > 0 && rect.height > 0) {
3586
+ hm.fx = round3((event.clientX - rect.left) / rect.width);
3587
+ hm.fy = round3((event.clientY - rect.top) / rect.height);
3588
+ }
3589
+ }
3590
+ content.metadata = {
3591
+ ...content.metadata,
3592
+ hm,
3593
+ };
3594
+ const now = Date.now();
3595
+ const click = {
3596
+ data,
3597
+ hm,
3598
+ x: position.x,
3599
+ y: position.y,
3600
+ t: now,
3601
+ candidate: !target.closest(INTERACTIVE_SELECTOR),
3602
+ focused: document.activeElement,
3603
+ href: location.href,
3604
+ };
3605
+ recent = recent.filter((r) => now - r.t <= RAGE_WINDOW_MS);
3606
+ recent.push(click);
3607
+ const cluster = recent.filter((r) => Math.abs(r.x - click.x) <= RAGE_RADIUS_PX &&
3608
+ Math.abs(r.y - click.y) <= RAGE_RADIUS_PX);
3609
+ if (cluster.length >= RAGE_CLICKS) {
3610
+ for (const r of cluster)
3611
+ r.hm.kind = 'rage';
3612
+ }
3613
+ if (isConversion) {
3614
+ if (hm.kind === undefined)
3615
+ hm.kind = null;
3616
+ return false;
3617
+ }
3618
+ held.push(click);
3619
+ if (click.candidate)
3620
+ watchMutations();
3621
+ setTimeout(() => settle(click), HOLD_MS);
3622
+ return true;
3623
+ }
3624
+
3383
3625
  function startSession(Coframe, cookiesEnabled, executionStartTime, personalizationHeaders, sessionContext, pageUrl = getCurrentPageUrl()) {
3384
3626
  const sessionPayload = [
3385
3627
  Coframe,
@@ -3406,7 +3648,7 @@ function startSession(Coframe, cookiesEnabled, executionStartTime, personalizati
3406
3648
  orgId: Coframe.orgId,
3407
3649
  userToken: Coframe.userToken,
3408
3650
  personalizationHeaders,
3409
- });
3651
+ }, heatmapActive() ? { hm: pageFields(false) } : undefined);
3410
3652
  }
3411
3653
  function reportInitTiming(Coframe, project, integrationStartTime, executionStartTime) {
3412
3654
  var _a;
@@ -3639,20 +3881,15 @@ function setupListeners(Coframe, executionStartTime) {
3639
3881
  sendPageEngagementEvent(Coframe, 'click', event, {
3640
3882
  projectId: Coframe.projectId,
3641
3883
  sessionId: Coframe.sessionId,
3884
+ orgId: Coframe.orgId,
3642
3885
  userToken: Coframe.userToken,
3643
3886
  personalizationHeaders: Coframe.personalizationHeaders,
3887
+ collect: heatmapActive() ? collectClick : undefined,
3644
3888
  });
3645
3889
  };
3646
3890
  document.addEventListener('click', handleClick, true);
3647
3891
  const handleEventFlush = debounce((eventType) => {
3648
- queueEvent(Coframe, {
3649
- projectId: Coframe.projectId,
3650
- sessionId: Coframe.sessionId,
3651
- eventType: eventType,
3652
- orgId: Coframe.orgId,
3653
- userToken: Coframe.userToken,
3654
- personalizationHeaders: Coframe.personalizationHeaders,
3655
- });
3892
+ queueLeaveEvent(Coframe, eventType, eventType === 'tab_show' ? undefined : leaveFields());
3656
3893
  flushQueuedEvents(Coframe.projectId);
3657
3894
  notifyEventsFlushed();
3658
3895
  }, 1);
@@ -3664,11 +3901,27 @@ function setupListeners(Coframe, executionStartTime) {
3664
3901
  handleEventFlush(eventType);
3665
3902
  });
3666
3903
  }
3904
+ function queueLeaveEvent(Coframe, eventType, fields) {
3905
+ queueEvent(Coframe, {
3906
+ projectId: Coframe.projectId,
3907
+ sessionId: Coframe.sessionId,
3908
+ eventType,
3909
+ orgId: Coframe.orgId,
3910
+ userToken: Coframe.userToken,
3911
+ personalizationHeaders: Coframe.personalizationHeaders,
3912
+ }, fields);
3913
+ }
3914
+ function sendPageLeave(Coframe) {
3915
+ const fields = pageLeaveFields();
3916
+ if (fields)
3917
+ queueLeaveEvent(Coframe, 'page_leave', fields);
3918
+ }
3667
3919
  function setupTracking(Coframe, projectResult, previewVariantId, executionStartTime, nonce, waitForCookiesEnabled, onConsentChange) {
3668
3920
  var _a, _b;
3669
3921
  const logger = Coframe.logger;
3670
3922
  const { project } = projectResult;
3671
3923
  setTrackOnlyActivatedFrames(!!((_a = project === null || project === void 0 ? void 0 : project.settings) === null || _a === void 0 ? void 0 : _a.track_only_activated_frames));
3924
+ startHeatmaps(Coframe, project);
3672
3925
  const analytics = createTreatmentAnalytics(Coframe, previewVariantId);
3673
3926
  setupListeners(Coframe, executionStartTime);
3674
3927
  const managedAnalyticsCallback = (_b = project === null || project === void 0 ? void 0 : project.settings) === null || _b === void 0 ? void 0 : _b.analytics_callback;
@@ -3784,6 +4037,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
3784
4037
  let navigationAbortController = null;
3785
4038
  observeUrlChanges(false, async (newPageUrl, _oldPageUrl) => {
3786
4039
  var _a;
4040
+ sendPageLeave(Coframe);
3787
4041
  if (navigationAbortController)
3788
4042
  navigationAbortController.abort();
3789
4043
  navigationAbortController = new AbortController();
@@ -3932,11 +4186,90 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
3932
4186
  setupFlushInterval(Coframe);
3933
4187
  }
3934
4188
 
4189
+ function readClientCommand() {
4190
+ try {
4191
+ const cmd = findLastCmd((c) => typeof c.cookiesEnabled === 'boolean');
4192
+ if (!cmd)
4193
+ return undefined;
4194
+ return cmd.cookiesEnabled === true ? 'granted' : 'denied';
4195
+ }
4196
+ catch (_a) {
4197
+ return undefined;
4198
+ }
4199
+ }
4200
+ function readOneTrust() {
4201
+ var _a;
4202
+ try {
4203
+ const { OnetrustActiveGroups: groups, OneTrust } = window;
4204
+ if (typeof groups !== 'string' && OneTrust === undefined)
4205
+ return undefined;
4206
+ if (typeof groups === 'string' && groups.split(',').indexOf('C0002') !== -1)
4207
+ return 'granted';
4208
+ return ((_a = OneTrust === null || OneTrust === void 0 ? void 0 : OneTrust.IsAlertBoxClosed) === null || _a === void 0 ? void 0 : _a.call(OneTrust)) === true ? 'denied' : 'pending';
4209
+ }
4210
+ catch (_b) {
4211
+ return undefined;
4212
+ }
4213
+ }
4214
+ function readCookiebot() {
4215
+ var _a;
4216
+ try {
4217
+ const { Cookiebot } = window;
4218
+ if (Cookiebot === undefined)
4219
+ return undefined;
4220
+ if (((_a = Cookiebot.consent) === null || _a === void 0 ? void 0 : _a.statistics) === true)
4221
+ return 'granted';
4222
+ return Cookiebot.hasResponse === true ? 'denied' : 'pending';
4223
+ }
4224
+ catch (_b) {
4225
+ return undefined;
4226
+ }
4227
+ }
4228
+ function readConsentMode() {
4229
+ var _a;
4230
+ try {
4231
+ const { dataLayer } = window;
4232
+ if (!Array.isArray(dataLayer))
4233
+ return undefined;
4234
+ let update;
4235
+ let defaultGranted = false;
4236
+ let defaultDenied = false;
4237
+ for (let i = 0; i < dataLayer.length; i++) {
4238
+ const entry = dataLayer[i];
4239
+ if (entry === null ||
4240
+ typeof entry !== 'object' ||
4241
+ entry[0] !== 'consent' ||
4242
+ (entry[1] !== 'default' && entry[1] !== 'update')) {
4243
+ continue;
4244
+ }
4245
+ const storage = (_a = entry[2]) === null || _a === void 0 ? void 0 : _a.analytics_storage;
4246
+ if (storage !== 'granted' && storage !== 'denied')
4247
+ continue;
4248
+ if (entry[1] === 'update')
4249
+ update = storage;
4250
+ else if (storage === 'denied')
4251
+ defaultDenied = true;
4252
+ else
4253
+ defaultGranted = true;
4254
+ }
4255
+ if (update !== undefined)
4256
+ return update;
4257
+ if (defaultDenied)
4258
+ return 'pending';
4259
+ return defaultGranted ? 'granted' : undefined;
4260
+ }
4261
+ catch (_b) {
4262
+ return undefined;
4263
+ }
4264
+ }
4265
+
3935
4266
  let startRequested = false;
3936
4267
  let replayScriptUrl;
3937
4268
  const COMPILED_REPLAY_SCRIPT_URL = `${"https://edge.cofra.me"}/replay/latest.js`;
3938
4269
  const CONSENT_POLL_MS = 100;
3939
4270
  const CONSENT_WAIT_MS = 5000;
4271
+ const CONSENT_DETECT_WAIT_MS = 10000;
4272
+ const EXPLICIT_CONSENT_WAIT_MS = 60000;
3940
4273
  function configureReplayScriptUrl(url) {
3941
4274
  replayScriptUrl = (url === null || url === void 0 ? void 0 : url.trim()) || undefined;
3942
4275
  }
@@ -3947,8 +4280,25 @@ function readReplayConsent() {
3947
4280
  return { state: 'denied', reason: 'gpc' };
3948
4281
  }
3949
4282
  const shopify = window.Shopify;
3950
- if (shopify === undefined)
3951
- return { state: 'allowed', source: 'none' };
4283
+ if (shopify === undefined) {
4284
+ const readers = [
4285
+ [readClientCommand, 'client'],
4286
+ [readOneTrust, 'onetrust'],
4287
+ [readCookiebot, 'cookiebot'],
4288
+ [readConsentMode, 'consent_mode'],
4289
+ ];
4290
+ for (let i = 0; i < readers.length; i++) {
4291
+ const [read, source] = readers[i];
4292
+ const signal = read();
4293
+ if (signal === 'granted')
4294
+ return { state: 'allowed', source };
4295
+ if (signal === 'denied')
4296
+ return { state: 'denied', reason: 'consent_denied' };
4297
+ if (signal === 'pending')
4298
+ return { state: 'pending', detected: true };
4299
+ }
4300
+ return { state: 'pending', detected: isWaitingForCookies() };
4301
+ }
3952
4302
  const customerPrivacy = shopify.customerPrivacy;
3953
4303
  const analyticsProcessingAllowed = customerPrivacy === null || customerPrivacy === void 0 ? void 0 : customerPrivacy.analyticsProcessingAllowed;
3954
4304
  if (typeof analyticsProcessingAllowed === 'function') {
@@ -4050,11 +4400,14 @@ function startReplayIfEnabled(coframe, project, nonce) {
4050
4400
  const settings = (_a = project.settings) === null || _a === void 0 ? void 0 : _a.session_replay;
4051
4401
  if ((settings === null || settings === void 0 ? void 0 : settings.enabled) !== true ||
4052
4402
  typeof CompressionStream !== 'function' ||
4053
- !shouldSendEvents() ||
4403
+ !shouldSendEvents({
4404
+ ignoreConsent: window.Shopify === undefined,
4405
+ }) ||
4054
4406
  startRequested) {
4055
4407
  return;
4056
4408
  }
4057
4409
  startRequested = true;
4410
+ const isShopify = window.Shopify !== undefined;
4058
4411
  let waited = 0;
4059
4412
  const decide = () => {
4060
4413
  var _a;
@@ -4065,7 +4418,12 @@ function startReplayIfEnabled(coframe, project, nonce) {
4065
4418
  else if (consent.state === 'denied') {
4066
4419
  reportReplaySkipped(coframe, consent.reason);
4067
4420
  }
4068
- else if (waited >= CONSENT_WAIT_MS) {
4421
+ else if (!isShopify &&
4422
+ consent.detected !== true &&
4423
+ waited >= CONSENT_DETECT_WAIT_MS) {
4424
+ reportReplaySkipped(coframe, 'consent_not_configured');
4425
+ }
4426
+ else if (waited >= (isShopify ? CONSENT_WAIT_MS : EXPLICIT_CONSENT_WAIT_MS)) {
4069
4427
  reportReplaySkipped(coframe, 'consent_unavailable');
4070
4428
  }
4071
4429
  else {
@@ -144,6 +144,10 @@ interface Metric {
144
144
  selector: SelectorCondition;
145
145
  js_binder?: string;
146
146
  }
147
+ interface HeatmapSettings {
148
+ enabled: boolean;
149
+ all_pages?: boolean;
150
+ }
147
151
  interface ProjectSettings {
148
152
  mutation_observer_active: boolean;
149
153
  track_only_activated_frames?: boolean;
@@ -152,6 +156,7 @@ interface ProjectSettings {
152
156
  bot_score_threshold?: number;
153
157
  analytics_callback?: AnalyticsCallback;
154
158
  session_replay?: SessionReplaySettings | null;
159
+ heatmaps?: HeatmapSettings | null;
155
160
  }
156
161
  interface Project {
157
162
  org_id: string;
@@ -164,6 +164,10 @@ interface Metric {
164
164
  selector: SelectorCondition;
165
165
  js_binder?: string;
166
166
  }
167
+ interface HeatmapSettings {
168
+ enabled: boolean;
169
+ all_pages?: boolean;
170
+ }
167
171
  interface ProjectSettings {
168
172
  mutation_observer_active: boolean;
169
173
  track_only_activated_frames?: boolean;
@@ -172,6 +176,7 @@ interface ProjectSettings {
172
176
  bot_score_threshold?: number;
173
177
  analytics_callback?: AnalyticsCallback;
174
178
  session_replay?: SessionReplaySettings | null;
179
+ heatmaps?: HeatmapSettings | null;
175
180
  }
176
181
  interface Project {
177
182
  org_id: string;
@@ -110,6 +110,10 @@ interface Metric {
110
110
  selector: SelectorCondition;
111
111
  js_binder?: string;
112
112
  }
113
+ interface HeatmapSettings {
114
+ enabled: boolean;
115
+ all_pages?: boolean;
116
+ }
113
117
  interface ProjectSettings {
114
118
  mutation_observer_active: boolean;
115
119
  track_only_activated_frames?: boolean;
@@ -118,6 +122,7 @@ interface ProjectSettings {
118
122
  bot_score_threshold?: number;
119
123
  analytics_callback?: AnalyticsCallback;
120
124
  session_replay?: SessionReplaySettings | null;
125
+ heatmaps?: HeatmapSettings | null;
121
126
  }
122
127
  interface Project {
123
128
  org_id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coframe/sdk",
3
- "version": "1.1.40",
3
+ "version": "1.1.42",
4
4
  "description": "Coframe optimizes your website using generative AI to deliver maximum impact to your audience and allow your site to improve itself as you sleep. Learn more at coframe.com.",
5
5
  "main": "dist/pkg/cf.cjs.js",
6
6
  "module": "dist/pkg/cf.esm.mjs",