From 69eafe8335cd4cd56c3dd4ff710b3d749e4b8f8d Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Wed, 25 Feb 2026 13:52:57 +0100 Subject: [PATCH] fix(experiments): explicitly use ad revenue (salesAds) for true ACOS and ROAS calculations instead of total sales revenue --- services/experimentAnalysis.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/services/experimentAnalysis.ts b/services/experimentAnalysis.ts index 2c4f071..cf51c5a 100644 --- a/services/experimentAnalysis.ts +++ b/services/experimentAnalysis.ts @@ -30,6 +30,7 @@ interface WeeklyMetrics { timestamp: number; units: number; revenue: number; + adRevenue: number; sessions: number; // glanceViews cost: number; clicks: number; @@ -73,6 +74,7 @@ function aggregateWeeklyMetrics( timestamp: getWeekStartSunday(year, weekNum), units: 0, revenue: 0, + adRevenue: 0, sessions: 0, cost: 0, clicks: 0, @@ -83,6 +85,7 @@ function aggregateWeeklyMetrics( const w = weeklyMap.get(key)!; w.units += r.unitsTotal ?? (r as any).units ?? 0; w.revenue += r.salesTotal ?? (r as any).sellOut ?? 0; + w.adRevenue += r.salesAds ?? 0; w.sessions += r.glanceViews || 0; w.cost += r.cost || 0; w.clicks += r.clicks || 0; @@ -95,7 +98,7 @@ function aggregateWeeklyMetrics( ...w, cvr: w.sessions > 0 ? (w.units / w.sessions) * 100 : 0, ctr: w.impressions > 0 ? (w.clicks / w.impressions) * 100 : 0, - roas: w.cost > 0 ? w.revenue / w.cost : 0, + roas: w.cost > 0 ? w.adRevenue / w.cost : 0, })); } @@ -107,7 +110,7 @@ function getMetricValue(w: ComputedWeeklyMetrics, metric: string): number { case 'ctr': return w.ctr; case 'roas': return w.roas; case 'revenue': return w.revenue; - case 'acos': return w.cost > 0 && w.revenue > 0 ? (w.cost / w.revenue) * 100 : 0; + case 'acos': return w.cost > 0 && w.adRevenue > 0 ? (w.cost / w.adRevenue) * 100 : 0; default: return w.units; } } @@ -163,14 +166,14 @@ function avgMetric(data: ComputedWeeklyMetrics[], metric: string, durationWeeks: return totalImpressions > 0 ? (totalClicks / totalImpressions) * 100 : 0; } if (metric === 'roas') { - const totalRevenue = data.reduce((s, w) => s + w.revenue, 0); + const totalAdRevenue = data.reduce((s, w) => s + w.adRevenue, 0); const totalCost = data.reduce((s, w) => s + w.cost, 0); - return totalCost > 0 ? totalRevenue / totalCost : 0; + return totalCost > 0 ? totalAdRevenue / totalCost : 0; } if (metric === 'acos') { - const totalRevenue = data.reduce((s, w) => s + w.revenue, 0); + const totalAdRevenue = data.reduce((s, w) => s + w.adRevenue, 0); const totalCost = data.reduce((s, w) => s + w.cost, 0); - return totalRevenue > 0 ? (totalCost / totalRevenue) * 100 : 0; + return totalAdRevenue > 0 ? (totalCost / totalAdRevenue) * 100 : 0; } // For absolute quantities (units, revenue, sessions), we sum them and divide by the duration