feat: add Detail Level BSR metric to experiments analysis

This commit is contained in:
Christian Vidal Wolf
2026-03-10 13:58:44 +01:00
parent 2363982144
commit c15642d62d
7 changed files with 70 additions and 24 deletions
+19 -2
View File
@@ -35,6 +35,8 @@ interface WeeklyMetrics {
cost: number;
clicks: number;
impressions: number;
detail_bsr: number;
bsrCount: number;
}
interface ComputedWeeklyMetrics extends WeeklyMetrics {
@@ -159,6 +161,8 @@ function aggregateWeeklyMetrics(
cost: 0,
clicks: 0,
impressions: 0,
detail_bsr: 0,
bsrCount: 0,
});
}
@@ -170,6 +174,10 @@ function aggregateWeeklyMetrics(
w.cost += Number(r.cost) || 0;
w.clicks += r.clicks || 0;
w.impressions += r.impressions || 0;
if (r.detailLevelBSR != null) {
w.detail_bsr += r.detailLevelBSR;
w.bsrCount += 1;
}
}
// Debug ad map
@@ -189,6 +197,7 @@ function aggregateWeeklyMetrics(
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.adRevenue / w.cost : 0,
detail_bsr: w.bsrCount > 0 ? w.detail_bsr / w.bsrCount : 0,
}));
}
@@ -201,6 +210,7 @@ function getMetricValue(w: ComputedWeeklyMetrics, metric: string): number {
case 'roas': return w.roas;
case 'revenue': return w.revenue;
case 'acos': return w.cost > 0 && w.adRevenue > 0 ? (w.cost / w.adRevenue) * 100 : 0;
case 'detail_bsr': return w.detail_bsr;
default: return w.units;
}
}
@@ -265,6 +275,13 @@ function avgMetric(data: ComputedWeeklyMetrics[], metric: string, durationWeeks:
const totalCost = data.reduce((s, w) => s + w.cost, 0);
return totalAdRevenue > 0 && totalCost > 0 ? (totalCost / totalAdRevenue) * 100 : 0;
}
if (metric === 'detail_bsr') {
// For detail_bsr, we want the average of the non-zero weeks
const validWeeks = data.filter(w => w.detail_bsr > 0);
if (validWeeks.length === 0) return 0;
const sum = validWeeks.reduce((s, w) => s + w.detail_bsr, 0);
return sum / validWeeks.length;
}
// For absolute quantities (units, revenue, sessions), we sum them and divide by the number of weeks
// Use actual data.length instead of theoretical durationWeeks for accuracy
@@ -272,8 +289,8 @@ function avgMetric(data: ComputedWeeklyMetrics[], metric: string, durationWeeks:
return sum / data.length;
}
const METRICS = ['units', 'sessions', 'cvr', 'ctr', 'roas', 'revenue', 'acos'];
const LOWER_IS_BETTER = new Set(['acos']);
const METRICS = ['units', 'sessions', 'cvr', 'ctr', 'roas', 'revenue', 'acos', 'detail_bsr'];
const LOWER_IS_BETTER = new Set(['acos', 'detail_bsr']);
function computeMetricDiD(
treatmentBefore: ComputedWeeklyMetrics[],