Events & analytics
Impressions, interactions, weights, and CTR.
03 - Events, weights & analytics
Related: Case study - Driffle CTR · Appendices SQL
Event types
Interactions (recomnext.interactions)
type | Typical meaning | Default event weight |
|---|---|---|
view | Product/page engagement (SDK trackView, widget card click often sends view) | 1.0 |
cart | Add to cart (trackCart) | 1.0 |
purchase | Purchase (trackPurchase) | 1.0 |
rating | Explicit rating (if integrated) | 1.0 |
Important fields:
| Field | Role |
|---|---|
tenant_id | Isolation |
user_id | Actor (may be sess_… anonymous) |
item_id | Catalog externalId |
session_id | Optional |
type | view/cart/purchase/rating |
weight | Per-event multiplier (usually 1) |
scenario_slug | Attribution to a scenario (empty = site-wide / unattributed) |
event_time | When it happened |
Impressions (recomnext.impressions)
One row per item shown (API accepts itemIds[]; engine expands to rows).
| Field | Role |
|---|---|
tenant_id, user_id, item_id, session_id | Same ideas as interactions |
scenario_slug | Placement attribution (required for scenario funnel analytics) |
event_time | When shown |
Impressions are usually fired by IntersectionObserver when a rail card is ≥ ~50% visible.
How events are stored (path)
- Writes are async (202 accepted → Kafka → CH). Slight delay before metrics update is normal.
- Behavioral recommenders read CH with windows like 30 days (purchase cap uses 90 days).
Weights - two layers
1) Event weight field
Optional float on each interaction (default 1.0). Rarely changed by hosts today.
2) Type multipliers (weighted-history algorithm)
When scoring a user’s history, the engine computes:
sum(
weight * multiIf(
type = 'purchase', 4,
type = 'cart', 2,
type = 'rating', 3,
1 -- view and anything else
)
) AS total_weight
…over the last 30 days, grouped by item_id, for that user_id.
| Type | Multiplier |
|---|---|
| purchase | ×4 |
| rating | ×3 |
| cart | ×2 |
| view (default) | ×1 |
These multipliers are code defaults for weighted-history. They are not Admin scenario toggles today. Changing them requires an engine change.
Worked micro-example
User U in 30d:
| Item | Events |
|---|---|
| A | 3 views (weight 1) |
| B | 1 cart + 1 view |
| C | 1 purchase |
Scores:
- A:
3 × 1 × 1 = 3 - B:
1×2 + 1×1 = 3 - C:
1 × 4 = 4→ ranks first
Popular fallback (cold start): if the user has too few personal items, the algo also pulls 7-day global popular items (by event count) with score 0.5 when they lack personal weight.
Analytics formulas (Admin scenario summary)
For scenario slug X, last N days (default 30):
| Metric | Definition |
|---|---|
| Impressions | count() from impressions where scenario_slug = X |
| Clicks | count() from interactions where scenario_slug = X and type = 'view' |
| Carts | same table, type = 'cart' |
| Purchases | same table, type = 'purchase' |
| CTR % | round(10000 * clicks / impressions) / 100 if impressions > 0 |
| Cart rate % | carts / impressions |
| Conversion % | purchases / impressions |
Dev snapshot (driffle-dev, ~30d, as of 2026-07-23)
| Interaction type | Count | Avg event weight |
|---|---|---|
| view | 114,554 | 1.0 |
| cart | 17 | 1.0 |
| purchase | 13 | 1.0 |
For scenario pdp-similar-products:
| Impressions | “Clicks” (view+slug) | CTR |
|---|---|---|
| 48,696 | 114,385 | 234.9% |
Why >100% is possible: 09 - Case study.
Attribution rules of thumb
| Do | Don’t |
|---|---|
Send impressions with scenarioSlug when cards are shown | Assume widget click alone creates scenario CTR |
Send trackView / cart / purchase with the same slug only when the action is attributable to that placement | Stamp every PDP view with the PDP scenario slug |
Keep stable userId / merge identity after login | Compare CTR across scenarios with different instrumentation |
Site-wide history (empty scenario_slug) still feeds behavioral algos; it simply does not appear in per-scenario funnel endpoints.
Identity
- Anonymous browse often uses
sess_…ids. - After login,
mergeIdentity(authenticatedUserId)merges session history into the user. - Broken merge → fragmented history → weaker
user-to-item/ purchase-cap behavior.
