kanmi-perf-revenue 1.0.0 → 1.2.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 +347 -173
- 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-product-analytics.d.ts +192 -0
- package/dist/empirical/datadog-product-analytics.d.ts.map +1 -0
- package/dist/empirical/datadog-product-analytics.js +632 -0
- package/dist/empirical/datadog-product-analytics.js.map +1 -0
- 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 +41 -16
- package/dist/empirical/index.d.ts.map +1 -1
- package/dist/empirical/index.js +96 -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 +2 -2
package/README.md
CHANGED
|
@@ -1,247 +1,421 @@
|
|
|
1
|
-
#
|
|
1
|
+
# kanmi-perf-revenue
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Revenue intelligence for web performance — Native Datadog RUM integration or bring your own data.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**No assumed coefficients.** No "0.5% CVR per 100ms" guesses. This tool measures the actual conversion rates at each performance bucket from YOUR session data.
|
|
6
|
+
|
|
7
|
+
## Data Sources
|
|
8
|
+
|
|
9
|
+
| Source | Integration | Features |
|
|
10
|
+
|--------|-------------|----------|
|
|
11
|
+
| **Datadog RUM + Product Analytics** | Native API | Full: frustration signals, funnels, retention, replay |
|
|
12
|
+
| **CSV/JSON import** | Universal | Core analysis works with any backend |
|
|
13
|
+
| **web-vitals.js + your backend** | Self-hosted | Collect → export → analyze |
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install kanmi-perf-revenue
|
|
19
|
+
```
|
|
6
20
|
|
|
7
21
|
## Quick Start
|
|
8
22
|
|
|
23
|
+
### CLI Usage
|
|
24
|
+
|
|
9
25
|
```bash
|
|
10
|
-
#
|
|
11
|
-
|
|
26
|
+
# Run with mock data (demo)
|
|
27
|
+
npx kanmi-perf-revenue --demo
|
|
12
28
|
|
|
13
|
-
#
|
|
14
|
-
perf-revenue
|
|
29
|
+
# Import from CSV/JSON file
|
|
30
|
+
npx kanmi-perf-revenue --file sessions.csv --client "Acme Corp"
|
|
15
31
|
|
|
16
|
-
#
|
|
17
|
-
perf-revenue
|
|
18
|
-
|
|
19
|
-
--display-name "Acme Corp" \
|
|
20
|
-
--ga4-project my-gcp-project \
|
|
21
|
-
--ga4-property 123456789 \
|
|
22
|
-
--datadog-app rum-app-id
|
|
32
|
+
# Use Datadog RUM directly
|
|
33
|
+
DD_API_KEY=xxx DD_APP_KEY=xxx npx kanmi-perf-revenue --start 2025-01-01 --end 2025-01-14
|
|
34
|
+
```
|
|
23
35
|
|
|
24
|
-
|
|
25
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
26
|
-
export DATADOG_API_KEY=...
|
|
27
|
-
export DATADOG_APP_KEY=...
|
|
36
|
+
### Library Usage
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
```typescript
|
|
39
|
+
import {
|
|
40
|
+
analyzeFromFile,
|
|
41
|
+
analyzeWithMockData,
|
|
42
|
+
analyzeWithDatadog,
|
|
43
|
+
} from 'kanmi-perf-revenue';
|
|
44
|
+
|
|
45
|
+
// From CSV/JSON
|
|
46
|
+
const result = analyzeFromFile({
|
|
47
|
+
filePath: './sessions.csv',
|
|
48
|
+
clientName: 'Acme Corp',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// From Datadog RUM
|
|
52
|
+
const result = await analyzeWithDatadog({
|
|
53
|
+
apiKey: process.env.DD_API_KEY,
|
|
54
|
+
appKey: process.env.DD_APP_KEY,
|
|
55
|
+
startDate: '2025-01-01',
|
|
56
|
+
endDate: '2025-01-14',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log(result.report);
|
|
60
|
+
console.log(`Top opportunity: $${result.topOpportunity?.monthlyRevenue}/month`);
|
|
31
61
|
```
|
|
32
62
|
|
|
33
|
-
##
|
|
63
|
+
## What You Get
|
|
64
|
+
|
|
65
|
+
### Empirical Conversion Curves
|
|
66
|
+
|
|
67
|
+
Actual CVR measured at each performance bucket:
|
|
34
68
|
|
|
35
69
|
```
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
│ Claude Agent (Autonomous) │
|
|
43
|
-
│ ├── Tool: BigQuery (fetch GA4 business data) │
|
|
44
|
-
│ ├── Tool: Datadog API (fetch RUM performance) │
|
|
45
|
-
│ ├── Tool: Analysis Engine (calculate impact) │
|
|
46
|
-
│ └── Tool: Report Generator (format output) │
|
|
47
|
-
└─────────────────────────────────────────────────────┘
|
|
48
|
-
│
|
|
49
|
-
▼
|
|
50
|
-
┌─────────────────────────────────────────────────────┐
|
|
51
|
-
│ Executive Report (markdown) │
|
|
52
|
-
│ • $47K/month revenue opportunity │
|
|
53
|
-
│ • Prioritized by financial impact │
|
|
54
|
-
│ • CFO-ready format │
|
|
55
|
-
└─────────────────────────────────────────────────────┘
|
|
70
|
+
| LCP Range | Sessions | CVR | Revenue |
|
|
71
|
+
|-------------|----------|--------|---------|
|
|
72
|
+
| 0.0s-1.0s | 1,852 | 3.67% | $8K |
|
|
73
|
+
| 1.0s-1.5s | 12,339 | 2.79% | $40K |
|
|
74
|
+
| 2.0s-2.5s | 13,684 | 2.22% | $37K |
|
|
75
|
+
| 3.0s+ | 420 | 1.40% | $500 |
|
|
56
76
|
```
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- **Autonomous Analysis** - Claude fetches, analyzes, and reports without manual intervention
|
|
61
|
-
- **Financial-First** - Revenue impact in dollars, not performance scores
|
|
62
|
-
- **Conservative Estimates** - Underestimates by design, defensible assumptions
|
|
63
|
-
- **Executive Output** - VP/Director/CFO-ready reports
|
|
78
|
+
### Revenue Opportunity Analysis
|
|
64
79
|
|
|
65
|
-
|
|
80
|
+
Prioritized recommendations with dollar amounts:
|
|
66
81
|
|
|
67
|
-
|
|
82
|
+
```
|
|
83
|
+
Top Opportunity: LCP
|
|
84
|
+
37% of sessions have LCP > 2.5s
|
|
85
|
+
These sessions convert 18.5% worse than faster sessions
|
|
86
|
+
Monthly revenue opportunity: $10K/month
|
|
87
|
+
```
|
|
68
88
|
|
|
69
|
-
|
|
89
|
+
## Features
|
|
70
90
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
91
|
+
| Feature | Description |
|
|
92
|
+
|---------|-------------|
|
|
93
|
+
| **8 Performance Metrics** | LCP, FCP, INP, CLS, TTFB, TTI, Onload, Page Size |
|
|
94
|
+
| **Datadog Product Analytics** | Frustration signals, user journeys, retention — no GA needed |
|
|
95
|
+
| **Segmentation** | Device, page type, geography, traffic source |
|
|
96
|
+
| **Statistical Significance** | Confidence intervals, p-values, effect sizes |
|
|
97
|
+
| **Correlation Analysis** | Which metrics correlate most with conversions |
|
|
98
|
+
| **Multi-Metric Interactions** | How LCP + INP together affect CVR |
|
|
99
|
+
| **Seasonality Patterns** | Hour-of-day, day-of-week analysis |
|
|
100
|
+
| **Funnel Analysis** | Where in the journey does performance matter most |
|
|
101
|
+
| **ROI Calculator** | Engineering effort vs expected revenue gain |
|
|
102
|
+
| **Forecasting** | 12-month revenue projections |
|
|
103
|
+
| **Cohort Analysis** | LTV by performance cohort |
|
|
104
|
+
| **A/B Test Integration** | Compare performance variants statistically |
|
|
105
|
+
| **Attribution Models** | First-touch, last-touch, linear, position-based |
|
|
106
|
+
| **Alerting** | Threshold breaches, regressions, anomalies |
|
|
107
|
+
| **Export Formats** | JSON, CSV, Slack blocks, HTML email, webhooks |
|
|
108
|
+
|
|
109
|
+
## Data Input Format
|
|
110
|
+
|
|
111
|
+
### CSV/JSON
|
|
112
|
+
|
|
113
|
+
Required columns:
|
|
114
|
+
- `session_id` — Unique session identifier
|
|
115
|
+
- `converted` or `has_purchase` — Boolean or 0/1
|
|
116
|
+
|
|
117
|
+
Optional columns:
|
|
118
|
+
- `lcp_ms`, `inp_ms`, `cls`, `fcp_ms`, `ttfb_ms` — Performance metrics
|
|
119
|
+
- `order_value` or `revenue` — Purchase amount
|
|
120
|
+
- `device` — mobile, desktop, tablet
|
|
121
|
+
- `page_type` — pdp, plp, checkout, home, etc.
|
|
122
|
+
- `country`, `traffic_source` — Segmentation
|
|
123
|
+
- `timestamp` — For time-based analysis
|
|
124
|
+
|
|
125
|
+
Example CSV:
|
|
126
|
+
```csv
|
|
127
|
+
session_id,lcp_ms,converted,order_value,device,page_type
|
|
128
|
+
abc123,1200,1,89.99,mobile,pdp
|
|
129
|
+
def456,3500,0,0,desktop,plp
|
|
130
|
+
ghi789,800,1,150.00,mobile,checkout
|
|
79
131
|
```
|
|
80
132
|
|
|
81
|
-
###
|
|
133
|
+
### Datadog RUM
|
|
82
134
|
|
|
83
|
-
|
|
135
|
+
The tool queries Datadog's RUM API for session-level data including Core Web Vitals, user actions, and custom events.
|
|
84
136
|
|
|
85
|
-
|
|
86
|
-
# Initialize config directory
|
|
87
|
-
perf-revenue config init
|
|
137
|
+
### Datadog Product Analytics
|
|
88
138
|
|
|
89
|
-
|
|
90
|
-
perf-revenue config show
|
|
139
|
+
Full integration with Datadog Product Analytics — **no need for Google Analytics**. One SDK provides:
|
|
91
140
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
--ga4-project <id> # GCP project ID
|
|
97
|
-
--ga4-property <id> # GA4 property ID
|
|
98
|
-
--ga4-key-file <path> # Service account JSON (optional)
|
|
99
|
-
--datadog-app <id> # Datadog RUM app ID
|
|
100
|
-
--datadog-site <site> # Datadog site (default: datadoghq.com)
|
|
141
|
+
- Core Web Vitals + conversion data in the same session
|
|
142
|
+
- Frustration signals (rage clicks, dead clicks, error clicks)
|
|
143
|
+
- User journey mapping and retention analysis
|
|
144
|
+
- Funnel analysis with performance correlation
|
|
101
145
|
|
|
102
|
-
|
|
103
|
-
|
|
146
|
+
```typescript
|
|
147
|
+
import {
|
|
148
|
+
queryEnhancedSessions,
|
|
149
|
+
queryFunnel,
|
|
150
|
+
queryCohortRetention,
|
|
151
|
+
analyzeFrustrationImpact,
|
|
152
|
+
} from 'kanmi-perf-revenue';
|
|
153
|
+
|
|
154
|
+
// Query sessions with frustration signals
|
|
155
|
+
const { sessions } = await queryEnhancedSessions({
|
|
156
|
+
apiKey: process.env.DD_API_KEY,
|
|
157
|
+
appKey: process.env.DD_APP_KEY,
|
|
158
|
+
startDate: '2025-01-01',
|
|
159
|
+
endDate: '2025-01-14',
|
|
160
|
+
includeFrustrationSignals: true,
|
|
161
|
+
});
|
|
104
162
|
|
|
105
|
-
|
|
106
|
-
|
|
163
|
+
// Analyze frustration impact on conversions
|
|
164
|
+
const impact = analyzeFrustrationImpact(sessions);
|
|
165
|
+
console.log(`Frustrated users convert ${(impact.summary.conversionImpact * 100).toFixed(1)}% less`);
|
|
166
|
+
|
|
167
|
+
// Query conversion funnel
|
|
168
|
+
const funnel = await queryFunnel(
|
|
169
|
+
{ apiKey: process.env.DD_API_KEY, appKey: process.env.DD_APP_KEY, startDate: '2025-01-01', endDate: '2025-01-14' },
|
|
170
|
+
[
|
|
171
|
+
{ name: 'View Product', selector: 'view_product' },
|
|
172
|
+
{ name: 'Add to Cart', selector: 'add_to_cart' },
|
|
173
|
+
{ name: 'Checkout', selector: 'checkout_start' },
|
|
174
|
+
{ name: 'Purchase', selector: 'purchase', isConversion: true },
|
|
175
|
+
]
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// Cohort retention analysis
|
|
179
|
+
const retention = await queryCohortRetention(
|
|
180
|
+
{ apiKey: process.env.DD_API_KEY, appKey: process.env.DD_APP_KEY, startDate: '2025-01-01', endDate: '2025-01-14' },
|
|
181
|
+
{
|
|
182
|
+
name: 'January Signups',
|
|
183
|
+
query: '@session.is_first_visit:true',
|
|
184
|
+
period: { start: '2025-01-01', end: '2025-01-31' },
|
|
185
|
+
}
|
|
186
|
+
);
|
|
107
187
|
```
|
|
108
188
|
|
|
109
|
-
###
|
|
189
|
+
### Self-Hosted with web-vitals.js
|
|
190
|
+
|
|
191
|
+
Don't use Datadog? Collect your own data with Google's [web-vitals](https://github.com/GoogleChrome/web-vitals) library and export to CSV.
|
|
192
|
+
|
|
193
|
+
```html
|
|
194
|
+
<!-- Add to your site -->
|
|
195
|
+
<script type="module">
|
|
196
|
+
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'https://unpkg.com/web-vitals@4/dist/web-vitals.js';
|
|
197
|
+
|
|
198
|
+
const sessionId = crypto.randomUUID();
|
|
199
|
+
const metrics = {};
|
|
200
|
+
|
|
201
|
+
// Detect page type from URL
|
|
202
|
+
function getPageType(path) {
|
|
203
|
+
if (path === '/') return 'home';
|
|
204
|
+
if (path.includes('/product/')) return 'pdp';
|
|
205
|
+
if (path.includes('/category/')) return 'plp';
|
|
206
|
+
if (path.includes('/cart') || path.includes('/checkout')) return 'checkout';
|
|
207
|
+
return 'other';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function sendToBackend(metric) {
|
|
211
|
+
metrics[metric.name.toLowerCase()] = metric.value;
|
|
212
|
+
|
|
213
|
+
// Send to your backend (adjust URL)
|
|
214
|
+
navigator.sendBeacon('/api/vitals', JSON.stringify({
|
|
215
|
+
session_id: sessionId,
|
|
216
|
+
...metrics,
|
|
217
|
+
timestamp: new Date().toISOString(),
|
|
218
|
+
device: /Mobile/.test(navigator.userAgent) ? 'mobile' : 'desktop',
|
|
219
|
+
page_type: getPageType(location.pathname),
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
onLCP(sendToBackend);
|
|
224
|
+
onINP(sendToBackend);
|
|
225
|
+
onCLS(sendToBackend);
|
|
226
|
+
onFCP(sendToBackend);
|
|
227
|
+
onTTFB(sendToBackend);
|
|
228
|
+
|
|
229
|
+
// Track conversions - call this on purchase
|
|
230
|
+
window.trackConversion = (value) => {
|
|
231
|
+
navigator.sendBeacon('/api/vitals', JSON.stringify({
|
|
232
|
+
session_id: sessionId,
|
|
233
|
+
converted: true,
|
|
234
|
+
order_value: value,
|
|
235
|
+
}));
|
|
236
|
+
};
|
|
237
|
+
</script>
|
|
238
|
+
```
|
|
110
239
|
|
|
111
|
-
|
|
240
|
+
Then export your backend data to CSV and analyze:
|
|
112
241
|
|
|
113
242
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
```
|
|
243
|
+
# Export from your database
|
|
244
|
+
psql -c "COPY (SELECT * FROM sessions) TO STDOUT CSV HEADER" > sessions.csv
|
|
117
245
|
|
|
118
|
-
|
|
246
|
+
# Analyze
|
|
247
|
+
npx kanmi-perf-revenue --file sessions.csv --client "My Site"
|
|
248
|
+
```
|
|
119
249
|
|
|
120
|
-
|
|
250
|
+
## CLI Reference
|
|
121
251
|
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
252
|
+
```bash
|
|
253
|
+
kanmi-perf-revenue [options]
|
|
254
|
+
|
|
255
|
+
Data Sources:
|
|
256
|
+
--file PATH Import from CSV or JSON file
|
|
257
|
+
--demo Run with mock data (for testing)
|
|
258
|
+
--api-key KEY Datadog API key (or set DD_API_KEY)
|
|
259
|
+
--app-key KEY Datadog App key (or set DD_APP_KEY)
|
|
260
|
+
|
|
261
|
+
Options:
|
|
262
|
+
--start DATE Start date (YYYY-MM-DD). Default: 14 days ago
|
|
263
|
+
--end DATE End date (YYYY-MM-DD). Default: today
|
|
264
|
+
--client NAME Client name for report header
|
|
265
|
+
--help, -h Show help
|
|
266
|
+
|
|
267
|
+
History & Tracking:
|
|
268
|
+
--save Save analysis to history
|
|
269
|
+
--tag TAG Tag the entry (e.g., "baseline", "post-fix")
|
|
270
|
+
--compare Compare to baseline
|
|
271
|
+
--history Show analysis history
|
|
272
|
+
--trend Show CVR trend over time
|
|
273
|
+
--metric METRIC Metric for trend (lcp, inp, cls)
|
|
126
274
|
```
|
|
127
275
|
|
|
128
|
-
###
|
|
276
|
+
### Workflow Example
|
|
129
277
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
| `DATADOG_API_KEY` | Yes | Datadog API key |
|
|
134
|
-
| `DATADOG_APP_KEY` | Yes | Datadog application key |
|
|
135
|
-
| `GOOGLE_APPLICATION_CREDENTIALS` | No | Path to GCP service account JSON |
|
|
278
|
+
```bash
|
|
279
|
+
# 1. Establish baseline
|
|
280
|
+
kanmi-perf-revenue --file week1.csv --save --tag baseline
|
|
136
281
|
|
|
137
|
-
|
|
282
|
+
# 2. After performance fix, compare
|
|
283
|
+
kanmi-perf-revenue --file week2.csv --save --tag post-fix --compare
|
|
138
284
|
|
|
139
|
-
|
|
285
|
+
# 3. View trend over time
|
|
286
|
+
kanmi-perf-revenue --trend --metric lcp
|
|
140
287
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
| 100ms INP improvement | +0.3% conversion rate |
|
|
145
|
-
| 0.01 CLS improvement | +0.1% conversion rate |
|
|
288
|
+
# 4. View history
|
|
289
|
+
kanmi-perf-revenue --history
|
|
290
|
+
```
|
|
146
291
|
|
|
147
|
-
##
|
|
292
|
+
## Advanced Usage
|
|
148
293
|
|
|
149
|
-
|
|
294
|
+
### Segmentation Analysis
|
|
150
295
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
3. **Prioritized Fix Order** - Ranked by financial impact
|
|
154
|
-
4. **What Not To Fix** - Issues below threshold
|
|
155
|
-
5. **Decision Guidance** - Actionable recommendations
|
|
296
|
+
```typescript
|
|
297
|
+
import { analyzeBySegment, generateSegmentationMarkdown } from 'kanmi-perf-revenue';
|
|
156
298
|
|
|
157
|
-
|
|
299
|
+
const report = analyzeBySegment(sessions, 'device');
|
|
300
|
+
console.log(generateSegmentationMarkdown(report));
|
|
301
|
+
// Shows CVR breakdown by mobile vs desktop vs tablet
|
|
302
|
+
```
|
|
158
303
|
|
|
159
|
-
|
|
304
|
+
### Statistical Testing
|
|
160
305
|
|
|
161
306
|
```typescript
|
|
162
307
|
import {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
} from '
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
308
|
+
twoProportionZTest,
|
|
309
|
+
calculateConfidenceInterval,
|
|
310
|
+
calculateRequiredSampleSize,
|
|
311
|
+
} from 'kanmi-perf-revenue';
|
|
312
|
+
|
|
313
|
+
// Compare two groups
|
|
314
|
+
const test = twoProportionZTest('fast', 150, 5000, 'slow', 80, 4000);
|
|
315
|
+
console.log(`p-value: ${test.p_value}, significant: ${test.is_significant}`);
|
|
316
|
+
|
|
317
|
+
// Sample size planning
|
|
318
|
+
const required = calculateRequiredSampleSize(0.03, 0.1); // 3% baseline, detect 10% lift
|
|
319
|
+
console.log(`Need ${required.sample_size_per_group} sessions per group`);
|
|
320
|
+
```
|
|
173
321
|
|
|
174
|
-
|
|
175
|
-
site: 'datadoghq.com',
|
|
176
|
-
applicationId: 'rum-app-id',
|
|
177
|
-
});
|
|
322
|
+
### ROI Calculation
|
|
178
323
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const datadogData = await fetchDatadogData(datadog);
|
|
182
|
-
const result = runAnalysis(ga4Data, datadogData, siteTotals);
|
|
183
|
-
```
|
|
324
|
+
```typescript
|
|
325
|
+
import { calculateROI, DEFAULT_COSTS } from 'kanmi-perf-revenue';
|
|
184
326
|
|
|
185
|
-
|
|
327
|
+
const roi = calculateROI(
|
|
328
|
+
{ metric: 'lcp', currentValue: 3500, targetValue: 2500, description: 'CDN optimization' },
|
|
329
|
+
sessions,
|
|
330
|
+
{ ...DEFAULT_COSTS, engineeringHours: 40 }
|
|
331
|
+
);
|
|
186
332
|
|
|
187
|
-
|
|
333
|
+
console.log(`ROI: ${roi.roi.roiPercent}%, break-even: ${roi.roi.breakEvenDays} days`);
|
|
334
|
+
console.log(`Recommendation: ${roi.roi.recommendation}`);
|
|
335
|
+
```
|
|
188
336
|
|
|
189
|
-
|
|
190
|
-
- Funnel drop-off analysis
|
|
191
|
-
- Conversion path journeys
|
|
337
|
+
### Alerting
|
|
192
338
|
|
|
193
|
-
|
|
339
|
+
```typescript
|
|
340
|
+
import { generateAlertReport, DEFAULT_ALERT_CONFIG } from 'kanmi-perf-revenue';
|
|
194
341
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- Frustration signals
|
|
342
|
+
// Check current sessions against thresholds
|
|
343
|
+
const alerts = generateAlertReport(sessions, DEFAULT_ALERT_CONFIG);
|
|
198
344
|
|
|
199
|
-
|
|
345
|
+
// Optionally compare to baseline for regression detection
|
|
346
|
+
// const alerts = generateAlertReport(sessions, DEFAULT_ALERT_CONFIG, baselineSessions);
|
|
200
347
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
348
|
+
if (alerts.summary.critical > 0) {
|
|
349
|
+
console.log('CRITICAL ALERTS:', alerts.alerts.filter(a => a.severity === 'critical'));
|
|
350
|
+
}
|
|
351
|
+
```
|
|
205
352
|
|
|
206
|
-
|
|
353
|
+
### Export to Slack
|
|
207
354
|
|
|
208
|
-
|
|
355
|
+
```typescript
|
|
356
|
+
import { exportToSlack } from 'kanmi-perf-revenue';
|
|
209
357
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
358
|
+
const slackMessage = exportToSlack(result, { clientName: 'Acme Corp' });
|
|
359
|
+
// Send slackMessage.blocks to Slack API
|
|
360
|
+
```
|
|
213
361
|
|
|
214
|
-
|
|
215
|
-
npm run build
|
|
362
|
+
### Correlation Analysis
|
|
216
363
|
|
|
217
|
-
|
|
218
|
-
|
|
364
|
+
```typescript
|
|
365
|
+
import { calculateMetricImportance, generateCorrelationMarkdown } from 'kanmi-perf-revenue';
|
|
219
366
|
|
|
220
|
-
|
|
221
|
-
|
|
367
|
+
const importance = calculateMetricImportance(sessions);
|
|
368
|
+
console.log(generateCorrelationMarkdown(importance));
|
|
369
|
+
// Shows which metrics correlate most strongly with conversions
|
|
222
370
|
```
|
|
223
371
|
|
|
224
|
-
|
|
372
|
+
### Forecasting
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import { forecastRevenue, generateForecastMarkdown } from 'kanmi-perf-revenue';
|
|
225
376
|
|
|
377
|
+
const forecast = forecastRevenue(sessions, {
|
|
378
|
+
metric: 'lcp',
|
|
379
|
+
currentValue: 3500,
|
|
380
|
+
targetValue: 2500,
|
|
381
|
+
implementationMonth: 2,
|
|
382
|
+
});
|
|
383
|
+
console.log(generateForecastMarkdown(forecast));
|
|
384
|
+
// 12-month revenue projection with cumulative gains
|
|
226
385
|
```
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
│ ├── agent.ts # Claude agent
|
|
240
|
-
│ ├── config.ts # Configuration
|
|
241
|
-
│ └── tools/ # Agent tools
|
|
242
|
-
└── prompts/ # System prompts
|
|
386
|
+
|
|
387
|
+
### A/B Test Analysis
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { analyzeABTest, generateABTestMarkdown } from 'kanmi-perf-revenue';
|
|
391
|
+
|
|
392
|
+
// Sessions must have experiment_id and experiment_variant fields
|
|
393
|
+
const abReport = analyzeABTest(sessions, 'perf-optimization-test');
|
|
394
|
+
if (abReport) {
|
|
395
|
+
console.log(generateABTestMarkdown(abReport));
|
|
396
|
+
console.log(`Winner: ${abReport.winner?.name || 'No clear winner yet'}`);
|
|
397
|
+
}
|
|
243
398
|
```
|
|
244
399
|
|
|
400
|
+
## How It Works
|
|
401
|
+
|
|
402
|
+
1. **Bucket sessions by performance** — Group sessions into performance ranges (e.g., 0-1s, 1-2s, 2-3s LCP)
|
|
403
|
+
2. **Measure actual CVR per bucket** — Calculate conversion rate from your real data
|
|
404
|
+
3. **Calculate opportunity** — If slow sessions performed like fast sessions, how many more conversions?
|
|
405
|
+
4. **Prioritize by revenue impact** — Rank metrics by potential monthly revenue gain
|
|
406
|
+
|
|
407
|
+
No industry benchmarks. No assumed coefficients. Just your data.
|
|
408
|
+
|
|
409
|
+
## Why Empirical?
|
|
410
|
+
|
|
411
|
+
Traditional performance-revenue models assume fixed relationships like "0.5% CVR per 100ms LCP improvement." These assumptions:
|
|
412
|
+
|
|
413
|
+
- Come from other companies' data, not yours
|
|
414
|
+
- May not apply to your industry, audience, or product
|
|
415
|
+
- Create false precision
|
|
416
|
+
|
|
417
|
+
This tool measures the actual relationship in YOUR data. If your fast sessions convert 3.5% and slow sessions convert 2.1%, that's a 67% relative difference — measured, not assumed.
|
|
418
|
+
|
|
245
419
|
## License
|
|
246
420
|
|
|
247
421
|
MIT
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A/B Test Integration
|
|
3
|
+
*
|
|
4
|
+
* Compare performance variants and analyze their impact on conversions.
|
|
5
|
+
* Integrates with experiment data to determine if performance changes
|
|
6
|
+
* drove conversion improvements.
|
|
7
|
+
*
|
|
8
|
+
* @author Kanmi Obasa <i@kanmiobasa.com>
|
|
9
|
+
*/
|
|
10
|
+
import type { SessionData } from './datadog-session-query.js';
|
|
11
|
+
export interface ABTestVariant {
|
|
12
|
+
/** Variant identifier */
|
|
13
|
+
variantId: string;
|
|
14
|
+
/** Variant name/description */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Sessions in this variant */
|
|
17
|
+
sessions: number;
|
|
18
|
+
/** Conversions in this variant */
|
|
19
|
+
conversions: number;
|
|
20
|
+
/** Conversion rate */
|
|
21
|
+
cvr: number;
|
|
22
|
+
/** 95% confidence interval */
|
|
23
|
+
cvrCI: {
|
|
24
|
+
lower: number;
|
|
25
|
+
upper: number;
|
|
26
|
+
};
|
|
27
|
+
/** Average LCP */
|
|
28
|
+
avgLcp: number | null;
|
|
29
|
+
/** Average INP */
|
|
30
|
+
avgInp: number | null;
|
|
31
|
+
/** p75 LCP */
|
|
32
|
+
p75Lcp: number | null;
|
|
33
|
+
}
|
|
34
|
+
export interface ABTestComparison {
|
|
35
|
+
control: ABTestVariant;
|
|
36
|
+
treatment: ABTestVariant;
|
|
37
|
+
/** Absolute CVR difference */
|
|
38
|
+
absoluteDifference: number;
|
|
39
|
+
/** Relative CVR difference (treatment vs control) */
|
|
40
|
+
relativeDifference: number;
|
|
41
|
+
/** p-value from z-test */
|
|
42
|
+
pValue: number;
|
|
43
|
+
/** Is statistically significant at alpha=0.05? */
|
|
44
|
+
isSignificant: boolean;
|
|
45
|
+
/** Effect size (Cohen's h) */
|
|
46
|
+
effectSize: number;
|
|
47
|
+
/** Performance comparison */
|
|
48
|
+
performanceComparison: {
|
|
49
|
+
lcpDelta: number | null;
|
|
50
|
+
inpDelta: number | null;
|
|
51
|
+
/** Did performance improve? */
|
|
52
|
+
performanceImproved: boolean;
|
|
53
|
+
};
|
|
54
|
+
/** Recommendation */
|
|
55
|
+
recommendation: 'ship_treatment' | 'keep_control' | 'need_more_data' | 'inconclusive';
|
|
56
|
+
rationale: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ABTestReport {
|
|
59
|
+
experimentId: string;
|
|
60
|
+
variants: ABTestVariant[];
|
|
61
|
+
comparisons: ABTestComparison[];
|
|
62
|
+
winner: ABTestVariant | null;
|
|
63
|
+
sampleSizeAnalysis: {
|
|
64
|
+
currentSamples: number;
|
|
65
|
+
requiredSamples: number;
|
|
66
|
+
isSufficient: boolean;
|
|
67
|
+
daysToSignificance: number | null;
|
|
68
|
+
};
|
|
69
|
+
insights: string[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Analyze an A/B test from session data.
|
|
73
|
+
*/
|
|
74
|
+
export declare function analyzeABTest(sessions: SessionData[], experimentId?: string): ABTestReport | null;
|
|
75
|
+
/**
|
|
76
|
+
* Create a synthetic A/B test by splitting sessions on performance.
|
|
77
|
+
*/
|
|
78
|
+
export declare function createPerformanceExperiment(sessions: SessionData[], metric: "lcp" | "inp" | "cls" | undefined, threshold: number): ABTestReport;
|
|
79
|
+
/**
|
|
80
|
+
* Generate markdown report for A/B test.
|
|
81
|
+
*/
|
|
82
|
+
export declare function generateABTestMarkdown(report: ABTestReport): string;
|
|
83
|
+
//# sourceMappingURL=ab-testing.d.ts.map
|