Skip to content

Cohort statistics

Where Explainability reads a single visitor, the cohort view aggregates content engagement across all visitors: which items are seen, liked, and abandoned, which themes are popular, and what each cluster prefers. It is the Content tab of the Inspector, backed by one endpoint.

Endpoint: GET /api/content/stats (PII-guarded by INGEST_API_KEY). It folds over every materialized user model (UserModelStore.iter_signals), so it is cohort-wide with no extra instrumentation.

What it returns

Field Meaning
users number of materialized user models folded in
content per-item rows: views, likes, dislikes, like_rate, sorted by views then likes
themes popular taxonomy themes, summed tag_affinity weight across visitors (top 15)
clusters per-cluster content preferences (top liked content + top themes), when a cluster model is loaded

like_rate is likes / views per item (0 when unseen). Themes and per-cluster labels strip the facet prefix, so theme:forced_labour reads as forced_labour.

{
  "result": {
    "users": 42,
    "content": [
      {"content_id": "841", "title": "...", "views": 30, "likes": 18, "dislikes": 2, "like_rate": 0.6}
    ],
    "themes": [["forced_labour", 12.4], ["resistance", 8.1]],
    "clusters": [
      {"cluster": 0, "size": 11,
       "top_content": [{"content_id": "841", "title": "...", "likes": 9}],
       "top_themes": [{"label": "forced_labour", "weight": 4.2}]}
    ]
  }
}

Per-cluster content

When CLUSTER_MODEL_PATH is set, the endpoint walks each cluster's member users and rolls up their liked content and tag affinity. This pairs the explainable segments (see Explainability -> clusters) with the concrete content each segment engages, so a segment such as "Forced Labour + Resistance, narrow" is shown alongside the actual stories its members liked.

Where it appears

The Inspector Content tab renders this directly: a sortable content table, a popular-themes list, and a content-preferences card per cluster.