From 1b25d28b45ba943413bb366baf83da0366f4a578 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Singh Date: Thu, 16 Jan 2025 18:03:52 +0530 Subject: [PATCH 1/4] feat: introduce navigation and traffic acquisition data in form audit --- .../src/functions/form-vitals.js | 34 ++- .../fixtures/bundles-for-form-vitals.json | 6 + .../fixtures/expected-form-vitals-result.json | 230 +++++++++++++----- 3 files changed, 210 insertions(+), 60 deletions(-) diff --git a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js index f2738f9d..46a7af81 100644 --- a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js +++ b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js @@ -11,6 +11,7 @@ */ import { DataChunks } from '@adobe/rum-distiller'; +import trafficAcquisition from './traffic-acquisition.js'; import { generateKey, DELIMITER, loadBundles } from '../utils.js'; const FORM_SOURCE = ['.form', '.marketo', '.marketo-form']; @@ -24,6 +25,7 @@ function initializeResult(url) { formengagement: {}, formbuttonclick: {}, pageview: {}, + forminternalnavigation: [], }; } @@ -48,6 +50,23 @@ const metricFns = { }, }; +function populateFormsInternalNavigation(bundles, formVitals) { + const dataChunks = new DataChunks(); + loadBundles(bundles, dataChunks); + dataChunks.filter = { checkpoint: ['navigate'] }; + dataChunks.filtered.forEach((bundle) => { + const forminternalnavigation = bundle.events.find((e) => e.checkpoint === 'navigate'); + if (forminternalnavigation + && !formVitals[bundle.url].forminternalnavigation + .some((e) => e.url === forminternalnavigation.source)) { + formVitals[bundle.url].forminternalnavigation.push({ + url: forminternalnavigation.source, + pageview: formVitals[forminternalnavigation.source]?.pageview || null, + }); + } + }); +} + function containsFormVitals(row) { return METRICS.some((metric) => Object.keys(row[metric]).length > 0); } @@ -62,12 +81,19 @@ function handler(bundles) { // counts metrics per each group METRICS.forEach((metric) => dataChunks.addSeries(metric, metricFns[metric])); + // traffic acquisition data per url + const trafficByUrl = trafficAcquisition.handler(bundles); + const trafficByUrlMap = Object.fromEntries( + trafficByUrl.map(({ url, ...item }) => [url, item]), + ); + // aggregates metrics per group (url and user agent) const formVitals = dataChunks.facets.urlUserAgents.reduce((acc, { value, metrics, weight }) => { const [url, userAgent] = value.split(DELIMITER); acc[url] = acc[url] || initializeResult(url); acc[url].pageview[userAgent] = weight; + acc[url].trafficacquisition = trafficByUrlMap[url]; METRICS.filter((metric) => metrics[metric].sum) // filter out user-agents with no form vitals .forEach((metric) => { @@ -77,11 +103,13 @@ function handler(bundles) { return acc; }, {}); - return Object.values(formVitals) - .filter(containsFormVitals); // filter out pages with no form vitals + // populate internal navigation data + populateFormsInternalNavigation(bundles, formVitals); + // filter out pages with no form vitals + return Object.values(formVitals).filter(containsFormVitals); } export default { handler, - checkpoints: ['viewblock', 'formsubmit', 'click'], + checkpoints: ['viewblock', 'formsubmit', 'click', 'navigate'], }; diff --git a/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json b/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json index b605dca8..df3c93aa 100644 --- a/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json +++ b/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json @@ -61384,6 +61384,12 @@ "userAgent": "desktop:windows", "weight": 100, "events": [ + { + "checkpoint": "navigate", + "target": "visible", + "source": "https://business.adobe.com/products/marketo.html", + "timeDelta": 5750 + }, { "checkpoint": "click", "target": "https://pps.services.adobe.com/api/profile/image/default/bb99dbb8-eab4-438d-ab41-f2f9f1b8ead3/138", diff --git a/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json b/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json index ba5ab1c0..1c0ce1b9 100644 --- a/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json +++ b/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json @@ -1,43 +1,68 @@ [ { "url": "https://business.adobe.com/jp/products/magento/magento-commerce.html", - "formsubmit": { - - }, + "formsubmit": {}, "formview": { "desktop:mac": 100 }, - "formengagement": { - - }, - "formbuttonclick": { - - }, + "formengagement": {}, + "formbuttonclick": {}, "pageview": { "desktop:linux": 2200, "desktop:mac": 100, "desktop:windows": 100 + }, + "forminternalnavigation": [ + { + "url": "https://business.adobe.com/products/marketo.html", + "pageview": { + "desktop:linux": 1900, + "desktop:mac": 1300, + "desktop:windows": 1200, + "mobile:android": 300, + "mobile:ios": 200 + } + } + ], + "trafficacquisition": { + "total": 2400, + "earned": 0, + "owned": 2400, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 2400 + } + ] } }, { "url": "https://business.adobe.com/", - "formsubmit": { - - }, - "formview": { - - }, + "formsubmit": {}, + "formview": {}, "formengagement": { "desktop:windows": 100 }, - "formbuttonclick": { - - }, + "formbuttonclick": {}, "pageview": { "desktop:windows": 1900, "desktop:mac": 800, "mobile:android": 300, "mobile:ios": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 3100, + "earned": 0, + "owned": 3100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 3100 + } + ] } }, { @@ -45,9 +70,7 @@ "formsubmit": { "desktop:mac": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:mac": 100 }, @@ -57,6 +80,19 @@ "pageview": { "desktop:linux": 1600, "desktop:mac": 200 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 1800, + "earned": 0, + "owned": 1800, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 1800 + } + ] } }, { @@ -64,9 +100,7 @@ "formsubmit": { "desktop:windows": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:windows": 100 }, @@ -77,6 +111,19 @@ "desktop:windows": 400, "mobile:android": 200, "mobile:ios": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 700, + "earned": 0, + "owned": 700, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 700 + } + ] } }, { @@ -84,9 +131,7 @@ "formsubmit": { "desktop:windows": 200 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:windows": 200 }, @@ -95,42 +140,69 @@ }, "pageview": { "desktop:windows": 200 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 200, + "earned": 0, + "owned": 200, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 200 + } + ] } }, { "url": "https://business.adobe.com/se/resources/main.html", - "formsubmit": { - - }, - "formview": { - - }, + "formsubmit": {}, + "formview": {}, "formengagement": { "desktop:windows": 100 }, - "formbuttonclick": { - - }, + "formbuttonclick": {}, "pageview": { "desktop:windows": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } }, { "url": "https://business.adobe.com/uk/products/magento/magento-commerce/sem.html", - "formsubmit": { - - }, - "formview": { - - }, + "formsubmit": {}, + "formview": {}, "formengagement": { "desktop:windows": 100 }, - "formbuttonclick": { - - }, + "formbuttonclick": {}, "pageview": { "desktop:windows": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } }, { @@ -138,9 +210,7 @@ "formsubmit": { "desktop:windows": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:windows": 100 }, @@ -149,6 +219,19 @@ }, "pageview": { "desktop:windows": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } }, { @@ -156,9 +239,7 @@ "formsubmit": { "desktop:mac": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:mac": 100 }, @@ -167,6 +248,19 @@ }, "pageview": { "desktop:mac": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } }, { @@ -174,9 +268,7 @@ "formsubmit": { "desktop:windows": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:windows": 100 }, @@ -185,6 +277,19 @@ }, "pageview": { "desktop:windows": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } }, { @@ -192,9 +297,7 @@ "formsubmit": { "desktop:mac": 100 }, - "formview": { - - }, + "formview": {}, "formengagement": { "desktop:mac": 100 }, @@ -203,6 +306,19 @@ }, "pageview": { "desktop:mac": 100 + }, + "forminternalnavigation": [], + "trafficacquisition": { + "total": 100, + "earned": 0, + "owned": 100, + "paid": 0, + "sources": [ + { + "type": "owned:direct", + "views": 100 + } + ] } } ] \ No newline at end of file From a788940a51b7baea138d726048c35a6eda87a215 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Singh Date: Sat, 25 Jan 2025 13:04:43 +0530 Subject: [PATCH 2/4] feat: introduce navigation and traffic acquisition data in form audit --- .../src/functions/form-vitals.js | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js index 46a7af81..aef77f01 100644 --- a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js +++ b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js @@ -56,7 +56,7 @@ function populateFormsInternalNavigation(bundles, formVitals) { dataChunks.filter = { checkpoint: ['navigate'] }; dataChunks.filtered.forEach((bundle) => { const forminternalnavigation = bundle.events.find((e) => e.checkpoint === 'navigate'); - if (forminternalnavigation + if (forminternalnavigation && formVitals[bundle.url] && !formVitals[bundle.url].forminternalnavigation .some((e) => e.url === forminternalnavigation.source)) { formVitals[bundle.url].forminternalnavigation.push({ @@ -67,6 +67,50 @@ function populateFormsInternalNavigation(bundles, formVitals) { }); } +function findFormCTAForInternalNavigation(bundles, formVitals) { + formVitals.forEach((item) => { + const { url, forminternalnavigation } = item; + if (forminternalnavigation && Array.isArray(forminternalnavigation)) { + forminternalnavigation.forEach((nav) => { + if (nav.url) { + let totalClickOnPage = 0; + const CTAs = new Map(); + const clickCheckpointBundles = bundles.filter((bundle) => bundle.url === nav.url && bundle.events.find((e) => e.checkpoint === 'click')); + clickCheckpointBundles.forEach((bundle) => { + totalClickOnPage += bundle.weight; + const clickCheckpoint = bundle.events.find((e) => e.checkpoint === 'click' && e.target === url); + + if (clickCheckpoint) { + const { source } = clickCheckpoint; + // Retrieves the existing CTA object if it exists; otherwise, + // initializes a new one with default values. + const existingCTA = CTAs.get(source) || { source, clicks: 0 }; + existingCTA.clicks += bundle.weight; + CTAs.set(source, existingCTA); + } + // if (clickCheckpoint) { + // const { source } = clickCheckpoint; + // if (CTAs.has(source)) { + // let { clicks } = CTAs.get(source); + // clicks += bundle.weight; + // CTAs.set(source, { source, clicks }); + // } else { + // CTAs.set(source, { source, clicks: bundle.weight }); + // } + // } + }); + + // Convert CTAs Map to an array and store it in the nav object + // eslint-disable-next-line no-param-reassign + nav.CTAs = Array.from(CTAs.values()); + // eslint-disable-next-line no-param-reassign + nav.totalClicksOnPage = totalClickOnPage; + } + }); + } + }); +} + function containsFormVitals(row) { return METRICS.some((metric) => Object.keys(row[metric]).length > 0); } @@ -106,7 +150,9 @@ function handler(bundles) { // populate internal navigation data populateFormsInternalNavigation(bundles, formVitals); // filter out pages with no form vitals - return Object.values(formVitals).filter(containsFormVitals); + const filteredFormVitals = Object.values(formVitals).filter(containsFormVitals); + findFormCTAForInternalNavigation(bundles, filteredFormVitals); + return filteredFormVitals; } export default { From c0a70b9e33b003cd8d361a7b6b563bfc5e1d62ee Mon Sep 17 00:00:00 2001 From: Rahul Kumar Singh Date: Sat, 25 Jan 2025 13:07:46 +0530 Subject: [PATCH 3/4] feat: introduce navigation and traffic acquisition data in form audit --- .../src/functions/form-vitals.js | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js index aef77f01..507257d9 100644 --- a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js +++ b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js @@ -88,24 +88,16 @@ function findFormCTAForInternalNavigation(bundles, formVitals) { existingCTA.clicks += bundle.weight; CTAs.set(source, existingCTA); } - // if (clickCheckpoint) { - // const { source } = clickCheckpoint; - // if (CTAs.has(source)) { - // let { clicks } = CTAs.get(source); - // clicks += bundle.weight; - // CTAs.set(source, { source, clicks }); - // } else { - // CTAs.set(source, { source, clicks: bundle.weight }); - // } - // } }); // Convert CTAs Map to an array and store it in the nav object - // eslint-disable-next-line no-param-reassign - nav.CTAs = Array.from(CTAs.values()); - // eslint-disable-next-line no-param-reassign - nav.totalClicksOnPage = totalClickOnPage; + return { + ...nav, + CTAs: Array.from(CTAs.values()), + totalClickOnPage, + }; } + return nav; }); } }); From 2e2b44e07b648711a66baf392a9376438ec30010 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Singh Date: Sat, 25 Jan 2025 15:43:37 +0530 Subject: [PATCH 4/4] feat: introduce navigation and traffic acquisition data in form audit --- .../src/functions/form-vitals.js | 10 ++++---- .../fixtures/bundles-for-form-vitals.json | 24 +++++++++++++++++++ .../fixtures/expected-form-vitals-result.json | 11 +++++++-- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js index 507257d9..b63b0408 100644 --- a/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js +++ b/packages/spacecat-shared-rum-api-client/src/functions/form-vitals.js @@ -91,13 +91,11 @@ function findFormCTAForInternalNavigation(bundles, formVitals) { }); // Convert CTAs Map to an array and store it in the nav object - return { - ...nav, - CTAs: Array.from(CTAs.values()), - totalClickOnPage, - }; + // eslint-disable-next-line no-param-reassign + nav.CTAs = Array.from(CTAs.values()); + // eslint-disable-next-line no-param-reassign + nav.totalClicksOnPage = totalClickOnPage; } - return nav; }); } }); diff --git a/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json b/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json index df3c93aa..2f396b35 100644 --- a/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json +++ b/packages/spacecat-shared-rum-api-client/test/fixtures/bundles-for-form-vitals.json @@ -61375,6 +61375,30 @@ } ] }, + { + "id": "fx4g", + "host": "rum.hlx.page", + "time": "2024-10-29T08:00:00.865Z", + "timeSlot": "2024-10-29T08:00:00.000Z", + "url": "https://business.adobe.com/products/marketo.html", + "userAgent": "desktop:linux", + "weight": 100, + "events": [ + { + "checkpoint": "click", + "source": "#tab-features-2", + "target": "https://business.adobe.com/jp/products/magento/magento-commerce.html" + }, + { + "checkpoint": "viewblock", + "timeDelta": 883 + }, + { + "checkpoint": "viewblock", + "timeDelta": 882 + } + ] + }, { "id": "g3jr", "host": "rum.hlx.page", diff --git a/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json b/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json index 1c0ce1b9..b1888a77 100644 --- a/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json +++ b/packages/spacecat-shared-rum-api-client/test/fixtures/expected-form-vitals-result.json @@ -16,12 +16,19 @@ { "url": "https://business.adobe.com/products/marketo.html", "pageview": { - "desktop:linux": 1900, + "desktop:linux": 2000, "desktop:mac": 1300, "desktop:windows": 1200, "mobile:android": 300, "mobile:ios": 200 - } + }, + "CTAs": [ + { + "source": "#tab-features-2", + "clicks": 100 + } + ], + "totalClicksOnPage": 800 } ], "trafficacquisition": {