Skip to content

Commit

Permalink
ZRZ-1318 engagement time changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ad-astra-via committed Jun 14, 2024
1 parent 09aadb3 commit 01d6ea7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 44 deletions.
60 changes: 25 additions & 35 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import {
computeEngagementDuration,
countConversion,
countPageview,
sendUserEngagementEvent,
} from './utils'

export const SESSION_DURATION_IN_MIN = 30

const sendGaAudiences = (
event: MCEvent,
settings: ComponentSettings,
Expand Down Expand Up @@ -70,45 +69,36 @@ const sendGaAudiences = (
client.fetch(finalDoubleClickURL)
}
}
const sendEvent = async (
export const sendEvent = async (
eventType: string,
event: MCEvent,
settings: ComponentSettings,
manager: Manager
) => {
const { client } = event
const { finalURL, requestBody } = getFinalURL(eventType, event, settings)

console.log(
'🚀🚀🚀🚀🚀🚀🚀🚀 final URL is here and send event fires',
finalURL
)
console.log('🚀🚀🚀🚀🚀🚀🚀🚀 also manager.fetch is working: ', manager.fetch)
manager.fetch(finalURL, {
headers: { 'User-Agent': client.userAgent },
})

if (settings['ga-audiences'] || event.payload['ga-audiences']) {
sendGaAudiences(event, settings, requestBody)
}

client.set('let', Date.now().toString()) // reset the last event time
}

const onVisibilityChange =
(settings: ComponentSettings, manager: Manager) => (event: MCEvent) => {
const { client, payload } = event

if (payload.visibilityChange[0].state == 'visible') {
event.client.set('engagementStart', payload.visibilityChange[0].timestamp)
client.set('engagementStart', payload.visibilityChange[0].timestamp)
} else if (payload.visibilityChange[0].state == 'hidden') {
// on pageblur
computeEngagementDuration(event)

const msSinceLastEvent = Date.now() - parseInt(client.get('let') || '0') // _let = "_lastEventTime"
if (msSinceLastEvent > 10000) {
// order matters so engagement duration is set before dispatching the hit
computeEngagementDuration(event)

sendEvent('user_engagement', event, settings, manager)

// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
}
// when visibilityChange status changes to hidden, fire `user_engagement` event
sendUserEngagementEvent(event, settings, manager)
}
}

Expand All @@ -119,42 +109,42 @@ export default async function (manager: Manager, settings: ComponentSettings) {
)

manager.addEventListener('pageview', event => {
// this line does not trigger visibilityChange after a pagview, it will start triggering events only on the fist change to hidden
event.client.attachEvent('visibilityChange')

// if engagement duration is >1 send a user_engagement event before pageview, to count the time on previous page properly
const engagementDuration =
parseInt(String(event.client.get('engagementDuration')), 10) || 0
if (engagementDuration >= 1) {
sendUserEngagementEvent(event, settings, manager)
}
// engagement start gets reset on every new pageview or event
const now = new Date(Date.now()).getTime()
event.client.set('engagementStart', `${now}`)
// Reset engagementDuration after pageview has been dispatched so it restarts the count
event.client.set('engagementDuration', '0')
// count pageviews for 'seg' value
countPageview(event.client)
// order matters so engagement duration is set before dispatching the hit

computeEngagementDuration(event)

sendEvent('page_view', event, settings, manager)

// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
})

manager.addEventListener('event', event => {
// count conversion events for 'seg' value
countConversion(event)
// order matters so engagement duration is set before dispatching the hit
computeEngagementDuration(event)
computeEngagementDuration(event, settings)

sendEvent('event', event, settings, manager)

// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
})

manager.addEventListener('ecommerce', async event => {
event.payload.conversion = true // set ecommerce events as conversion events
// count conversion events for 'seg' value
countConversion(event)
// order matters so engagement duration is set before dispatching the hit
computeEngagementDuration(event)
computeEngagementDuration(event, settings)

sendEvent('ecommerce', event, settings, manager)

// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
})
}
35 changes: 33 additions & 2 deletions src/requestBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentSettings, MCEvent } from '@managed-components/types'
import { Client, ComponentSettings, MCEvent } from '@managed-components/types'
import {
buildProductRequest,
EVENTS,
Expand All @@ -9,6 +9,16 @@ import { flattenKeys, getParamSafely } from './utils'

const getRandomInt = () => Math.floor(2147483647 * Math.random())

const firstPageEvent = (client: Client) => {
const countedEvent = client.get('countedEvent')
if (countedEvent) {
console.log('🥑🥑🥑🥑🥑🥑🥑 this is not the first event!')
return false
} else {
console.log('🥑🥑🥑🥑🥑🥑🥑 this is the FIRST event!')
return true
}
}
function getToolRequest(
eventType: string,
event: MCEvent,
Expand Down Expand Up @@ -108,8 +118,29 @@ function getToolRequest(
//const notTheFirstSession = parseInt(requestBody['_s'] as string) > 1
const engagementDuration =
parseInt(String(client.get('engagementDuration')), 10) || 0
if (engagementDuration) {

// include _et parameter for engagement time metrics
if (
(eventType === 'event' || eventType === 'ecommerce') &&
firstPageEvent(client)
) {
requestBody._et = engagementDuration
console.log(
'💡💡💡💡💡💡💡💡 event/ecommerce includes _et: ',
requestBody._et
)
// mark first event to avoid sending _et with upcoming events on that page
event.client.set('countedEvent', '1', { scope: 'page' })
// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
} else if (eventType === 'user_engagement') {
requestBody._et = engagementDuration
// Reset engagementDuration after event has been dispatched so it does not accumulate
event.client.set('engagementDuration', '0')
console.log(
'🐝🐝🐝🐝🐝🐝🐝 user_engagement includes _et: ',
requestBody._et
)
}

/* Start of gclid treating */
Expand Down
30 changes: 23 additions & 7 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Client, MCEvent } from '@managed-components/types'
import { SESSION_DURATION_IN_MIN } from '.'
import {
Client,
ComponentSettings,
MCEvent,
Manager,
} from '@managed-components/types'
import { sendEvent } from '.'
import { Settings } from 'http2'

export const flattenKeys = (obj: { [k: string]: unknown } = {}, prefix = '') =>
Object.keys(obj).reduce((acc: { [k: string]: unknown }, k) => {
Expand Down Expand Up @@ -72,7 +78,12 @@ export const countConversion = (event: MCEvent) => {
}
}

export const computeEngagementDuration = (event: MCEvent) => {
export const computeEngagementDuration = (
event: MCEvent,
settings: ComponentSettings
) => {
const SESSION_DURATION_IN_MIN = settings.sessionLength || 30 // inactivity time gap between sessions (in min)

const now = new Date(Date.now()).getTime()

let engagementDuration =
Expand All @@ -87,10 +98,15 @@ export const computeEngagementDuration = (event: MCEvent) => {
}

engagementDuration += now - engagementStart

event.client.set('engagementDuration', `${engagementDuration}`)

// engagement start gets reset on every new pageview or event
event.client.set('engagementStart', `${now}`)
}

export const sendUserEngagementEvent = (
event: MCEvent,
settings: Settings,
manager: Manager
) => {
computeEngagementDuration(event, settings)

sendEvent('user_engagement', event, settings, manager)
}

0 comments on commit 01d6ea7

Please sign in to comment.