Skip to main content

Creator Analytics — Technical Reference

← Back to Creator Analytics

The dashboard is mostly a composition of analytics that already existed on the backend (earnings summary, earnings-by-source, exclusive-post earnings, subscriber count), plus several genuinely new backend queries added across passes: a daily earnings time series (Fase D.4 / roadmap 4.12), monthly subscriber retention/churn, and a calendar-year earnings statement. The page it replaces was an honest stub that declared creator analytics had "no backend support"; that was already out of date.

Where this lives

Backend

Frontend

Technical implementation checklist

  • myEarningsTimeSeries(days) — query/resolver/manager/access-service, zero-filled daily series; EarningsTrendChart.tsx
  • Exclusive post sales — surfaces myPostPurchaseEarnings (backend already existed; no frontend consumer before)
  • Active subscriber count — surfaces subscriberCount(creatorId)
  • Reused earnings summary + by-source cards
  • Subscriber retention time-series — subscriberRetention(months) query/resolver/manager, 6-month bar chart + churn on InsightsAndToolsPage.tsx
  • Per-buyer sales view — myPostPurchaseSales surfaced via a client-grouped "Top buyers" list on CreatorSalesPage.tsx (/settings/sales)
  • CSV export — client-side only (handleExportCsv in InsightsAndToolsPage.tsx); no dedicated export query
  • Annual earnings statement — myEarningsStatement(year) via EarningsStatementCard.tsx, also rendered on this page (primary docs under Payouts)

GraphQL API

# Daily earnings trend, zero-filled, last N days (default 30, max 365)
query MyEarningsTimeSeries($days: Int) {
myEarningsTimeSeries(days: $days) {
date # YYYY-MM-DD
earnings # coins earned that day
}
}

# Monthly subscriber retention/churn, oldest -> newest (default 6 months, max 24)
query SubscriberRetention($months: Int) {
subscriberRetention(months: $months) {
month # YYYY-MM
newSubscribers
churned
activeAtEnd
churnRate # percent
retentionRate # percent
}
}

# Reused on the dashboard
query DashboardExtras($creatorId: ID!) {
myEarningsSummary { availableForCashout unmaturedRecentEarnings }
myEarningsBySource(days: 30) { tips contentSales profileSubscriptions groupSubscriptions marketplace other }
myPostPurchaseEarnings { totalSales totalRevenue totalEarnings platformFees }
myPostPurchaseSales(limit: 20, offset: 0) { id coinPrice sellerEarningsCoins status createdAt buyer { id username } }
subscriberCount(creatorId: $creatorId)
myEarningsStatement(year: 2026) { totalEarnings tips contentSales profileSubscriptions groupSubscriptions marketplace other totalCashedOut }
}

Notes

  • Earnings definition is shared. Both myEarningsBySource and myEarningsTimeSeries count the same transaction types as "earnings," so the trend total and the by-source total agree for a given window. Coin purchases and admin-granted bonuses are excluded from the trend (they'd otherwise show up as spurious spikes).
  • Zero-filling happens in the manager, not SQL — the access-service returns only days with earnings, and getEarningsTimeSeries in the manager expands that into a continuous day-by-day array. This keeps the query cheap while giving the chart a clean axis.
  • Retention buckets are computed in application code, not SQL — getSubscriberRetention pulls the creator's full UserSubscription history once (getAllByCreatorForAnalytics) and buckets it into calendar months in JS. "Active at end" for a month counts subscriptions created before the bucket's end and not cancelled before it; churn rate is churned-in-month over active-at-start.
  • CSV/statement exports are client-side. The "Exportar CSV" button on Insights & Tools and the statement download on EarningsStatementCard both build their file (CSV / plain text) from already-fetched query data in the browser — there's no server-side export endpoint or file storage involved.