How it works
Architecture
Pipeline freshness
Live from /api/stats. Measured against the latest snapshot date, not the dbt run — a rebuild over failed ingestion still reads as stale.
The dbt DAG
Staging views normalize raw ingestion tables. Marts do the general-purpose analytical joins. The api/ layer is narrow, pre-joined, and pre-indexed on purpose — the app never queries the marts directly.
stg_artist_snapshots— one row per artist per weekstg_weekly_charts— chart page/rankstg_genre_artists— artist ↔ genre tag
int_artist_base— profanity filter applied once, at the source
artist_growth_summary— first/last listener counts, total growthartist_tiers— mainstream / indie / unranked, left-joined so ~17k uncharted artists still get a profilelistener_growth— week-over-week deltasgenre_stats— per-genre aggregates
api_artist_profile— one narrow, pre-joined, pre-indexed row per artistapi_artist_timeseries— listeners_indexed to 100 at first observationapi_cohort_weekly— precomputed median/p25/p75 per cohort per week
Methodology & caveats
Listener counts are cumulative all-time, not active listeners — Last.fm's artist.getInfo returns a running total, so "growth" here means new scrobblers discovering an artist, not a change in how many people are currently listening. This can only go up.
Headline finding: median 13-week growth falls monotonically with starting listener size — 2.67% / 2.46% / 2.10% / 1.76% / 1.71% from smallest to largest quintile, across 22,201 artists. An earlier claim that growth increases with chart page depth was retracted after re-analysis — smaller starting size, not chart depth, is what predicts higher growth.
Chart survivorship: the mainstream/indie split comes from a chart snapshot that is now fully seeded (all 10,000 ranked artists), but the remaining ~17,000 tracked artists were seeded via genre tags or the similarity graph and never had a chart position — "unranked" is an observation gap, not a popularity tier, which is why cohorts here are built on listener-size bands rather than chart tier.
Self-reported tags: genres come from Last.fm user tagging, not a curated taxonomy — expect noise and overlapping labels.
Two early snapshot dates are excluded from cross-artist aggregates: 2026-04-27 and 2026-05-03 cover different, non-overlapping populations of artists rather than a full weekly panel; every aggregate here is computed from 2026-05-10 onward.
Source
Full repo, including the ingestion scripts, dbt project, and this app, is on GitHub.