fix(experiments): explicitly use ad revenue (salesAds) for true ACOS and ROAS calculations instead of total sales revenue

This commit is contained in:
Christian Vidal Wolf
2026-02-25 13:52:57 +01:00
parent 30466a94ff
commit 69eafe8335
+9 -6
View File
@@ -30,6 +30,7 @@ interface WeeklyMetrics {
timestamp: number; timestamp: number;
units: number; units: number;
revenue: number; revenue: number;
adRevenue: number;
sessions: number; // glanceViews sessions: number; // glanceViews
cost: number; cost: number;
clicks: number; clicks: number;
@@ -73,6 +74,7 @@ function aggregateWeeklyMetrics(
timestamp: getWeekStartSunday(year, weekNum), timestamp: getWeekStartSunday(year, weekNum),
units: 0, units: 0,
revenue: 0, revenue: 0,
adRevenue: 0,
sessions: 0, sessions: 0,
cost: 0, cost: 0,
clicks: 0, clicks: 0,
@@ -83,6 +85,7 @@ function aggregateWeeklyMetrics(
const w = weeklyMap.get(key)!; const w = weeklyMap.get(key)!;
w.units += r.unitsTotal ?? (r as any).units ?? 0; w.units += r.unitsTotal ?? (r as any).units ?? 0;
w.revenue += r.salesTotal ?? (r as any).sellOut ?? 0; w.revenue += r.salesTotal ?? (r as any).sellOut ?? 0;
w.adRevenue += r.salesAds ?? 0;
w.sessions += r.glanceViews || 0; w.sessions += r.glanceViews || 0;
w.cost += r.cost || 0; w.cost += r.cost || 0;
w.clicks += r.clicks || 0; w.clicks += r.clicks || 0;
@@ -95,7 +98,7 @@ function aggregateWeeklyMetrics(
...w, ...w,
cvr: w.sessions > 0 ? (w.units / w.sessions) * 100 : 0, cvr: w.sessions > 0 ? (w.units / w.sessions) * 100 : 0,
ctr: w.impressions > 0 ? (w.clicks / w.impressions) * 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 'ctr': return w.ctr;
case 'roas': return w.roas; case 'roas': return w.roas;
case 'revenue': return w.revenue; 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; default: return w.units;
} }
} }
@@ -163,14 +166,14 @@ function avgMetric(data: ComputedWeeklyMetrics[], metric: string, durationWeeks:
return totalImpressions > 0 ? (totalClicks / totalImpressions) * 100 : 0; return totalImpressions > 0 ? (totalClicks / totalImpressions) * 100 : 0;
} }
if (metric === 'roas') { 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); 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') { 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); 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 // For absolute quantities (units, revenue, sessions), we sum them and divide by the duration