@outlit/browser 0.2.2 → 0.4.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 +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +155 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +151 -9
- package/dist/index.mjs.map +1 -1
- package/dist/outlit.global.js +1 -1
- package/dist/outlit.global.js.map +1 -1
- package/dist/react/index.d.mts +56 -4
- package/dist/react/index.d.ts +56 -4
- package/dist/react/index.js +191 -8
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +193 -9
- package/dist/react/index.mjs.map +1 -1
- package/dist/{tracker-DFcTv3EM.d.mts → tracker-DK-2gYCi.d.mts} +91 -1
- package/dist/{tracker-DFcTv3EM.d.ts → tracker-DK-2gYCi.d.ts} +91 -1
- package/package.json +7 -2
package/dist/react/index.mjs
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
buildFormEvent,
|
|
10
10
|
buildIdentifyEvent,
|
|
11
11
|
buildIngestPayload,
|
|
12
|
-
buildPageviewEvent
|
|
12
|
+
buildPageviewEvent,
|
|
13
|
+
buildStageEvent
|
|
13
14
|
} from "@outlit/core";
|
|
14
15
|
|
|
15
16
|
// src/autocapture.ts
|
|
@@ -229,6 +230,7 @@ var DEFAULT_IDLE_TIMEOUT = 3e4;
|
|
|
229
230
|
var SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
230
231
|
var TIME_UPDATE_INTERVAL = 1e3;
|
|
231
232
|
var MIN_SPURIOUS_THRESHOLD = 50;
|
|
233
|
+
var MIN_PAGE_TIME_FOR_ENGAGEMENT = 500;
|
|
232
234
|
var SESSION_ID_KEY = "outlit_session_id";
|
|
233
235
|
var SESSION_LAST_ACTIVITY_KEY = "outlit_session_last_activity";
|
|
234
236
|
var SessionTracker = class {
|
|
@@ -273,7 +275,8 @@ var SessionTracker = class {
|
|
|
273
275
|
this.updateActiveTime();
|
|
274
276
|
const totalTimeMs = Date.now() - this.state.pageEntryTime;
|
|
275
277
|
const isSpuriousEvent = this.state.activeTimeMs < MIN_SPURIOUS_THRESHOLD && totalTimeMs < MIN_SPURIOUS_THRESHOLD;
|
|
276
|
-
|
|
278
|
+
const isTooSoonAfterNavigation = totalTimeMs < MIN_PAGE_TIME_FOR_ENGAGEMENT;
|
|
279
|
+
if (!isSpuriousEvent && !isTooSoonAfterNavigation) {
|
|
277
280
|
const event = buildEngagementEvent({
|
|
278
281
|
url: this.state.currentUrl,
|
|
279
282
|
referrer: document.referrer,
|
|
@@ -459,6 +462,7 @@ var SessionTracker = class {
|
|
|
459
462
|
this.checkSessionExpiry();
|
|
460
463
|
this.state.lastActiveTime = Date.now();
|
|
461
464
|
this.state.hasEmittedEngagement = false;
|
|
465
|
+
this.updateSessionActivity();
|
|
462
466
|
}
|
|
463
467
|
}
|
|
464
468
|
/**
|
|
@@ -614,6 +618,9 @@ var Outlit = class {
|
|
|
614
618
|
options;
|
|
615
619
|
hasHandledExit = false;
|
|
616
620
|
sessionTracker = null;
|
|
621
|
+
// User identity state for stage events
|
|
622
|
+
currentUser = null;
|
|
623
|
+
pendingUser = null;
|
|
617
624
|
constructor(options) {
|
|
618
625
|
this.publicKey = options.publicKey;
|
|
619
626
|
this.apiHost = options.apiHost ?? DEFAULT_API_HOST;
|
|
@@ -659,9 +666,7 @@ var Outlit = class {
|
|
|
659
666
|
}
|
|
660
667
|
this.visitorId = getOrCreateVisitorId();
|
|
661
668
|
this.startFlushTimer();
|
|
662
|
-
|
|
663
|
-
this.initSessionTracking();
|
|
664
|
-
}
|
|
669
|
+
this.initSessionTracking();
|
|
665
670
|
if (this.options.trackPageviews !== false) {
|
|
666
671
|
this.initPageviewTracking();
|
|
667
672
|
}
|
|
@@ -672,6 +677,10 @@ var Outlit = class {
|
|
|
672
677
|
this.initCalendarTracking();
|
|
673
678
|
}
|
|
674
679
|
this.isTrackingEnabled = true;
|
|
680
|
+
if (this.pendingUser) {
|
|
681
|
+
this.applyUser(this.pendingUser);
|
|
682
|
+
this.pendingUser = null;
|
|
683
|
+
}
|
|
675
684
|
}
|
|
676
685
|
/**
|
|
677
686
|
* Check if tracking is currently enabled.
|
|
@@ -698,12 +707,21 @@ var Outlit = class {
|
|
|
698
707
|
/**
|
|
699
708
|
* Identify the current visitor.
|
|
700
709
|
* Links the anonymous visitor to a known user.
|
|
710
|
+
*
|
|
711
|
+
* When email or userId is provided, also sets the current user identity
|
|
712
|
+
* for stage events (activate, engaged, paid).
|
|
701
713
|
*/
|
|
702
714
|
identify(options) {
|
|
703
715
|
if (!this.isTrackingEnabled) {
|
|
704
716
|
console.warn("[Outlit] Tracking not enabled. Call enableTracking() first.");
|
|
705
717
|
return;
|
|
706
718
|
}
|
|
719
|
+
if (options.email || options.userId) {
|
|
720
|
+
this.currentUser = {
|
|
721
|
+
email: options.email,
|
|
722
|
+
userId: options.userId
|
|
723
|
+
};
|
|
724
|
+
}
|
|
707
725
|
const event = buildIdentifyEvent({
|
|
708
726
|
url: window.location.href,
|
|
709
727
|
referrer: document.referrer,
|
|
@@ -713,6 +731,98 @@ var Outlit = class {
|
|
|
713
731
|
});
|
|
714
732
|
this.enqueue(event);
|
|
715
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* Set the current user identity.
|
|
736
|
+
* This is useful for SPA applications where you know the user's identity
|
|
737
|
+
* after authentication. Calls identify() under the hood.
|
|
738
|
+
*
|
|
739
|
+
* If called before tracking is enabled, the identity is stored as pending
|
|
740
|
+
* and applied automatically when enableTracking() is called.
|
|
741
|
+
*
|
|
742
|
+
* Note: Both setUser() and identify() enable stage events. The difference is
|
|
743
|
+
* setUser() can be called before tracking is enabled (identity is queued),
|
|
744
|
+
* while identify() requires tracking to be enabled first.
|
|
745
|
+
*/
|
|
746
|
+
setUser(identity) {
|
|
747
|
+
if (!identity.email && !identity.userId) {
|
|
748
|
+
console.warn("[Outlit] setUser requires at least email or userId");
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (!this.isTrackingEnabled) {
|
|
752
|
+
this.pendingUser = identity;
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
this.applyUser(identity);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Clear the current user identity.
|
|
759
|
+
* Call this when the user logs out.
|
|
760
|
+
*/
|
|
761
|
+
clearUser() {
|
|
762
|
+
this.currentUser = null;
|
|
763
|
+
this.pendingUser = null;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Apply user identity and send identify event.
|
|
767
|
+
*/
|
|
768
|
+
applyUser(identity) {
|
|
769
|
+
this.currentUser = identity;
|
|
770
|
+
this.identify({ email: identity.email, userId: identity.userId, traits: identity.traits });
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Mark the current user as activated.
|
|
774
|
+
* This is typically called after a user completes onboarding or a key activation milestone.
|
|
775
|
+
* Requires the user to be identified (via setUser or identify with userId).
|
|
776
|
+
*/
|
|
777
|
+
activate(properties) {
|
|
778
|
+
this.sendStageEvent("activated", properties);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Mark the current user as engaged.
|
|
782
|
+
* This is typically called when a user reaches a usage milestone.
|
|
783
|
+
* Can also be computed automatically by the engagement cron.
|
|
784
|
+
*/
|
|
785
|
+
engaged(properties) {
|
|
786
|
+
this.sendStageEvent("engaged", properties);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Mark the current user as paid.
|
|
790
|
+
* This is typically called after a successful payment/subscription.
|
|
791
|
+
* Can also be triggered by Stripe integration.
|
|
792
|
+
*/
|
|
793
|
+
paid(properties) {
|
|
794
|
+
this.sendStageEvent("paid", properties);
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Mark the current user as churned.
|
|
798
|
+
* This is typically called when a subscription is cancelled.
|
|
799
|
+
* Can also be triggered by Stripe integration.
|
|
800
|
+
*/
|
|
801
|
+
churned(properties) {
|
|
802
|
+
this.sendStageEvent("churned", properties);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Internal method to send a stage event.
|
|
806
|
+
*/
|
|
807
|
+
sendStageEvent(stage, properties) {
|
|
808
|
+
if (!this.isTrackingEnabled) {
|
|
809
|
+
console.warn("[Outlit] Tracking not enabled. Call enableTracking() first.");
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
if (!this.currentUser) {
|
|
813
|
+
console.warn(
|
|
814
|
+
`[Outlit] Cannot call ${stage}() without setting user identity. Call setUser() or identify() first.`
|
|
815
|
+
);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
const event = buildStageEvent({
|
|
819
|
+
url: window.location.href,
|
|
820
|
+
referrer: document.referrer,
|
|
821
|
+
stage,
|
|
822
|
+
properties
|
|
823
|
+
});
|
|
824
|
+
this.enqueue(event);
|
|
825
|
+
}
|
|
716
826
|
/**
|
|
717
827
|
* Get the current visitor ID.
|
|
718
828
|
* Returns null if tracking is not enabled.
|
|
@@ -748,8 +858,8 @@ var Outlit = class {
|
|
|
748
858
|
// ============================================
|
|
749
859
|
initSessionTracking() {
|
|
750
860
|
this.sessionTracker = initSessionTracking({
|
|
751
|
-
|
|
752
|
-
|
|
861
|
+
// Only emit engagement events when trackEngagement is enabled (default: true)
|
|
862
|
+
onEngagement: this.options.trackEngagement !== false ? (event) => this.enqueue(event) : () => {
|
|
753
863
|
},
|
|
754
864
|
idleTimeout: this.options.idleTimeout
|
|
755
865
|
});
|
|
@@ -820,7 +930,9 @@ var Outlit = class {
|
|
|
820
930
|
async sendEvents(events) {
|
|
821
931
|
if (events.length === 0) return;
|
|
822
932
|
if (!this.visitorId) return;
|
|
823
|
-
const
|
|
933
|
+
const userIdentity = this.currentUser ?? void 0;
|
|
934
|
+
const sessionId = this.sessionTracker?.getSessionId();
|
|
935
|
+
const payload = buildIngestPayload(this.visitorId, "client", events, userIdentity, sessionId);
|
|
824
936
|
const url = `${this.apiHost}/api/i/v1/${this.publicKey}/events`;
|
|
825
937
|
try {
|
|
826
938
|
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
@@ -860,7 +972,8 @@ function OutlitProvider({
|
|
|
860
972
|
formFieldDenylist,
|
|
861
973
|
flushInterval,
|
|
862
974
|
autoTrack = true,
|
|
863
|
-
autoIdentify = true
|
|
975
|
+
autoIdentify = true,
|
|
976
|
+
user
|
|
864
977
|
}) {
|
|
865
978
|
const outlitRef = useRef(null);
|
|
866
979
|
const initializedRef = useRef(false);
|
|
@@ -892,6 +1005,14 @@ function OutlitProvider({
|
|
|
892
1005
|
autoTrack,
|
|
893
1006
|
autoIdentify
|
|
894
1007
|
]);
|
|
1008
|
+
useEffect(() => {
|
|
1009
|
+
if (!outlitRef.current) return;
|
|
1010
|
+
if (user && (user.email || user.userId)) {
|
|
1011
|
+
outlitRef.current.setUser(user);
|
|
1012
|
+
} else {
|
|
1013
|
+
outlitRef.current.clearUser();
|
|
1014
|
+
}
|
|
1015
|
+
}, [user]);
|
|
895
1016
|
const enableTracking = useCallback(() => {
|
|
896
1017
|
if (outlitRef.current) {
|
|
897
1018
|
outlitRef.current.enableTracking();
|
|
@@ -940,10 +1061,73 @@ function useOutlit() {
|
|
|
940
1061
|
if (!outlit) return null;
|
|
941
1062
|
return outlit.getVisitorId();
|
|
942
1063
|
}, [outlit]);
|
|
1064
|
+
const setUser = useCallback2(
|
|
1065
|
+
(identity) => {
|
|
1066
|
+
if (!outlit) {
|
|
1067
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
outlit.setUser(identity);
|
|
1071
|
+
},
|
|
1072
|
+
[outlit]
|
|
1073
|
+
);
|
|
1074
|
+
const clearUser = useCallback2(() => {
|
|
1075
|
+
if (!outlit) {
|
|
1076
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
outlit.clearUser();
|
|
1080
|
+
}, [outlit]);
|
|
1081
|
+
const activate = useCallback2(
|
|
1082
|
+
(properties) => {
|
|
1083
|
+
if (!outlit) {
|
|
1084
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
outlit.activate(properties);
|
|
1088
|
+
},
|
|
1089
|
+
[outlit]
|
|
1090
|
+
);
|
|
1091
|
+
const engaged = useCallback2(
|
|
1092
|
+
(properties) => {
|
|
1093
|
+
if (!outlit) {
|
|
1094
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
outlit.engaged(properties);
|
|
1098
|
+
},
|
|
1099
|
+
[outlit]
|
|
1100
|
+
);
|
|
1101
|
+
const paid = useCallback2(
|
|
1102
|
+
(properties) => {
|
|
1103
|
+
if (!outlit) {
|
|
1104
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
outlit.paid(properties);
|
|
1108
|
+
},
|
|
1109
|
+
[outlit]
|
|
1110
|
+
);
|
|
1111
|
+
const churned = useCallback2(
|
|
1112
|
+
(properties) => {
|
|
1113
|
+
if (!outlit) {
|
|
1114
|
+
console.warn("[Outlit] Not initialized. Make sure OutlitProvider is mounted.");
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
outlit.churned(properties);
|
|
1118
|
+
},
|
|
1119
|
+
[outlit]
|
|
1120
|
+
);
|
|
943
1121
|
return {
|
|
944
1122
|
track,
|
|
945
1123
|
identify,
|
|
946
1124
|
getVisitorId,
|
|
1125
|
+
setUser,
|
|
1126
|
+
clearUser,
|
|
1127
|
+
activate,
|
|
1128
|
+
engaged,
|
|
1129
|
+
paid,
|
|
1130
|
+
churned,
|
|
947
1131
|
isInitialized,
|
|
948
1132
|
isTrackingEnabled,
|
|
949
1133
|
enableTracking
|