Read the Analytics Dashboard cohort retention matrix
GET benecaster-analytics/v1/analytics/cohort groups subscribers by the UTC calendar month they first joined, and counts how many of each month were still subscribed at the end of the join month and of each month after. It takes show_id, date_from, date_to and an optional scope (show, the default, or all), with the same permission and errors as the other Analytics Dashboard routes (see Read or extend the Analytics Dashboard growth series and Read every Analytics Dashboard route for All my shows); a tier_slug is accepted and ignored. Cohorts are whole months: every month the range touches, so a range starting on the 15th counts that month’s joins from the 1st (cohort_from says where it began). On Benecaster’s admin page the add-on publishes its own REST base as window.benecasterAnalyticsDashboard.apiUrl, which works under every permalink setting.
retained[0]is the end of the join month and each later entry a month later; the last entry of every row ends ondate_to, not on the month’s last day. Later cohorts have shorter rows.retained_pctis a percentage ofsize, one decimal, andnullfor a cohort of 0.- A join is a
joinedevent, or asyncedevent withsource = 'bridge_sync'on the member’s real start. A follower who starts paying has a secondjoinedrow and stays in the cohort of their first.churnedends a subscription andreactivatedbrings it back;licence_gracerows are the podcaster’s licence, not the subscriber, and change nothing. - The matrix is approximate, and
notessays by how much:synced_undated(members linked with no start date, never in a cohort),join_not_on_record(a subscriber whose history in the range does not start with a join: pruned by a retention period, or older than the log), anderased_joins/erased_churns(rows an erasure unlinked from their subscriber, which cannot be paired). Say so beside any matrix you draw. - Change the matrix for every caller with the
benecaster_analytics_cohortfilter. Its$argsareshow_ids,date_from,date_toandtier_slug(alwaysnull); a non-array return is ignored.
Code
const url = window.benecasterAnalyticsDashboard.apiUrl
+ 'analytics/cohort?show_id=12&date_from=2026-05-01&date_to=2026-10-28';
const matrix = await ( await fetch( url, { headers: { 'X-WP-Nonce': window.benecasterAdmin.nonce } } ) ).json();
// matrix.columns → 6
// matrix.cohorts[0] → { month: '2026-05', size: 40, retained: [ 38, 35, 33, 31, 30, 30 ], retained_pct: [ 95, 87.5, 82.5, 77.5, 75, 75 ] }
Hooks Used
Need this built rather than just documented? See our services →