diff --git a/src/index.ts b/src/index.ts index 7d15786..123d26c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,11 @@ -import { ComponentSettings, Manager, MCEvent } from '@managed-components/types' +import { + Client, + ComponentSettings, + Manager, + MCEvent, +} from '@managed-components/types' import { getFinalURL } from './requestBuilder' +import { countConversion, countPageview } from './utils' const SESSION_DURATION_IN_MIN = 30 @@ -137,6 +143,8 @@ export default async function (manager: Manager, settings: ComponentSettings) { manager.createEventListener('visibilityChange', onVisibilityChange(settings)) 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) @@ -149,7 +157,10 @@ export default async function (manager: Manager, settings: ComponentSettings) { manager.addEventListener('pageview', event => { event.client.attachEvent('visibilityChange') + // 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) @@ -159,6 +170,8 @@ export default async function (manager: Manager, settings: ComponentSettings) { }) manager.addEventListener('ecommerce', async event => { + // count conversion events for 'seg' value + countConversion(event) // order matters so engagement duration is set before dispatching the hit computeEngagementDuration(event) diff --git a/src/requestBuilder.ts b/src/requestBuilder.ts index 1e3c969..2994beb 100644 --- a/src/requestBuilder.ts +++ b/src/requestBuilder.ts @@ -61,14 +61,30 @@ function getToolRequest( if (!Number.isInteger(sessionCounter)) { sessionCounter = 0 } + if (typeof client !== 'undefined' && client) { + // Determine if the session is engaged to set the 'seg' value + const pageviewCounter = parseInt(client.get('pageviewCounter') || '0') + const conversionCounter = parseInt(client.get('conversionCounter') || '0') + let engagementDuration = parseInt(client.get('engagementDuration') || '0') + + // Session will be marked engaged if longer than 10 seconds, has at least 1 conversion event, and 2 or more pageviews + if ( + engagementDuration > 10 && + conversionCounter > 0 && + pageviewCounter > 1 + ) { + requestBody['seg'] = 1 // Session engaged + } else { + requestBody['seg'] = 0 + } + } else { + console.error('Client object is undefined or not initialized') + } // Create, refresh or renew session id const sessionLength = 30 * 60 * 1000 // By default, GA4 keeps sessions for 30 minutes let currentSessionID = client.get('ga4sid') - if (currentSessionID) { - requestBody['seg'] = 1 // Session engaged - } else { - requestBody['seg'] = 0 + if (!currentSessionID) { requestBody['_ss'] = 1 // Session start sessionCounter++ currentSessionID = getRandomInt().toString() @@ -92,7 +108,8 @@ function getToolRequest( requestBody['cid'] = cid //const notTheFirstSession = parseInt(requestBody['_s'] as string) > 1 - const engagementDuration = parseInt(String(client.get('engagementDuration')), 10) || 0; + const engagementDuration = + parseInt(String(client.get('engagementDuration')), 10) || 0 if (engagementDuration) { requestBody._et = engagementDuration } diff --git a/src/utils.ts b/src/utils.ts index 716e535..8712645 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,5 @@ +import { Client, MCEvent } from "@managed-components/types" + export const flattenKeys = (obj: { [k: string]: unknown } = {}, prefix = '') => Object.keys(obj).reduce((acc: { [k: string]: unknown }, k) => { const pre = prefix.length ? `${prefix}.` : '' @@ -43,3 +45,28 @@ export const getParamSafely = ( } return {} } +// pageviews in session counter +export const countPageview = (client: Client) => { + let pageviewCounter = parseInt(client.get('pageviewCounter') || '0') || 0 + + if (pageviewCounter === 0) { + client.set('pageviewCounter', '1', { scope: 'session' }) + } else { + pageviewCounter++ + client.set('pageviewCounter', `${pageviewCounter}`, { scope: 'session' }) + } +} + +// conversion events in session counter +export const countConversion = (event: MCEvent) => { + const {client} = event + let conversionCounter = parseInt(client.get('conversionCounter') || '0') || 0 + if (conversionCounter === 0 && event.payload.conversion) { + client.set('conversionCounter', '1', { scope: 'session' }) + } else { + conversionCounter++ + client.set('conversionCounter', `${conversionCounter}`, { + scope: 'session', + }) + } +} \ No newline at end of file