@@ -12,6 +12,7 @@ import {
1212 setConnectorUserId ,
1313 isNewSession ,
1414 isPageViewTrackingEnabled ,
15+ WebAttribution ,
1516} from '@amplitude/analytics-client-common' ;
1617import {
1718 BrowserClient ,
@@ -23,11 +24,11 @@ import {
2324 Revenue as IRevenue ,
2425 TransportType ,
2526 OfflineDisabled ,
27+ Result ,
2628} from '@amplitude/analytics-types' ;
2729import { convertProxyObjectToRealObject , isInstanceProxy } from './utils/snippet-helper' ;
2830import { Context } from './plugins/context' ;
2931import { useBrowserConfig , createTransport } from './config' ;
30- import { webAttributionPlugin } from '@amplitude/plugin-web-attribution-browser' ;
3132import { pageViewTrackingPlugin } from '@amplitude/plugin-page-view-tracking-browser' ;
3233import { formInteractionTracking } from './plugins/form-interaction-tracking' ;
3334import { fileDownloadTracking } from './plugins/file-download-tracking' ;
@@ -41,6 +42,7 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
4142 config : BrowserConfig ;
4243 previousSessionDeviceId : string | undefined ;
4344 previousSessionUserId : string | undefined ;
45+ webAttribution : WebAttribution | undefined ;
4446
4547 init ( apiKey = '' , userIdOrOptions ?: string | BrowserOptions , maybeOptions ?: BrowserOptions ) {
4648 let userId : string | undefined ;
@@ -71,6 +73,14 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
7173 const browserOptions = await useBrowserConfig ( options . apiKey , options , this ) ;
7274 this . config = browserOptions ;
7375
76+ // Add web attribution plugin
77+ if ( isAttributionTrackingEnabled ( this . config . defaultTracking ) ) {
78+ const attributionTrackingOptions = getAttributionTrackingConfig ( this . config ) ;
79+ this . webAttribution = new WebAttribution ( attributionTrackingOptions , this . config ) ;
80+ // Fetch the current campaign, check if need to track web attribution later
81+ await this . webAttribution . init ( ) ;
82+ }
83+
7484 // Step 3: Set session ID
7585 // Priority 1: `options.sessionId`
7686 // Priority 2: last known sessionId from user identity storage
@@ -109,13 +119,6 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
109119 await this . add ( formInteractionTracking ( ) ) . promise ;
110120 }
111121
112- // Add web attribution plugin
113- if ( isAttributionTrackingEnabled ( this . config . defaultTracking ) ) {
114- const attributionTrackingOptions = getAttributionTrackingConfig ( this . config ) ;
115- const webAttribution = webAttributionPlugin ( attributionTrackingOptions ) ;
116- await this . add ( webAttribution ) . promise ;
117- }
118-
119122 // Add page view plugin
120123 if ( isPageViewTrackingEnabled ( this . config . defaultTracking ) ) {
121124 await this . add ( pageViewTrackingPlugin ( getPageViewTrackingConfig ( this . config ) ) ) . promise ;
@@ -170,14 +173,14 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
170173 }
171174
172175 setSessionId ( sessionId : number ) {
176+ const promises : Promise < Result > [ ] = [ ] ;
173177 if ( ! this . config ) {
174178 this . q . push ( this . setSessionId . bind ( this , sessionId ) ) ;
175- return ;
179+ return returnWrapper ( Promise . resolve ( ) ) ;
176180 }
177-
178181 // Prevents starting a new session with the same session ID
179182 if ( sessionId === this . config . sessionId ) {
180- return ;
183+ return returnWrapper ( Promise . resolve ( ) ) ;
181184 }
182185
183186 const previousSessionId = this . getSessionId ( ) ;
@@ -190,25 +193,37 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
190193
191194 if ( isSessionTrackingEnabled ( this . config . defaultTracking ) ) {
192195 if ( previousSessionId && lastEventTime ) {
193- this . track ( DEFAULT_SESSION_END_EVENT , undefined , {
194- device_id : this . previousSessionDeviceId ,
195- event_id : ++ lastEventId ,
196- session_id : previousSessionId ,
197- time : lastEventTime + 1 ,
198- user_id : this . previousSessionUserId ,
199- } ) ;
196+ promises . push (
197+ this . track ( DEFAULT_SESSION_END_EVENT , undefined , {
198+ device_id : this . previousSessionDeviceId ,
199+ event_id : ++ lastEventId ,
200+ session_id : previousSessionId ,
201+ time : lastEventTime + 1 ,
202+ user_id : this . previousSessionUserId ,
203+ } ) . promise ,
204+ ) ;
200205 }
201-
202206 this . config . lastEventTime = this . config . sessionId ;
203- this . track ( DEFAULT_SESSION_START_EVENT , undefined , {
204- event_id : ++ lastEventId ,
205- session_id : this . config . sessionId ,
206- time : this . config . lastEventTime ,
207- } ) ;
207+ }
208+
209+ // Fire web attribution event when enable webAttribution tracking
210+ // 1. has new campaign (call setSessionId from init function)
211+ // 2. or shouldTrackNewCampaign (call setSessionId from async process(event) when there has new campaign and resetSessionOnNewCampaign = true )
212+ const isCampaignEventTracked = this . trackCampaignEventIfNeeded ( ++ lastEventId , promises ) ;
213+
214+ if ( isSessionTrackingEnabled ( this . config . defaultTracking ) ) {
215+ promises . push (
216+ this . track ( DEFAULT_SESSION_START_EVENT , undefined , {
217+ event_id : isCampaignEventTracked ? ++ lastEventId : lastEventId ,
218+ session_id : this . config . sessionId ,
219+ time : this . config . lastEventTime ,
220+ } ) . promise ,
221+ ) ;
208222 }
209223
210224 this . previousSessionDeviceId = this . config . deviceId ;
211225 this . previousSessionUserId = this . config . userId ;
226+ return returnWrapper ( Promise . all ( promises ) ) ;
212227 }
213228
214229 extendSession ( ) {
@@ -260,17 +275,40 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient {
260275 return super . revenue ( revenue , eventOptions ) ;
261276 }
262277
278+ private trackCampaignEventIfNeeded ( lastEventId ?: number , promises ?: Promise < Result > [ ] ) {
279+ if ( ! this . webAttribution || ! this . webAttribution . shouldTrackNewCampaign ) {
280+ return false ;
281+ }
282+ const campaignEvent = this . webAttribution . generateCampaignEvent ( lastEventId ) ;
283+ if ( promises ) {
284+ promises . push ( this . track ( campaignEvent ) . promise ) ;
285+ } else {
286+ this . track ( campaignEvent ) ;
287+ }
288+ this . config . loggerProvider . log ( 'Tracking attribution.' ) ;
289+ return true ;
290+ }
291+
263292 async process ( event : Event ) {
264293 const currentTime = Date . now ( ) ;
265294 const isEventInNewSession = isNewSession ( this . config . sessionTimeout , this . config . lastEventTime ) ;
295+ const shouldSetSessionIdOnNewCampaign =
296+ this . webAttribution && this . webAttribution . shouldSetSessionIdOnNewCampaign ( ) ;
266297
267298 if (
268299 event . event_type !== DEFAULT_SESSION_START_EVENT &&
269300 event . event_type !== DEFAULT_SESSION_END_EVENT &&
270- ( ! event . session_id || event . session_id === this . getSessionId ( ) ) &&
271- isEventInNewSession
301+ ( ! event . session_id || event . session_id === this . getSessionId ( ) )
272302 ) {
273- this . setSessionId ( currentTime ) ;
303+ if ( isEventInNewSession || shouldSetSessionIdOnNewCampaign ) {
304+ this . setSessionId ( currentTime ) ;
305+ if ( shouldSetSessionIdOnNewCampaign ) {
306+ this . config . loggerProvider . log ( 'Created a new session for new campaign.' ) ;
307+ }
308+ } else if ( ! isEventInNewSession ) {
309+ // web attribution should be track during the middle of the session if there has any new campaign
310+ this . trackCampaignEventIfNeeded ( ) ;
311+ }
274312 }
275313
276314 return super . process ( event ) ;
0 commit comments