@magicfeedback/popup-sdk 1.11.0 → 1.13.0

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/index.d.mts CHANGED
@@ -383,6 +383,23 @@ type EventListener = (event: DeepdotsEvent) => void;
383
383
  * anterior se cierra y se abre otra, como hace GA con su timeout de sesión.
384
384
  */
385
385
  type SessionEndReason = 'page_hide' | 'background' | 'user_change' | 'tracking_disabled' | 'manual' | 'idle_timeout';
386
+ /**
387
+ * Motivo del `deepdots_session_start` (param `reason`): por qué EMPIEZA la sesión. Permite a
388
+ * analytics separar una carga/arranque real de una vuelta desde background ("Started here").
389
+ * Mismos valores que el SDK nativo donde el significado coincide:
390
+ * - `cold_start`: `init()` (carga de la página / arranque de la app RN) sin sesión suspendida
391
+ * que reanudar. Una recarga en menos de 1 min no emite `session_start` sino
392
+ * `deepdots_session_resume`.
393
+ * - `foreground`: `onForeground()` (RN, AppState 'active') tras un cierre (`onBackground()`
394
+ * o `endSession()`). Con la sesión abierta no emite nada.
395
+ * - `tracking_enabled`: `setTrackingEnabled(true)` (consentimiento concedido).
396
+ * - `user_change`: `setUserId()` o un `init()` con otro `userId`, tras cerrar la del anterior.
397
+ * - `idle_timeout`: la pestaña vuelve a verse tras más de 30 min oculta (web): la sesión
398
+ * anterior se cerró (o se descartó) y empieza otra.
399
+ * - `bfcache_restore`: la página vuelve de la bfcache (botón atrás, `pageshow` con
400
+ * `persisted`) fuera de la ventana de reanudación (web).
401
+ */
402
+ type SessionStartReason = 'cold_start' | 'foreground' | 'tracking_enabled' | 'user_change' | 'idle_timeout' | 'bfcache_restore';
386
403
  /** Trigger type used by remote popup definitions */
387
404
  type PopupTriggerType = 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
388
405
  type PopupTriggerConditionStatus = 'SHOWED' | 'PARTIAL' | 'COMPLETED';
