kanmi-perf-revenue 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -186
- package/dist/empirical/ab-testing.d.ts +83 -0
- package/dist/empirical/ab-testing.d.ts.map +1 -0
- package/dist/empirical/ab-testing.js +281 -0
- package/dist/empirical/ab-testing.js.map +1 -0
- package/dist/empirical/alerting.d.ts +85 -0
- package/dist/empirical/alerting.d.ts.map +1 -0
- package/dist/empirical/alerting.js +358 -0
- package/dist/empirical/alerting.js.map +1 -0
- package/dist/empirical/attribution.d.ts +80 -0
- package/dist/empirical/attribution.d.ts.map +1 -0
- package/dist/empirical/attribution.js +305 -0
- package/dist/empirical/attribution.js.map +1 -0
- package/dist/empirical/cohort.d.ts +75 -0
- package/dist/empirical/cohort.d.ts.map +1 -0
- package/dist/empirical/cohort.js +305 -0
- package/dist/empirical/cohort.js.map +1 -0
- package/dist/empirical/conversion-curve.d.ts +7 -10
- package/dist/empirical/conversion-curve.d.ts.map +1 -1
- package/dist/empirical/conversion-curve.js +37 -4
- package/dist/empirical/conversion-curve.js.map +1 -1
- package/dist/empirical/correlation.d.ts +91 -0
- package/dist/empirical/correlation.d.ts.map +1 -0
- package/dist/empirical/correlation.js +461 -0
- package/dist/empirical/correlation.js.map +1 -0
- package/dist/empirical/data-import.d.ts +22 -0
- package/dist/empirical/data-import.d.ts.map +1 -1
- package/dist/empirical/data-import.js +44 -0
- package/dist/empirical/data-import.js.map +1 -1
- package/dist/empirical/datadog-session-query.d.ts +32 -0
- package/dist/empirical/datadog-session-query.d.ts.map +1 -1
- package/dist/empirical/datadog-session-query.js +238 -17
- package/dist/empirical/datadog-session-query.js.map +1 -1
- package/dist/empirical/engagement-analysis.d.ts +112 -0
- package/dist/empirical/engagement-analysis.d.ts.map +1 -0
- package/dist/empirical/engagement-analysis.js +354 -0
- package/dist/empirical/engagement-analysis.js.map +1 -0
- package/dist/empirical/export.d.ts +75 -0
- package/dist/empirical/export.d.ts.map +1 -0
- package/dist/empirical/export.js +392 -0
- package/dist/empirical/export.js.map +1 -0
- package/dist/empirical/forecasting.d.ts +80 -0
- package/dist/empirical/forecasting.d.ts.map +1 -0
- package/dist/empirical/forecasting.js +287 -0
- package/dist/empirical/forecasting.js.map +1 -0
- package/dist/empirical/funnel.d.ts +66 -0
- package/dist/empirical/funnel.d.ts.map +1 -0
- package/dist/empirical/funnel.js +293 -0
- package/dist/empirical/funnel.js.map +1 -0
- package/dist/empirical/history.d.ts +198 -0
- package/dist/empirical/history.d.ts.map +1 -0
- package/dist/empirical/history.js +396 -0
- package/dist/empirical/history.js.map +1 -0
- package/dist/empirical/index.d.ts +39 -16
- package/dist/empirical/index.d.ts.map +1 -1
- package/dist/empirical/index.js +95 -13
- package/dist/empirical/index.js.map +1 -1
- package/dist/empirical/interactions.d.ts +89 -0
- package/dist/empirical/interactions.d.ts.map +1 -0
- package/dist/empirical/interactions.js +346 -0
- package/dist/empirical/interactions.js.map +1 -0
- package/dist/empirical/opportunity-calculator.d.ts +6 -18
- package/dist/empirical/opportunity-calculator.d.ts.map +1 -1
- package/dist/empirical/opportunity-calculator.js +19 -1
- package/dist/empirical/opportunity-calculator.js.map +1 -1
- package/dist/empirical/report.d.ts +3 -11
- package/dist/empirical/report.d.ts.map +1 -1
- package/dist/empirical/report.js +11 -7
- package/dist/empirical/report.js.map +1 -1
- package/dist/empirical/roi-calculator.d.ts +104 -0
- package/dist/empirical/roi-calculator.d.ts.map +1 -0
- package/dist/empirical/roi-calculator.js +403 -0
- package/dist/empirical/roi-calculator.js.map +1 -0
- package/dist/empirical/seasonality.d.ts +80 -0
- package/dist/empirical/seasonality.d.ts.map +1 -0
- package/dist/empirical/seasonality.js +340 -0
- package/dist/empirical/seasonality.js.map +1 -0
- package/dist/empirical/segmentation.d.ts +135 -0
- package/dist/empirical/segmentation.d.ts.map +1 -0
- package/dist/empirical/segmentation.js +379 -0
- package/dist/empirical/segmentation.js.map +1 -0
- package/dist/empirical/statistics.d.ts +118 -0
- package/dist/empirical/statistics.d.ts.map +1 -0
- package/dist/empirical/statistics.js +344 -0
- package/dist/empirical/statistics.js.map +1 -0
- package/dist/empirical/sweet-spot.d.ts +81 -0
- package/dist/empirical/sweet-spot.d.ts.map +1 -0
- package/dist/empirical/sweet-spot.js +198 -0
- package/dist/empirical/sweet-spot.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Metric Interaction Analysis
|
|
3
|
+
*
|
|
4
|
+
* Analyzes how combinations of performance metrics affect conversion rates.
|
|
5
|
+
* Goes beyond single-metric analysis to find interaction effects.
|
|
6
|
+
*
|
|
7
|
+
* Key insights:
|
|
8
|
+
* - Do users with both good LCP AND good INP convert better than expected?
|
|
9
|
+
* - Are there threshold combinations that matter?
|
|
10
|
+
* - Which metric pairs have synergistic effects?
|
|
11
|
+
*
|
|
12
|
+
* @author Kanmi Obasa <i@kanmiobasa.com>
|
|
13
|
+
*/
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// THRESHOLDS (Core Web Vitals standards)
|
|
16
|
+
// =============================================================================
|
|
17
|
+
const METRIC_THRESHOLDS = {
|
|
18
|
+
lcp: { good: 2500, poor: 4000 },
|
|
19
|
+
inp: { good: 200, poor: 500 },
|
|
20
|
+
cls: { good: 0.1, poor: 0.25 },
|
|
21
|
+
fcp: { good: 1800, poor: 3000 },
|
|
22
|
+
ttfb: { good: 800, poor: 1800 },
|
|
23
|
+
};
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// CORE ANALYSIS
|
|
26
|
+
// =============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* Get metric value from session.
|
|
29
|
+
*/
|
|
30
|
+
function getMetricValue(session, metric) {
|
|
31
|
+
switch (metric) {
|
|
32
|
+
case 'lcp':
|
|
33
|
+
return session.lcp_ms;
|
|
34
|
+
case 'inp':
|
|
35
|
+
return session.inp_ms;
|
|
36
|
+
case 'cls':
|
|
37
|
+
return session.cls;
|
|
38
|
+
case 'fcp':
|
|
39
|
+
return session.fcp_ms;
|
|
40
|
+
case 'ttfb':
|
|
41
|
+
return session.ttfb_ms;
|
|
42
|
+
default:
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classify metric value into bucket.
|
|
48
|
+
*/
|
|
49
|
+
function classifyMetric(value, thresholds) {
|
|
50
|
+
if (value === null)
|
|
51
|
+
return null;
|
|
52
|
+
if (value <= thresholds.good)
|
|
53
|
+
return 'good';
|
|
54
|
+
if (value >= thresholds.poor)
|
|
55
|
+
return 'poor';
|
|
56
|
+
return 'needs_improvement';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Analyze interaction between two metrics.
|
|
60
|
+
*/
|
|
61
|
+
export function analyzeMetricInteraction(sessions, metricA, metricB) {
|
|
62
|
+
const thresholdsA = METRIC_THRESHOLDS[metricA];
|
|
63
|
+
const thresholdsB = METRIC_THRESHOLDS[metricB];
|
|
64
|
+
// Classify each session
|
|
65
|
+
const classified = [];
|
|
66
|
+
for (const session of sessions) {
|
|
67
|
+
const valueA = getMetricValue(session, metricA);
|
|
68
|
+
const valueB = getMetricValue(session, metricB);
|
|
69
|
+
const bucketA = classifyMetric(valueA, thresholdsA);
|
|
70
|
+
const bucketB = classifyMetric(valueB, thresholdsB);
|
|
71
|
+
if (bucketA && bucketB) {
|
|
72
|
+
classified.push({
|
|
73
|
+
bucketA,
|
|
74
|
+
bucketB,
|
|
75
|
+
converted: session.has_purchase,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (classified.length < 100)
|
|
80
|
+
return null; // Need sufficient data
|
|
81
|
+
// Build 3x3 grid
|
|
82
|
+
const buckets = [
|
|
83
|
+
'good',
|
|
84
|
+
'needs_improvement',
|
|
85
|
+
'poor',
|
|
86
|
+
];
|
|
87
|
+
// Calculate marginal CVRs
|
|
88
|
+
const marginalsA = {};
|
|
89
|
+
const marginalsB = {};
|
|
90
|
+
for (const bucket of buckets) {
|
|
91
|
+
marginalsA[bucket] = { sessions: 0, conversions: 0 };
|
|
92
|
+
marginalsB[bucket] = { sessions: 0, conversions: 0 };
|
|
93
|
+
}
|
|
94
|
+
for (const item of classified) {
|
|
95
|
+
marginalsA[item.bucketA].sessions++;
|
|
96
|
+
marginalsB[item.bucketB].sessions++;
|
|
97
|
+
if (item.converted) {
|
|
98
|
+
marginalsA[item.bucketA].conversions++;
|
|
99
|
+
marginalsB[item.bucketB].conversions++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const overallCvr = classified.filter((c) => c.converted).length / classified.length;
|
|
103
|
+
// Build grid
|
|
104
|
+
const grid = [];
|
|
105
|
+
let bestCell = null;
|
|
106
|
+
let worstCell = null;
|
|
107
|
+
let totalInteractionEffect = 0;
|
|
108
|
+
let cellCount = 0;
|
|
109
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
110
|
+
grid[i] = [];
|
|
111
|
+
for (let j = 0; j < buckets.length; j++) {
|
|
112
|
+
const bucketA = buckets[i];
|
|
113
|
+
const bucketB = buckets[j];
|
|
114
|
+
const cellData = classified.filter((c) => c.bucketA === bucketA && c.bucketB === bucketB);
|
|
115
|
+
const cellSessions = cellData.length;
|
|
116
|
+
const cellConversions = cellData.filter((c) => c.converted).length;
|
|
117
|
+
const cvr = cellSessions > 0 ? cellConversions / cellSessions : 0;
|
|
118
|
+
// Expected CVR based on marginals (independence assumption)
|
|
119
|
+
const cvrA = marginalsA[bucketA].sessions > 0
|
|
120
|
+
? marginalsA[bucketA].conversions / marginalsA[bucketA].sessions
|
|
121
|
+
: overallCvr;
|
|
122
|
+
const cvrB = marginalsB[bucketB].sessions > 0
|
|
123
|
+
? marginalsB[bucketB].conversions / marginalsB[bucketB].sessions
|
|
124
|
+
: overallCvr;
|
|
125
|
+
// Expected under independence: P(convert | A) * P(convert | B) / P(convert)
|
|
126
|
+
// Simplified: average of the two marginal effects
|
|
127
|
+
const expectedCvr = (cvrA + cvrB) / 2;
|
|
128
|
+
const interactionEffect = cvr - expectedCvr;
|
|
129
|
+
const cell = {
|
|
130
|
+
metricABucket: bucketA,
|
|
131
|
+
metricBBucket: bucketB,
|
|
132
|
+
sessions: cellSessions,
|
|
133
|
+
conversions: cellConversions,
|
|
134
|
+
cvr,
|
|
135
|
+
expectedCvr,
|
|
136
|
+
interactionEffect,
|
|
137
|
+
synergistic: interactionEffect > 0,
|
|
138
|
+
};
|
|
139
|
+
grid[i][j] = cell;
|
|
140
|
+
if (cellSessions >= 10) {
|
|
141
|
+
// Only consider cells with sufficient data
|
|
142
|
+
totalInteractionEffect += Math.abs(interactionEffect);
|
|
143
|
+
cellCount++;
|
|
144
|
+
if (!bestCell || cvr > bestCell.cvr) {
|
|
145
|
+
bestCell = cell;
|
|
146
|
+
}
|
|
147
|
+
if (!worstCell || cvr < worstCell.cvr) {
|
|
148
|
+
worstCell = cell;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const interactionStrength = cellCount > 0 ? totalInteractionEffect / cellCount : 0;
|
|
154
|
+
// Generate insights
|
|
155
|
+
const insights = [];
|
|
156
|
+
// Check for synergy in good-good cell
|
|
157
|
+
const goodGood = grid[0][0];
|
|
158
|
+
if (goodGood.sessions >= 10 && goodGood.interactionEffect > 0.005) {
|
|
159
|
+
insights.push(`Synergy: Good ${metricA.toUpperCase()} + Good ${metricB.toUpperCase()} converts ${(goodGood.interactionEffect * 100).toFixed(2)}% better than expected`);
|
|
160
|
+
}
|
|
161
|
+
// Check for compounding poor performance
|
|
162
|
+
const poorPoor = grid[2][2];
|
|
163
|
+
if (poorPoor.sessions >= 10 && poorPoor.interactionEffect < -0.005) {
|
|
164
|
+
insights.push(`Compound penalty: Poor ${metricA.toUpperCase()} + Poor ${metricB.toUpperCase()} converts ${Math.abs(poorPoor.interactionEffect * 100).toFixed(2)}% worse than expected`);
|
|
165
|
+
}
|
|
166
|
+
// Compare good-good vs poor-poor
|
|
167
|
+
if (goodGood.sessions >= 10 && poorPoor.sessions >= 10 && goodGood.cvr > 0) {
|
|
168
|
+
const lift = ((goodGood.cvr - poorPoor.cvr) / poorPoor.cvr) * 100;
|
|
169
|
+
if (lift > 20) {
|
|
170
|
+
insights.push(`Combined impact: ${lift.toFixed(0)}% higher CVR when both metrics are good vs both poor`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
metricA,
|
|
175
|
+
metricB,
|
|
176
|
+
grid,
|
|
177
|
+
interactionStrength,
|
|
178
|
+
insights,
|
|
179
|
+
bestCombination: bestCell
|
|
180
|
+
? {
|
|
181
|
+
metricA: bestCell.metricABucket,
|
|
182
|
+
metricB: bestCell.metricBBucket,
|
|
183
|
+
cvr: bestCell.cvr,
|
|
184
|
+
lift: bestCell.cvr > overallCvr ? (bestCell.cvr - overallCvr) / overallCvr : 0,
|
|
185
|
+
}
|
|
186
|
+
: { metricA: 'good', metricB: 'good', cvr: overallCvr, lift: 0 },
|
|
187
|
+
worstCombination: worstCell
|
|
188
|
+
? {
|
|
189
|
+
metricA: worstCell.metricABucket,
|
|
190
|
+
metricB: worstCell.metricBBucket,
|
|
191
|
+
cvr: worstCell.cvr,
|
|
192
|
+
}
|
|
193
|
+
: { metricA: 'poor', metricB: 'poor', cvr: overallCvr },
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Analyze all pairwise metric interactions.
|
|
198
|
+
*/
|
|
199
|
+
export function analyzeAllInteractions(sessions) {
|
|
200
|
+
const metrics = ['lcp', 'inp', 'cls', 'fcp', 'ttfb'];
|
|
201
|
+
const interactions = [];
|
|
202
|
+
// Analyze all pairs
|
|
203
|
+
for (let i = 0; i < metrics.length; i++) {
|
|
204
|
+
for (let j = i + 1; j < metrics.length; j++) {
|
|
205
|
+
const interaction = analyzeMetricInteraction(sessions, metrics[i], metrics[j]);
|
|
206
|
+
if (interaction) {
|
|
207
|
+
interactions.push(interaction);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Rank by interaction strength
|
|
212
|
+
const rankedInteractions = interactions
|
|
213
|
+
.map((i) => ({
|
|
214
|
+
metricA: i.metricA,
|
|
215
|
+
metricB: i.metricB,
|
|
216
|
+
strength: i.interactionStrength,
|
|
217
|
+
}))
|
|
218
|
+
.sort((a, b) => b.strength - a.strength);
|
|
219
|
+
// Generate findings
|
|
220
|
+
const findings = [];
|
|
221
|
+
if (rankedInteractions.length > 0) {
|
|
222
|
+
const top = rankedInteractions[0];
|
|
223
|
+
findings.push(`Strongest interaction: ${top.metricA.toUpperCase()} × ${top.metricB.toUpperCase()} (strength: ${(top.strength * 100).toFixed(2)}%)`);
|
|
224
|
+
}
|
|
225
|
+
// Collect all insights
|
|
226
|
+
for (const interaction of interactions.slice(0, 3)) {
|
|
227
|
+
findings.push(...interaction.insights.slice(0, 2));
|
|
228
|
+
}
|
|
229
|
+
// Generate recommendations
|
|
230
|
+
const recommendations = [];
|
|
231
|
+
// Find the metric pair with highest synergy in good-good
|
|
232
|
+
let bestSynergy = null;
|
|
233
|
+
for (const interaction of interactions) {
|
|
234
|
+
const goodGood = interaction.grid[0][0];
|
|
235
|
+
if (goodGood.sessions >= 10 && goodGood.interactionEffect > 0) {
|
|
236
|
+
if (!bestSynergy || goodGood.interactionEffect > bestSynergy.effect) {
|
|
237
|
+
bestSynergy = {
|
|
238
|
+
pair: `${interaction.metricA.toUpperCase()} + ${interaction.metricB.toUpperCase()}`,
|
|
239
|
+
effect: goodGood.interactionEffect,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (bestSynergy) {
|
|
245
|
+
recommendations.push(`Prioritize improving both ${bestSynergy.pair} together for synergistic gains`);
|
|
246
|
+
}
|
|
247
|
+
// Find worst compound penalty
|
|
248
|
+
let worstPenalty = null;
|
|
249
|
+
for (const interaction of interactions) {
|
|
250
|
+
const poorPoor = interaction.grid[2][2];
|
|
251
|
+
if (poorPoor.sessions >= 10 && poorPoor.interactionEffect < 0) {
|
|
252
|
+
if (!worstPenalty || poorPoor.interactionEffect < worstPenalty.effect) {
|
|
253
|
+
worstPenalty = {
|
|
254
|
+
pair: `${interaction.metricA.toUpperCase()} + ${interaction.metricB.toUpperCase()}`,
|
|
255
|
+
effect: poorPoor.interactionEffect,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (worstPenalty) {
|
|
261
|
+
recommendations.push(`Address ${worstPenalty.pair} together - compound penalty of ${Math.abs(worstPenalty.effect * 100).toFixed(2)}%`);
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
interactions,
|
|
265
|
+
rankedInteractions,
|
|
266
|
+
findings,
|
|
267
|
+
recommendations,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
// =============================================================================
|
|
271
|
+
// REPORT GENERATION
|
|
272
|
+
// =============================================================================
|
|
273
|
+
/**
|
|
274
|
+
* Generate markdown report for interaction analysis.
|
|
275
|
+
*/
|
|
276
|
+
export function generateInteractionMarkdown(report) {
|
|
277
|
+
const lines = [];
|
|
278
|
+
lines.push('## Multi-Metric Interaction Analysis');
|
|
279
|
+
lines.push('');
|
|
280
|
+
lines.push('How combinations of performance metrics affect conversion rates beyond individual effects.');
|
|
281
|
+
lines.push('');
|
|
282
|
+
// Key Findings
|
|
283
|
+
if (report.findings.length > 0) {
|
|
284
|
+
lines.push('### Key Findings');
|
|
285
|
+
lines.push('');
|
|
286
|
+
for (const finding of report.findings) {
|
|
287
|
+
lines.push(`- ${finding}`);
|
|
288
|
+
}
|
|
289
|
+
lines.push('');
|
|
290
|
+
}
|
|
291
|
+
// Recommendations
|
|
292
|
+
if (report.recommendations.length > 0) {
|
|
293
|
+
lines.push('### Recommendations');
|
|
294
|
+
lines.push('');
|
|
295
|
+
for (const rec of report.recommendations) {
|
|
296
|
+
lines.push(`- ${rec}`);
|
|
297
|
+
}
|
|
298
|
+
lines.push('');
|
|
299
|
+
}
|
|
300
|
+
// Interaction Strength Ranking
|
|
301
|
+
if (report.rankedInteractions.length > 0) {
|
|
302
|
+
lines.push('### Interaction Strength Ranking');
|
|
303
|
+
lines.push('');
|
|
304
|
+
lines.push('| Metric Pair | Interaction Strength |');
|
|
305
|
+
lines.push('|-------------|---------------------|');
|
|
306
|
+
for (const ranked of report.rankedInteractions) {
|
|
307
|
+
lines.push(`| ${ranked.metricA.toUpperCase()} × ${ranked.metricB.toUpperCase()} | ${(ranked.strength * 100).toFixed(2)}% |`);
|
|
308
|
+
}
|
|
309
|
+
lines.push('');
|
|
310
|
+
}
|
|
311
|
+
// Detailed grids for top interactions
|
|
312
|
+
const topInteractions = report.interactions.slice(0, 3);
|
|
313
|
+
for (const interaction of topInteractions) {
|
|
314
|
+
lines.push(`### ${interaction.metricA.toUpperCase()} × ${interaction.metricB.toUpperCase()}`);
|
|
315
|
+
lines.push('');
|
|
316
|
+
lines.push(`| | Good ${interaction.metricB.toUpperCase()} | Needs Imp. | Poor ${interaction.metricB.toUpperCase()} |`);
|
|
317
|
+
lines.push('|---|---|---|---|');
|
|
318
|
+
const rowLabels = [`Good ${interaction.metricA.toUpperCase()}`, 'Needs Imp.', `Poor ${interaction.metricA.toUpperCase()}`];
|
|
319
|
+
for (let i = 0; i < 3; i++) {
|
|
320
|
+
const cells = interaction.grid[i];
|
|
321
|
+
const row = [
|
|
322
|
+
rowLabels[i],
|
|
323
|
+
formatCell(cells[0]),
|
|
324
|
+
formatCell(cells[1]),
|
|
325
|
+
formatCell(cells[2]),
|
|
326
|
+
];
|
|
327
|
+
lines.push(`| ${row.join(' | ')} |`);
|
|
328
|
+
}
|
|
329
|
+
lines.push('');
|
|
330
|
+
if (interaction.insights.length > 0) {
|
|
331
|
+
lines.push('**Insights:**');
|
|
332
|
+
for (const insight of interaction.insights) {
|
|
333
|
+
lines.push(`- ${insight}`);
|
|
334
|
+
}
|
|
335
|
+
lines.push('');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return lines.join('\n');
|
|
339
|
+
}
|
|
340
|
+
function formatCell(cell) {
|
|
341
|
+
if (cell.sessions < 10)
|
|
342
|
+
return `${(cell.cvr * 100).toFixed(1)}% (n=${cell.sessions})`;
|
|
343
|
+
const indicator = cell.synergistic ? '↑' : '↓';
|
|
344
|
+
return `${(cell.cvr * 100).toFixed(2)}% ${indicator}`;
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.js","sourceRoot":"","sources":["../../src/empirical/interactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @author Kanmi Obasa <i@kanmiobasa.com>
|
|
11
11
|
*/
|
|
12
|
-
import type { ConversionCurve } from './conversion-curve.js';
|
|
12
|
+
import type { ConversionCurve, PerformanceMetric } from './conversion-curve.js';
|
|
13
13
|
export interface OpportunityScenario {
|
|
14
14
|
/** Descriptive name for the scenario */
|
|
15
15
|
name: string;
|
|
@@ -40,7 +40,7 @@ export interface OpportunityScenario {
|
|
|
40
40
|
}
|
|
41
41
|
export interface OpportunityReport {
|
|
42
42
|
/** The metric analyzed */
|
|
43
|
-
metric:
|
|
43
|
+
metric: PerformanceMetric;
|
|
44
44
|
/** Analysis period */
|
|
45
45
|
period: {
|
|
46
46
|
days: number;
|
|
@@ -82,26 +82,14 @@ export interface OpportunityConfig {
|
|
|
82
82
|
*/
|
|
83
83
|
export declare function calculateOpportunity(curve: ConversionCurve, config: OpportunityConfig): OpportunityReport;
|
|
84
84
|
/**
|
|
85
|
-
* Calculate opportunity for all
|
|
85
|
+
* Calculate opportunity for all performance metrics.
|
|
86
86
|
*/
|
|
87
|
-
export declare function calculateAllOpportunities(curves:
|
|
88
|
-
lcp: ConversionCurve;
|
|
89
|
-
inp: ConversionCurve;
|
|
90
|
-
cls: ConversionCurve;
|
|
91
|
-
}, config: OpportunityConfig): {
|
|
92
|
-
lcp: OpportunityReport;
|
|
93
|
-
inp: OpportunityReport;
|
|
94
|
-
cls: OpportunityReport;
|
|
95
|
-
};
|
|
87
|
+
export declare function calculateAllOpportunities(curves: Record<PerformanceMetric, ConversionCurve>, config: OpportunityConfig): Record<PerformanceMetric, OpportunityReport>;
|
|
96
88
|
/**
|
|
97
89
|
* Get the single highest-impact opportunity across all metrics.
|
|
98
90
|
*/
|
|
99
|
-
export declare function getTopOpportunity(opportunities: {
|
|
100
|
-
|
|
101
|
-
inp: OpportunityReport;
|
|
102
|
-
cls: OpportunityReport;
|
|
103
|
-
}): {
|
|
104
|
-
metric: 'lcp' | 'inp' | 'cls';
|
|
91
|
+
export declare function getTopOpportunity(opportunities: Record<string, OpportunityReport>): {
|
|
92
|
+
metric: PerformanceMetric;
|
|
105
93
|
scenario: OpportunityScenario;
|
|
106
94
|
} | null;
|
|
107
95
|
//# sourceMappingURL=opportunity-calculator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunity-calculator.d.ts","sourceRoot":"","sources":["../../src/empirical/opportunity-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"opportunity-calculator.d.ts","sourceRoot":"","sources":["../../src/empirical/opportunity-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAoB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAMlG,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,0BAA0B,EAAE,MAAM,CAAC;IACnC,gDAAgD;IAChD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uDAAuD;IACvD,4BAA4B,EAAE,MAAM,CAAC;IACrC,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,0BAA0B;IAC1B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,sBAAsB;IACtB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,+CAA+C;IAC/C,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,qDAAqD;IACrD,cAAc,EAAE;QACd,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,sCAAsC;IACtC,aAAa,EAAE;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,+DAA+D;IAC/D,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAQD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CA6CnB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,eAAe,CAAC,EAClD,MAAM,EAAE,iBAAiB,GACxB,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAW9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC/C;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,GAAG,IAAI,CAoBrE"}
|
|
@@ -54,13 +54,18 @@ export function calculateOpportunity(curve, config) {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Calculate opportunity for all
|
|
57
|
+
* Calculate opportunity for all performance metrics.
|
|
58
58
|
*/
|
|
59
59
|
export function calculateAllOpportunities(curves, config) {
|
|
60
60
|
return {
|
|
61
61
|
lcp: calculateOpportunity(curves.lcp, config),
|
|
62
|
+
fcp: calculateOpportunity(curves.fcp, config),
|
|
62
63
|
inp: calculateOpportunity(curves.inp, config),
|
|
63
64
|
cls: calculateOpportunity(curves.cls, config),
|
|
65
|
+
ttfb: calculateOpportunity(curves.ttfb, config),
|
|
66
|
+
tti: calculateOpportunity(curves.tti, config),
|
|
67
|
+
onload: calculateOpportunity(curves.onload, config),
|
|
68
|
+
page_size: calculateOpportunity(curves.page_size, config),
|
|
64
69
|
};
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
@@ -211,16 +216,29 @@ function getDefaultTargets(metric) {
|
|
|
211
216
|
switch (metric) {
|
|
212
217
|
case 'lcp':
|
|
213
218
|
return [2500, 3000, 4000]; // Good threshold, mid, poor threshold
|
|
219
|
+
case 'fcp':
|
|
220
|
+
return [1800, 2400, 3000]; // Good < 1.8s, needs improvement < 3s
|
|
214
221
|
case 'inp':
|
|
215
222
|
return [200, 300, 500];
|
|
216
223
|
case 'cls':
|
|
217
224
|
return [100, 150, 250]; // Scaled by 1000
|
|
225
|
+
case 'ttfb':
|
|
226
|
+
return [800, 1200, 1800];
|
|
227
|
+
case 'tti':
|
|
228
|
+
return [3800, 5500, 7300]; // Good < 3.8s, needs improvement < 7.3s
|
|
229
|
+
case 'onload':
|
|
230
|
+
return [3000, 4500, 6000];
|
|
231
|
+
case 'page_size':
|
|
232
|
+
return [3000, 5000, 8000]; // KB
|
|
218
233
|
}
|
|
219
234
|
}
|
|
220
235
|
function formatTargetLabel(targetMs, metric) {
|
|
221
236
|
if (metric === 'cls') {
|
|
222
237
|
return (targetMs / 1000).toFixed(2);
|
|
223
238
|
}
|
|
239
|
+
if (metric === 'page_size') {
|
|
240
|
+
return `${(targetMs / 1000).toFixed(1)}MB`;
|
|
241
|
+
}
|
|
224
242
|
if (targetMs >= 1000) {
|
|
225
243
|
return `${(targetMs / 1000).toFixed(1)}s`;
|
|
226
244
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunity-calculator.js","sourceRoot":"","sources":["../../src/empirical/opportunity-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwEH,gFAAgF;AAChF,yBAAyB;AACzB,gFAAgF;AAEhF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAsB,EACtB,MAAyB;IAEzB,MAAM,EACJ,UAAU,EACV,sBAAsB,GAAG,EAAE,GAC5B,GAAG,MAAM,CAAC;IAEX,MAAM,aAAa,GAAG,mBAAmB,GAAG,UAAU,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,gBAAgB,IAAI,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE3E,MAAM,SAAS,GAA0B,EAAE,CAAC;IAE5C,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,yBAAyB,CACxC,KAAK,EACL,QAAQ,EACR,aAAa,EACb,sBAAsB,CACvB,CAAC;QAEF,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,4BAA4B,GAAG,CAAC,CAAC,4BAA4B,CAAC,CAAC;IAE1F,0BAA0B;IAC1B,MAAM,cAAc,GAAG,sBAAsB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEhE,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE;YACN,IAAI,EAAE,UAAU;YAChB,cAAc,EAAE,aAAa;SAC9B;QACD,SAAS;QACT,cAAc;QACd,aAAa,EAAE;YACb,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc;YAC5C,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;YACtC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;YACtC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;SACnC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,
|
|
1
|
+
{"version":3,"file":"opportunity-calculator.js","sourceRoot":"","sources":["../../src/empirical/opportunity-calculator.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @author Kanmi Obasa <i@kanmiobasa.com>
|
|
9
9
|
*/
|
|
10
|
-
import type { ConversionCurve } from './conversion-curve.js';
|
|
10
|
+
import type { ConversionCurve, PerformanceMetric } from './conversion-curve.js';
|
|
11
11
|
import type { OpportunityReport } from './opportunity-calculator.js';
|
|
12
12
|
export interface ReportConfig {
|
|
13
13
|
clientName?: string;
|
|
@@ -19,16 +19,8 @@ export interface ReportConfig {
|
|
|
19
19
|
includeRawCurve?: boolean;
|
|
20
20
|
}
|
|
21
21
|
export interface FullReport {
|
|
22
|
-
curves:
|
|
23
|
-
|
|
24
|
-
inp: ConversionCurve;
|
|
25
|
-
cls: ConversionCurve;
|
|
26
|
-
};
|
|
27
|
-
opportunities: {
|
|
28
|
-
lcp: OpportunityReport;
|
|
29
|
-
inp: OpportunityReport;
|
|
30
|
-
cls: OpportunityReport;
|
|
31
|
-
};
|
|
22
|
+
curves: Record<PerformanceMetric, ConversionCurve>;
|
|
23
|
+
opportunities: Record<PerformanceMetric, OpportunityReport>;
|
|
32
24
|
}
|
|
33
25
|
/**
|
|
34
26
|
* Generate a complete markdown report.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/empirical/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/empirical/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAMrE,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;IACnD,aAAa,EAAE,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;CAC7D;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CA+F7E"}
|
package/dist/empirical/report.js
CHANGED
|
@@ -32,15 +32,18 @@ export function generateReport(data, config) {
|
|
|
32
32
|
lines.push('');
|
|
33
33
|
lines.push(generateExecutiveSummary(data.opportunities));
|
|
34
34
|
lines.push('');
|
|
35
|
+
// All performance metrics
|
|
36
|
+
const ALL_METRICS = ['lcp', 'fcp', 'inp', 'cls', 'ttfb', 'tti', 'onload', 'page_size'];
|
|
35
37
|
// Measured Conversion Curves
|
|
36
38
|
lines.push('## Measured Conversion Rates');
|
|
37
39
|
lines.push('');
|
|
38
40
|
lines.push('These are the **actual conversion rates** measured at each performance bucket from your session data:');
|
|
39
41
|
lines.push('');
|
|
40
|
-
for (const metric of
|
|
42
|
+
for (const metric of ALL_METRICS) {
|
|
41
43
|
const curve = data.curves[metric];
|
|
42
44
|
if (curve.buckets.length > 0) {
|
|
43
|
-
|
|
45
|
+
const metricLabel = metric === 'page_size' ? 'Page Size' : metric.toUpperCase();
|
|
46
|
+
lines.push(`### ${metricLabel} Conversion Curve`);
|
|
44
47
|
lines.push('');
|
|
45
48
|
lines.push(generateCurveTable(curve));
|
|
46
49
|
lines.push('');
|
|
@@ -49,11 +52,12 @@ export function generateReport(data, config) {
|
|
|
49
52
|
// Revenue Opportunities
|
|
50
53
|
lines.push('## Revenue Opportunities');
|
|
51
54
|
lines.push('');
|
|
52
|
-
const allOpportunities =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const allOpportunities = ALL_METRICS
|
|
56
|
+
.map((metric) => ({
|
|
57
|
+
metric: metric === 'page_size' ? 'Page Size' : metric.toUpperCase(),
|
|
58
|
+
report: data.opportunities[metric],
|
|
59
|
+
}))
|
|
60
|
+
.filter((o) => o.report.scenarios.length > 0);
|
|
57
61
|
if (allOpportunities.length === 0) {
|
|
58
62
|
lines.push('No significant opportunities detected. Your performance distribution shows minimal CVR variation across buckets.');
|
|
59
63
|
lines.push('');
|