No dashboard renders a number it computed itself. Everything traces back to one offline pipeline and one pinned artifact set. This page explains that pipeline and defines the terms.
Six stages turn a flat event log into the artifacts this site reads.
The raw event log is read once through DuckDB and written to a column-trimmed Parquet. Nothing loads the whole table into memory.
build_all() derives dim_users, dim_products, fact_sessions, fact_daily_kpis, plus the RFM, affinity, and retention tables.
Every user with pre-November activity is scored by the frozen LightGBM model. The bulk pass is prediction-identical to per-user scoring.
Product pairs bought in the same session are counted, filtered by support and lift, and keyed for lookup in both directions.
The A/B engine runs across a segment by lift by confidence grid so the experiment page can check its live math against fixed points.
Each output is written as byte-deterministic JSON, keyed by commit. The frontend build pins one set and refuses to build without it.
Table sizes for this build. Every figure elsewhere on the site aggregates one of these.
1,645,912 source events
Each choice earns its place by removing a moving part, not adding one.
| Layer | Choice | Why |
|---|---|---|
| Query engine | DuckDB | In-process column store. Runs the pipeline offline and the explorer in the browser from the same SQL. |
| Pipeline | Python, DuckDB SQL, LightGBM | SQL for the joins and aggregations, LightGBM for the purchase model, one script to produce every artifact. |
| Artifacts | Versioned JSON and Parquet | Byte-deterministic output keyed by commit. The frontend build pins one set and fails if it is missing. |
| Frontend | Next.js App Router, static export | Prerendered HTML on a CDN. No server on the request path, so no cold start. |
| Charts | Recharts and hand-built SVG | Recharts for standard series, custom SVG for the cohort grid and funnel where a library would fight the design. |
| In-browser SQL | DuckDB-WASM | Ad-hoc queries over the trimmed event log without shipping the data through a backend. |
Terms used across the site, with what each one means for this dataset.
An embedded column-store built for analytical queries. It runs in-process with no server, the way SQLite does for transactional work.
On this data: The build pipeline uses it to turn the raw event log into a star schema. The data explorer runs the same engine compiled to WebAssembly, directly in your browser.
A warehouse layout that splits data into fact tables (measurements, one row per event or per day) and dimension tables (attributes of a user or product). Queries join a fact to a few dimensions.
On this data: dim_users and dim_products hold attributes; fact_sessions and fact_daily_kpis hold the measurements. Row counts are on the method page.
Grouping a user's sequential events into visits. Here a visit is one server-assigned session id.
On this data: The event log collapses into fact_sessions, one row per visit, carrying duration, event count, and whether the visit ended in a purchase.
A segmentation that scores each buyer on how recently they purchased, how often, and how much they have spent, then names groups from the score pattern.
On this data: Each metric is bucketed into fifths with NTILE(5). Recency is inverted so a recent buyer scores high. Segment names come from the recency and frequency scores; spend is reported per segment but does not drive the name.
A SQL function that splits ordered rows into N equal-sized buckets. NTILE(5) produces quintiles.
On this data: Used to turn raw recency, frequency, and spend into 1 to 5 scores for RFM.
Group users by the week they first appeared, then track what share is still active in each later week. It separates a discovery problem from a lifecycle problem.
On this data: The retention grid on the user intelligence page is built from weekly_retention. Week 0 is always 100 percent by construction.
A model that estimates the probability a user buys in the next period from their past behavior.
On this data: A LightGBM classifier trained on a temporal split: October behavior predicts a November purchase. Its card and drivers are on the propensity page.
A gradient-boosted decision tree library. It grows trees leaf-wise and handles class imbalance well, which suits a low base-rate target like purchase.
On this data: The frozen model is a raw Booster loaded from LightGBM's native text format. Predictions are identical whether it loads from that or the legacy pickle.
The probability that the model ranks a random buyer above a random non-buyer. 0.5 is a coin flip, 1.0 is perfect ranking.
On this data: Reported on held-out users on the propensity page, straight from metrics.json.
The conversion rate of a top slice of the ranked population divided by the overall rate. A lift of 3 means that slice converts three times as often as average.
On this data: Measured on the top five percent of users by predicted propensity.
For a pair of products, the chance they are bought together divided by what you would expect if the two were independent. Above 1 is a real affinity.
On this data: Product pairs are mined from co-purchases in the same session. The affinity table keeps pairs with at least three co-occurrences and lift above 1.2.
A two-sample test of whether two means differ that does not assume the groups have the same variance. Standard for A/B conversion comparisons.
On this data: The experiment calculator runs it on the two arms' conversion outcomes, matching the Python engine within rounding.
The chance a test detects a real effect of a given size. Teams usually aim for 0.8 before running an experiment.
On this data: Computed post-hoc for each calculator run and precomputed across a segment by lift by confidence grid.
scope The site describes the 2019-10-01 to 2019-11-30 sample: 1,645,912 events and 135,767 users. It is not the full multi-month source, and the aggregate figures scale with that.
model The propensity model is a frozen artifact. Its card on the propensity page reports 0.75 AUC and 4.6x top-5% lift as trained, and those values do not change when the sample does.
freshness There is no live data. A new pipeline run produces a new artifact set under a new commit, and a redeploy picks it up.