@@ -888,8 +905,15 @@ declare class DeepdotsPopups {
888
905
  */
889
906
  private closeSession;
890
907
  /**
891
- * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente:
892
- * se llama en init(), al volver a foreground y al conceder el consentimiento.
908
+ * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente.
909
+ * El `reason` dice por qué empieza (ver `SessionStartReason`):
910
+ * - `cold_start`: init() (carga de la página / arranque de la app RN).
911
+ * - `foreground`: onForeground() tras un cierre (RN).
912
+ * - `tracking_enabled`: setTrackingEnabled(true).
913
+ * - `user_change`: setUserId() o init() con otro userId.
914
+ * - `idle_timeout`: la pestaña vuelve a verse tras más de 30 min oculta.
915
+ * - `bfcache_restore`: vuelta desde la bfcache fuera de la ventana de reanudación.
916
+ * Si hay una sesión suspendida a tiempo emite `deepdots_session_resume` en su lugar, sin reason.
893
917
  */
894
918
  private openSession;
895
919
  /** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
@@ -905,7 +929,20 @@ declare class DeepdotsPopups {
905
929
  final?: boolean;
906
930
  sessionEnd?: boolean;
907
931
  }): void;
908
- /** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
932
+ /**
933
+ * Emite un evento `user_engagement` con el tiempo activo acumulado (#8) y la pantalla en
934
+ * curso: `screen` y `path` (los mismos que llevará su `page_view`) y `screen_seconds` (lo
935
+ * que lleva en ella, medido como el `duration_seconds` del `page_view`).
936
+ *
937
+ * El `page_view` sale al SALIR de la pantalla; si el cierre no llega nunca (pestaña dormida
938
+ * y descartada al volver, pestaña o app matada en segundo plano), la última pantalla de la
939
+ * sesión se perdía y una visita de una sola pantalla se quedaba sin ninguna. Con la pantalla
940
+ * en el latido y en el engagement de ocultar la pestaña, el backend la reconstruye.
941
+ *
942
+ * En los cierres (`closeSession`, `suspendSession`) el observador ya emitió el `page_view`
943
+ * y no tiene pantalla, así que ese engagement va sin `screen`: nunca se cuenta dos veces.
944
+ * Tampoco se emite un `page_view` aquí, por lo mismo.
945
+ */
909
946
  private flushEngagement;
910
947
  /** Tick del flush periódico: latido de engagement si toca, y envío de lo acumulado. */
911
948
  private onAnalyticsFlushTick;
@@ -1362,4 +1399,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
1362
1399
  */
1363
1400
  declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
1364
1401
 
1365
- export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
1402
+ export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type SessionStartReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
package/dist/index.d.ts CHANGED
@@ -383,6 +383,23 @@ type EventListener = (event: DeepdotsEvent) => void;
383
383
  * anterior se cierra y se abre otra, como hace GA con su timeout de sesión.
384
384
  */
385
385
  type SessionEndReason = 'page_hide' | 'background' | 'user_change' | 'tracking_disabled' | 'manual' | 'idle_timeout';
386
+ /**
387
+ * Motivo del `deepdots_session_start` (param `reason`): por qué EMPIEZA la sesión. Permite a
388
+ * analytics separar una carga/arranque real de una vuelta desde background ("Started here").
389
+ * Mismos valores que el SDK nativo donde el significado coincide:
390
+ * - `cold_start`: `init()` (carga de la página / arranque de la app RN) sin sesión suspendida
391
+ * que reanudar. Una recarga en menos de 1 min no emite `session_start` sino
392
+ * `deepdots_session_resume`.
393
+ * - `foreground`: `onForeground()` (RN, AppState 'active') tras un cierre (`onBackground()`
394
+ * o `endSession()`). Con la sesión abierta no emite nada.
395
+ * - `tracking_enabled`: `setTrackingEnabled(true)` (consentimiento concedido).
396
+ * - `user_change`: `setUserId()` o un `init()` con otro `userId`, tras cerrar la del anterior.
397
+ * - `idle_timeout`: la pestaña vuelve a verse tras más de 30 min oculta (web): la sesión
398
+ * anterior se cerró (o se descartó) y empieza otra.
399
+ * - `bfcache_restore`: la página vuelve de la bfcache (botón atrás, `pageshow` con
400
+ * `persisted`) fuera de la ventana de reanudación (web).
401
+ */
402
+ type SessionStartReason = 'cold_start' | 'foreground' | 'tracking_enabled' | 'user_change' | 'idle_timeout' | 'bfcache_restore';
386
403
  /** Trigger type used by remote popup definitions */
387
404
  type PopupTriggerType = 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
388
405
  type PopupTriggerConditionStatus = 'SHOWED' | 'PARTIAL' | 'COMPLETED';
@@ -888,8 +905,15 @@ declare class DeepdotsPopups {
888
905
  */
889
906
  private closeSession;
890
907
  /**
891
- * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente:
892
- * se llama en init(), al volver a foreground y al conceder el consentimiento.
908
+ * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente.
909
+ * El `reason` dice por qué empieza (ver `SessionStartReason`):
910
+ * - `cold_start`: init() (carga de la página / arranque de la app RN).
911
+ * - `foreground`: onForeground() tras un cierre (RN).
912
+ * - `tracking_enabled`: setTrackingEnabled(true).
913
+ * - `user_change`: setUserId() o init() con otro userId.
914
+ * - `idle_timeout`: la pestaña vuelve a verse tras más de 30 min oculta.
915
+ * - `bfcache_restore`: vuelta desde la bfcache fuera de la ventana de reanudación.
916
+ * Si hay una sesión suspendida a tiempo emite `deepdots_session_resume` en su lugar, sin reason.
893
917
  */
894
918
  private openSession;
895
919
  /** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
@@ -905,7 +929,20 @@ declare class DeepdotsPopups {
905
929
  final?: boolean;
906
930
  sessionEnd?: boolean;
907
931
  }): void;
908
- /** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
932
+ /**
933
+ * Emite un evento `user_engagement` con el tiempo activo acumulado (#8) y la pantalla en
934
+ * curso: `screen` y `path` (los mismos que llevará su `page_view`) y `screen_seconds` (lo
935
+ * que lleva en ella, medido como el `duration_seconds` del `page_view`).
936
+ *
937
+ * El `page_view` sale al SALIR de la pantalla; si el cierre no llega nunca (pestaña dormida
938
+ * y descartada al volver, pestaña o app matada en segundo plano), la última pantalla de la
939
+ * sesión se perdía y una visita de una sola pantalla se quedaba sin ninguna. Con la pantalla
940
+ * en el latido y en el engagement de ocultar la pestaña, el backend la reconstruye.
941
+ *
942
+ * En los cierres (`closeSession`, `suspendSession`) el observador ya emitió el `page_view`
943
+ * y no tiene pantalla, así que ese engagement va sin `screen`: nunca se cuenta dos veces.
944
+ * Tampoco se emite un `page_view` aquí, por lo mismo.
945
+ */
909
946
  private flushEngagement;
910
947
  /** Tick del flush periódico: latido de engagement si toca, y envío de lo acumulado. */
911
948
  private onAnalyticsFlushTick;
@@ -1362,4 +1399,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
1362
1399
  */
1363
1400
  declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
1364
1401
 
1365
- export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
1402
+ export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type SessionStartReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
package/dist/index.js CHANGED
@@ -7739,6 +7739,23 @@ var NavigationObserver = class {
7739
7739
  if (!this.installed || this.currentScreen != null || typeof window === "undefined") return;
7740
7740
  this.begin(window.location.href);
7741
7741
  }
7742
+ /**
7743
+ * La pantalla en curso, sin cerrarla ni emitir nada; null si no hay (antes de `begin`, tras
7744
+ * `stop`/`discard`). Para que el `user_engagement` lleve la pantalla: si el cierre de la
7745
+ * sesión no llega nunca (pestaña dormida y descartada, app matada), la última pantalla no
7746
+ * tiene `page_view` y solo queda esto.
7747
+ */
7748
+ current() {
7749
+ if (this.currentScreen == null) return null;
7750
+ return {
7751
+ screen: this.currentScreen,
7752
+ path: this.currentPath ?? this.currentScreen,
7753
+ seconds: this.secondsSinceEntry(this.now())
7754
+ };
7755
+ }
7756
+ secondsSinceEntry(at) {
7757
+ return Math.max(0, Math.round((at - this.entryAt) / 1e3));
7758
+ }
7742
7759
  closeCurrent() {
7743
7760
  if (this.currentScreen == null) return;
7744
7761
  const exit = this.now();
@@ -7747,7 +7764,7 @@ var NavigationObserver = class {
7747
7764
  path: this.currentPath ?? this.currentScreen,
7748
7765
  entry: this.entryAt,
7749
7766
  exit,
7750
- durationSeconds: Math.max(0, Math.round((exit - this.entryAt) / 1e3))
7767
+ durationSeconds: this.secondsSinceEntry(exit)
7751
7768
  };
7752
7769
  this.listeners.forEach((l) => {
7753
7770
  try {
@@ -8472,7 +8489,7 @@ var DeepdotsPopups = class {
8472
8489
  this.navObserver.install();
8473
8490
  this.engagement = new EngagementTracker();
8474
8491
  this.setupAnalyticsFlush();
8475
- this.openSession();
8492
+ this.openSession("cold_start");
8476
8493
  if (resumable && this.analyticsFeedbackSessionId === resumable.sessionId) {
8477
8494
  this.notifyFeedbackSession(resumable.sessionId, "open");
8478
8495
  }
@@ -8530,7 +8547,7 @@ var DeepdotsPopups = class {
8530
8547
  setTrackingEnabled(enabled) {
8531
8548
  if (!enabled) this.closeSession("tracking_disabled");
8532
8549
  this.tracking?.setTrackingEnabled(enabled);
8533
- if (enabled) this.openSession();
8550
+ if (enabled) this.openSession("tracking_enabled");
8534
8551
  if (enabled) this.resolveGeo();
8535
8552
  this.log("tracking \xB7 setTrackingEnabled:", enabled, "\xB7 session_id:", this.tracking?.getSessionId() ?? null);
8536
8553
  }
@@ -8647,7 +8664,7 @@ var DeepdotsPopups = class {
8647
8664
  /** App a foreground (RN: AppState 'active'): reanuda el engagement time y abre sesión nueva. */
8648
8665
  onForeground() {
8649
8666
  this.engagement?.resume();
8650
- this.openSession();
8667
+ this.openSession("foreground");
8651
8668
  }
8652
8669
  /**
8653
8670
  * App a background (RN: AppState 'background'): FIN DE SESIÓN. Cierra pantalla actual
@@ -8695,7 +8712,7 @@ var DeepdotsPopups = class {
8695
8712
  this.answeredSurveys.clear();
8696
8713
  clearPopupState(storage);
8697
8714
  this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
8698
- this.openSession();
8715
+ this.openSession("user_change");
8699
8716
  }
8700
8717
  /**
8701
8718
  * Cierra la sesión actual: vuelca todo lo que quedaba abierto y envía el último lote
@@ -8721,17 +8738,24 @@ var DeepdotsPopups = class {
8721
8738
  this.log("tracking \xB7 session_end:", reason);
8722
8739
  }
8723
8740
  /**
8724
- * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente:
8725
- * se llama en init(), al volver a foreground y al conceder el consentimiento.
8741
+ * Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente.
8742
+ * El `reason` dice por qué empieza (ver `SessionStartReason`):
8743
+ * - `cold_start`: init() (carga de la página / arranque de la app RN).
8744
+ * - `foreground`: onForeground() tras un cierre (RN).
8745
+ * - `tracking_enabled`: setTrackingEnabled(true).
8746
+ * - `user_change`: setUserId() o init() con otro userId.
8747
+ * - `idle_timeout`: la pestaña vuelve a verse tras más de 30 min oculta.
8748
+ * - `bfcache_restore`: vuelta desde la bfcache fuera de la ventana de reanudación.
8749
+ * Si hay una sesión suspendida a tiempo emite `deepdots_session_resume` en su lugar, sin reason.
8726
8750
  */
8727
- openSession() {
8751
+ openSession(reason) {
8728
8752
  if (this.sessionOpen) return;
8729
8753
  if (!this.tracking?.isTrackingEnabled()) return;
8730
8754
  const suspendedMs = this.takeSuspendedSession();
8731
8755
  this.sessionOpen = true;
8732
8756
  this.lastEngagementAt = Date.now();
8733
8757
  if (suspendedMs === null) {
8734
- this.track("deepdots_session_start", {});
8758
+ this.track("deepdots_session_start", { reason });
8735
8759
  } else {
8736
8760
  this.track("deepdots_session_resume", { suspended_ms: suspendedMs });
8737
8761
  this.log("tracking \xB7 session resumed after", suspendedMs, "ms:", this.analyticsFeedbackSessionId);
@@ -8761,12 +8785,29 @@ var DeepdotsPopups = class {
8761
8785
  if (!this.tracking?.isTrackingEnabled()) return;
8762
8786
  this.analytics?.flush(this.analyticsIdentity(), options);
8763
8787
  }
8764
- /** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
8788
+ /**
8789
+ * Emite un evento `user_engagement` con el tiempo activo acumulado (#8) y la pantalla en
8790
+ * curso: `screen` y `path` (los mismos que llevará su `page_view`) y `screen_seconds` (lo
8791
+ * que lleva en ella, medido como el `duration_seconds` del `page_view`).
8792
+ *
8793
+ * El `page_view` sale al SALIR de la pantalla; si el cierre no llega nunca (pestaña dormida
8794
+ * y descartada al volver, pestaña o app matada en segundo plano), la última pantalla de la
8795
+ * sesión se perdía y una visita de una sola pantalla se quedaba sin ninguna. Con la pantalla
8796
+ * en el latido y en el engagement de ocultar la pestaña, el backend la reconstruye.
8797
+ *
8798
+ * En los cierres (`closeSession`, `suspendSession`) el observador ya emitió el `page_view`
8799
+ * y no tiene pantalla, así que ese engagement va sin `screen`: nunca se cuenta dos veces.
8800
+ * Tampoco se emite un `page_view` aquí, por lo mismo.
8801
+ */
8765
8802
  flushEngagement() {
8766
8803
  if (!this.tracking?.isTrackingEnabled()) return;
8767
8804
  const ms = this.engagement?.consume() ?? 0;
8768
8805
  if (ms > 0) {
8769
- this.track("deepdots_user_engagement", { engagement_time_msec: ms });
8806
+ const current = this.navObserver?.current();
8807
+ this.track("deepdots_user_engagement", {
8808
+ engagement_time_msec: ms,
8809
+ ...current ? { screen: current.screen, path: current.path, screen_seconds: current.seconds } : {}
8810
+ });
8770
8811
  this.lastEngagementAt = Date.now();
8771
8812
  }
8772
8813
  }
@@ -8798,7 +8839,7 @@ var DeepdotsPopups = class {
8798
8839
  } else {
8799
8840
  this.discardSession();
8800
8841
  }
8801
- this.openSession();
8842
+ this.openSession("idle_timeout");
8802
8843
  }
8803
8844
  /**
8804
8845
  * `pagehide` en web: SUSPENDE la sesión en vez de cerrarla, porque el navegador lo lanza
@@ -8922,7 +8963,7 @@ var DeepdotsPopups = class {
8922
8963
  window.addEventListener("pageshow", (event) => {
8923
8964
  if (!event.persisted) return;
8924
8965
  this.startAnalyticsFlushTimer();
8925
- this.openSession();
8966
+ this.openSession("bfcache_restore");
8926
8967
  });
8927
8968
  document.addEventListener("visibilitychange", () => {
8928
8969
  if (document.visibilityState === "hidden") {