Skip to main content
Getting Started

Analytics Guide

How coach, club, and platform analytics and period reports work.

Engineering reference: the canonical, code-anchored source of truth for every metric below — including the helper function each surface calls, the exact SQL filters, and the cross-surface reconciliation contract — lives in `docs/metrics-canonical-definitions.md`. Live reconciliation proofs against the staging database are in `docs/metrics-reconciliation-proofs.md`. The cross-helper assertion suite is tests/metrics-reconciliation.test.ts. These three artefacts together are the reconciliation gate that must remain green before the reporting suite ships.

Overview

AllSquads provides analytics dashboards for coaches, clubs, and AllSquads admins. Analytics are updated in real time and cover revenue, bookings, attendance, and player retention.

Note (in progress): the dashboard home (/dashboard) and dedicated analytics surface (/dashboard/analytics) are being split — action-oriented widgets stay on the home page, deeper analytics tabs move to /dashboard/analytics. Until that ticket ships, the analytics tabs described below may render under the existing /dashboard route.

Period presets

Every period filter in the product uses the same calendar preset set — the dashboard home "Showing" selector (club + coach), the Club Analytics range selector, the coach Analytics date selector, the platform-admin Analytics range, the admin Payouts bulk export, and the club Payouts CSV export range (where the date inputs remain available for a custom range). The presets are calendar periods, not rolling windows:

  • This week — Monday–Sunday containing today (club timezone)
  • Last week — the previous Monday–Sunday week. Matches the Reports weekly view and that week's payout batch exactly.
  • Month to date — 1st of the month → today
  • Last month — the full previous calendar month
  • Quarter to date — quarter start (Jan/Apr/Jul/Oct) → today
  • Year to date — 1 January → today
  • Last 12 months — the last 12 calendar months

Weeks are Mon–Sun in the club's timezone, the same convention Reports and payout batches use — so Dashboard, Analytics, Reports, and Payouts are directly comparable for the same period. The Reports prev/next navigation anchors on the club-local today as well, so "this week" in Reports always equals the "This week" preset. On the Facility Hire tab, every widget — KPI cards, revenue trend, utilisation heatmap, per-court table, and court drill-downs — covers the selected calendar window, and the heatmap header names the active period.

Period comparisons

KPIs render with delta arrows (▲ green / ▼ red) comparing against the previous equivalent calendar period: this week vs last week, month-to-date vs the same day-span of last month, year-to-date vs the same day-span of last year, and so on. Each delta is labelled with the period it compares against.

Exports

  • CSV transaction export — available from the Payments tab on coach and club analytics. Exports the filtered transaction list as a downloadable CSV.
  • Payout PDF report — each completed payout has a downloadable PDF receipt summarising the included transactions and the payout amount. Available from the Payouts tab.

Coach Analytics

Revenue

  • Total revenue by period (day, week, month, custom range)
  • Revenue by class
  • Revenue by sport
  • Gross revenue vs net payout (after the platform fee deducted at payout time)

Bookings

  • Total bookings by period
  • New vs returning player bookings
  • Booking type breakdown (full term, drop-in, one-off, private lesson)
  • Waitlist conversion rate

Participations vs Bookings

The Bookings Trend chart shows two lines: Bookings (the number of sales made, one per booking — a family that books an 8-week term counts as one booking) and Participations (one for every player at every class session inside that month — the same 8-week term family counts as 8). Participations is about growth and how much your roster is actually attending or booked in for, not revenue — it never changes how much money a booking is worth, and it counts a session whether it has already run or is still coming up within the month shown.

Attendance

  • Overall attendance rate
  • Attendance rate by class
  • No-show rate
  • Late cancellation rate (within policy window)

Class performance

  • Revenue per class
  • Attendance rate per class
  • Capacity utilisation per class
  • Sessions delivered vs sessions cancelled

Club Analytics

Club analytics extend coach analytics across all coaches and add court hire and financial reporting.

Summary KPI row

The Analytics → Summary tab opens with cards for the selected period: Club Revenue, Total Bookings, Active Staff, Active Squads and Participations.

  • Active Staff — the number of people on your team who ran at least one session in the selected period. Every staff role counts (owners, admins, head coaches, coaches and hosts), each person is counted once even if they hold more than one role, and a team member is only counted when they actually ran a session that completed inside the period — the person assigned to the session, or the class's head coach when no one else was assigned. Someone on the roster who ran nothing that period is not counted, and an unbooked private-lesson slot does not count as a session run. With the period comparison on, the delta compares against the same measure over the previous period. The card's subline reads "Staff who ran a session this period".
  • Participations — every player, at every non-cancelled class session inside the selected period, counted once each. Unlike Total Bookings (which counts sales — one per booking, however many sessions it covers), Participations counts actual class attendance/enrolment: a family on an 8-week term booking counts as 8, not 1, and a weekly class with sessions still to come this period counts those upcoming sessions too. It is a growth and engagement measure, never a money figure — Club Revenue and Total Bookings are unaffected by it.

Revenue

  • Total club revenue by period
  • Revenue by coach
  • Revenue by class type
  • Court hire revenue
  • Membership revenue
  • Session pack revenue
  • Fee breakdown (booking fee paid by players at checkout vs platform fee deducted at payout)

Club Revenue composition

"Club Revenue" on the Analytics → Summary tab is the headline KPI. It is the sum of the received-payment streams over the selected period:

Club Revenue = Class income + Court hire + Private lessons + Memberships + Pro shop
  • Class income — class bookings with status confirmed or completed where money was actually received: paid online (Stripe, account credits, or a paid Stripe payment link) or collected offline (cash, or marked "already paid" outside the platform). Free/complimentary bookings, club-internal bookings, and session-pack redemptions (the pack purchase already counted) are not revenue and are excluded. When part of a booking is cancelled and the player gets account credit back, the credited amount is not counted here: it counts once, when the credit is spent on another booking. A seat the coach or the club cancels is not counted either. The previous breakdown split this into "Stripe (Online)" and "Cash Paid", but court hire can also be paid via Stripe — so the rail axis was the wrong partition for the top-level Club Revenue split. Stream axis (Alex 2026-06-07) is canonical for that split and is unchanged. Alex 2026-07-19 ruling: the Class income tile on the Summary Revenue Breakdown card additionally shows an "Online (Stripe) $X · Cash $Y" sub-line decomposing the Class income figure by payment rail — mirroring the Financials tab's existing rail split. This is a sub-split of Class income only (stripePaid + cashPaid === classIncome); it does not reintroduce rail as the top-level partition and Court hire/Memberships/Pro shop are not rail-split.
  • Subscriptions vs Drop-in online (Alex Option A ruling, 2026-07-20): nested one axis deeper than the rail split, under the "Online (Stripe)" figure specifically, the card shows a "↳ Subscriptions $A · Drop-in online $B" line splitting the online rail by payment MODEL rather than payment method. Subscriptions is the sum of paid weekly subscription_payment_rows invoices (recurring class-subscription charges, recognised on the date each invoice was charged). Drop-in online is every other online class payment — single-session drop-ins, term-upfront lump sums, camps, one-off bookings — anything paid online that isn't a recurring subscription invoice. Drop-in online is derived, not independently computed: dropInOnlineRevenue = stripePaid − subscriptionsRevenue, so Subscriptions + Drop-in online === Online (Stripe) always, by construction, regardless of data shape. Coach-side analytics (/dashboard/coach/analytics/revenue-split) surfaces subscriptionsRevenue as an additive field for parity but does not derive a coach-side drop-in-online figure — coach stripePaid has never included subscription money (a pre-existing, separate gap from the club-side figure).
  • Court hire — court hire bookings with status confirmed (price collected at booking time). A coach's private-lesson court booking is not court hire: it is counted on its own line below.
  • Private lessons — the paid private-lesson court bookings (a lesson added from Schedule > Add booking, one-off or repeating). They are part of Club Revenue and Reports on their own Private lessons line, so Court hire + Private lessons equals everything the court bookings brought in. The Court Hire tab's cards, per-court revenue and revenue trend show court hire only. Court utilisation, the heatmap and per-court booking counts still include lessons, because a lesson still uses the court.
  • Memberships — membership purchases, counted on their payment date (memberships have no session to recognise against). Memberships are platform-held like every other Stripe payment and settle through the same weekly payout batch. They appear as their own line in the Summary Revenue Breakdown card and squad-type donut, the Financials tab (Membership Revenue KPI + monthly column), Reports (both Performance and Payout views, with their own breakdown row), Top Squads (reconciling row) and the club Payouts page Current payout figure.
  • Pro shop — pro shop product purchases paid online, counted on their payment date (pro shop orders have no session to recognise against, same basis as memberships). Pro shop sales are platform-held and settle through the same weekly payout batch. They show their revenue and order count on the Summary Revenue Breakdown card and appear as a "Pro Shop Revenue" KPI plus monthly column on the Financials tab, and in the club Reports + weekly payout breakdown.
  • Competitions — paid competition entries at the entry price, counted on the competition's start date. The booking fee is an AllSquads fee, not club revenue. A withdrawn entry, an entry still awaiting approval, or a cancelled competition counts $0. On the Financials tab they appear as a Competitions tile and, once any month has entries, a Competitions column in the Monthly Financial Summary (and its CSV export), so every month's Total equals its columns.

Cash Outstanding (pending cash bookings) is not counted in Club Revenue — it is promised money, not received. It is shown beneath the Revenue Breakdown card as "Cash Outstanding (not in Club Revenue)" and will roll into Club Revenue once the cash is collected and the booking flips to confirmed.

The Revenue Breakdown card on the Summary tab renders the stream components side by side with a "Subtotal = Club Revenue" reconciliation row so the tiles visibly add up to the headline. On the free plan, the Revenue Breakdown card and the Court Hire summary card are not shown on the Summary tab — that stream split is part of full analytics — while the Club Revenue tile itself keeps showing the recognised headline figure regardless of plan.

Note: Analytics surfaces (Summary / Classes / Players / Court Hire / Team / Financials tabs) are Performance / accrual — revenue is counted on the recognition date per BOOKING_RECOGNITION_DATE_EXPR (a booking's earliest booked session). Camps recognise on the camp START day (per-day camps recognise daily; a whole-camp booking recognises in full on the start day), superseding the earlier end-of-camp rule. Cash payouts (money settled to your Stripe account) live on /dashboard/payments and on /dashboard/reports → Payouts section, and use the booking-date (cash) basis. The two bases answer different questions and will not match for any window where bookings span the period boundary — this is by design.

Forecast vs Actual on the monthly Revenue chart (2026-09): because revenue recognises on a booking's session date, the MONTHLY chart can legitimately show a bucket for a future month — a term whose first session lands next month recognises its whole (lump-sum) amount then, even though it was booked and paid today. To keep that from reading as an error, the chart draws a future month's bar as a hatched Forecast segment (a texture over the same Actual colour, not a new colour) instead of solid Actual, and the in-progress current month splits into its own already-happened (Actual) portion plus whatever is still to come this month (Forecast) when the split can be computed. The chart legend names both; hovering a bar states which segment its dollars belong to. No total changes — this only recolours dollars that were already on the chart. Weekly buckets and the compare ("vs previous period") view are unaffected.

Pre-cutover "paid direct" annotation: payments charged before the platform-held cutover were destination charges — the money went straight to the club's Stripe account and is not in the weekly payout batch. On the Reports Payout (cash) view those amounts are flagged with a badge — "$X paid direct (pre-cutover) — not in weekly batch" — so a window whose Performance revenue exceeds its batch payout is explained, not silent.

Bookings

  • Total bookings across all classes
  • New player acquisition (first booking per player by period)
  • Player retention (players with 2+ bookings vs single-booking players)
  • Repeat booking rate
  • Booking type distribution

Court hire utilisation

  • Total court hire bookings by period
  • Utilisation rate per court (booked hours vs available hours)
  • Revenue per court
  • Member vs non-member court hire breakdown
  • Peak usage times (by hour of day, day of week)

Attendance

  • Club-wide attendance rate
  • Attendance by coach
  • Attendance by class
  • No-show and late cancellation rates

Contacts and CRM

  • Total active contacts
  • New contacts by period and source (booking, manual, import)
  • Contacts by sport
  • Contacts with active membership
  • Credit balances outstanding

Financial

  • Gross revenue vs net payout
  • Refunds and credits issued
  • Outstanding credits liability
  • Payout history

Reports (period rollups)

Clubs have a dedicated reporting surface at Dashboard → Reports (/dashboard/reports) — separate from Analytics. Reports answer "how am I tracking over time?" with calendar-aligned period rollups, while Analytics is for real-time exploration and ad-hoc filtering.

Tabs

  • Weekly — current ISO week (Monday–Sunday) + 11 prior weeks of trend.
  • Monthly — current calendar month + 11 prior months of trend.
  • Quarterly — current calendar quarter (Q1=Jan–Mar … Q4=Oct–Dec) + 7 prior quarters.
  • Financial year — current AU FY (1 July → 30 June) + 4 prior FYs.

Per tab

  • Summary cards: Total revenue, Cash collected, Bookings, Players, each with the previous-period delta (WoW / MoM / QoQ / YoY). Total revenue composition is Stripe + Cash + Court Hire (same canonical definition as the Analytics → Summary tab).
  • Trend chart: Bars of total revenue across the trend window. Used to spot growth / decline at a glance.
  • By squad type table: Players, bookings, cash, revenue broken down by effective squad type (Group / Social / Term / Private / Camp / Court hire). Uses the same deriveSquadType rules as the Squad-type donut on Analytics so Term bookings with legacy squad_type='group' bucket correctly.
  • Classes this period table: Per-class revenue, cash, bookings, players for the active window.
  • Drill-down: Click "View bookings" on any row → drawer with per- booking detail (player, class/court, payment, amount). Drawer reuses the /financials/revenue-breakdown endpoint scoped to the active window so the numbers reconcile with the row clicked.
  • Export (PDF / CSV): download the active period as a PDF summary or a CSV of every line item. Membership and pro shop payments appear as their own rows in the CSV (membership / pro_shop), alongside class bookings and court hire, so the file's totals always match its rows.

Reconciliation

Reports figures reconcile with the Analytics → Summary tab Club Revenue for the same period. The route enforces summary.payoutCents === sum(bySquadType.payoutCents) (invariant — historic field name retained for backwards-compat; the field now carries gross revenue) before responding; mismatches surface as a "Reconciliation warning" banner on the report (also logged server-side for follow-up). Terminology is aligned so the "Reconciles" badge matches the Summary tab the operator compares against. Reports' class-income figures (Summary cards, By squad type table, Classes this period table) now exclude complimentary/internal/pack bookings using the same payment-method partition Summary uses — pre-fix Reports and the Financials tab both counted that money while Summary didn't, so the two "reconciling" surfaces agreed with each other but disagreed with the Summary tab they claim to reconcile with.

Two ways to read your money: Performance and Payout

Every money figure on AllSquads is one of exactly two things, and each one is labelled so you always know which you are looking at.

  • Performance — revenue for the classes that RAN in the period. A term counts on the day of its first session; camps count per the camp's own rule; everything else counts on the day the session ran. This is the "how is the business doing?" number, and it is what Analytics' money cards, the Reports Performance summary and the "Revenue over time" bars all show.
  • Payout — the money actually paid to your bank for that period's payout batch, including any correction top-ups and any carried-over amounts from the old platform. This is what the Payouts tab and drawer, the Reports Payout summary and the "Payouts over time" bars show, and it always equals the transfer that reached your account.

Two surfaces showing the same view for the same period will show the same number to the cent. If they ever do not, that is a bug — please report it.

The two views legitimately differ for the same week, and that is the point: cash you collected yourself is revenue but never lands in a transfer, credits pay for a place without new money arriving, and a week that has run may not have been paid out yet.

Counts follow the same discipline. "Players" on a payout means DISTINCT PEOPLE — a child who attends three sessions in the week is one player, not three. "Bookings" is counted the same way on Reports and Analytics, so the two tabs never disagree.

Payouts you have not approved yet

A payout week is only shown to a club once it has been approved and paid. Until then every club-facing surface — the Payouts tab, Club Home's payout card, the weekly pulse tile and the Reports Payout view — reads "Awaiting approval" with no dollar figure, and the week counts as $0.

That is deliberate. A pending week's amount can still change before it is approved (a fee-tier change, a price correction, a top-up), so publishing a figure would invite you to reconcile against a number that then moves. The week appears with its real amount the moment the transfer goes out.

For the same reason, the label "Money paid to you" only ever appears against money that has actually been transferred to your Stripe account. Where you see "Payout" instead, the money is either awaiting approval or there was none for that window.

All of these surfaces read one shared calculation, so they cannot show you different amounts for the same week. The platform fee shown on Analytics → Financials is the fee that was actually deducted from that payout — not a re-calculation at today's rate.

Source endpoints

  • GET /dashboard/club/reports/:period (period in weekly | monthly | quarterly | fy). Optional ?anchor=YYYY-MM-DD to view a historical period.
  • Drill-down rows: GET /dashboard/club/analytics/financials/revenue- breakdown?type=class|court_hire|total&from=...&to=....

Using Analytics Effectively

Identifying underperforming classes

Sort classes by attendance rate or revenue. Classes with consistently low attendance and high cancellation rates are candidates for rescheduling, repricing, or archiving.

Tracking player retention

The retention metric shows what percentage of players make a second booking after their first. Low retention on a specific class may indicate the class is not meeting expectations. Compare retention by coach to identify coaching quality signals.

Court hire optimisation

Use peak usage times to identify high-demand slots. Consider premium pricing for peak times. Identify underutilised courts and off-peak slots that could be promoted with discounts.

Revenue per session

Calculate revenue per session to identify which classes generate the most value per hour of coaching time. Useful for prioritising class types and scheduling.

Credit liability monitoring

Outstanding credits represent a future revenue obligation to the club (players can redeem credits for future bookings). Monitor the outstanding credits balance to understand cash flow implications.


Admin Analytics (AllSquads Platform)

Available to AllSquads platform administrators only.

Platform overview

  • Total platform revenue by period
  • Total bookings across all clubs and coaches
  • Active clubs, coaches, and players
  • Platform fees collected (booking fee + platform fee streams reported separately)

What AllSquads made

The admin home, the top of the Analytics overview and the Platform Revenue tab all show the same five figures for the selected period, from one calculation:

  • Booking fees: what players paid in booking fees, on every product.
  • Platform fees: what clubs pay in platform fees. Fees already taken in a payout and fees on money not yet paid out (an estimate until the payout runs) are one number; a note says how much is estimated.
  • Subscriptions: plan subscriptions Stripe has collected. Shows "Not checked" if Stripe could not be read, never $0.
  • Stripe fees: Stripe's own processing fees.
  • Net after Stripe: booking fees + platform fees + subscriptions − Stripe fees.

A footnote shows the GST included in the fees (the fees ÷ 11). GST is on AllSquads' fees only, never on the class or court price. Fees count on the day the class ran.

The weekly revenue table on the Platform Revenue tab has the same columns: Week, Booking fees, Platform fees, Subscriptions, Stripe fees and Net. Tap any figure to see the lines behind it. Weeks in July include fees from the old system.

The Booking Fee, Platform Fee and Club subscriptions panels in Growth trends, on the Analytics overview, use the same figures: each week, month, quarter or year equals these five figures for that period, so the periods add up to the figures at the top of the page. The six-month revenue trend chart shows revenue only; fees over time are in Growth trends.

On the Clubs tab, the table lists the top 50 clubs by club sales. A note under it gives the total fees for every club (the same figure as the fee cards) and how much of it is not in the rows: other clubs, and fees with no club.

Platform counts (admin home)

The top of the admin home page shows the platform's live counts — the same figures the public Explore page used to display as result totals, now for administrators only:

  • Classes: live, bookable classes (active, at a published club, listed publicly), with the number of scheduled sessions in the next 7 and 30 days and a per-sport breakdown across every sport in the taxonomy (zeros included, largest first). The class figures also appear at the top of the admin Classes page.
  • Clubs: clubs listed on Explore (published, excluding directory preview profiles), with the preview-profile count shown separately.
  • Coaches: coach profiles listed on Explore.
  • Courts: courts open for booking.
  • Active players: players with a class, court or membership booking in the last 30 days, with a 90-day figure alongside. A class booking counts unless it was cancelled or declined; a court hire counts while confirmed; a membership counts from purchase. Each player is counted once; deleted accounts are excluded.

Every figure is recalculated when the page loads (and on Refresh) — nothing is cached.

Club view

The Club view tab on Admin → Analytics shows one club's analytics exactly as that club's owner sees them at Dashboard → Analytics — the same Summary, Classes, Facility Hire, Players, Team and Financials tabs, drawn from the same queries, so the figures match the club's own view for the same period.

  • Pick a club with the searchable picker (type part of the name). Unclaimed directory preview profiles are not offered.
  • Period follows the Analytics page's own range selector (This week, Last week, MTD, …) — the club view has no separate date control.
  • Which tabs appear depends on the club's plan, the same way it does for the club.
  • Read-only. Nothing on the club view can change the club's data — the Team tab's employment type and hourly rate are shown as text, not editors.

Stripe fees

The Stripe fees tab on Admin → Analytics shows everything Stripe charged AllSquads' account in the period set by the Analytics range selector, from Stripe's own records. They are synced every morning at 5am Brisbane time, or straight away with Sync now. Records start on 1 July 2026.

  • Totals: the fees, the amount charged on cards, the effective rate (fees divided by the amount charged) and the share of charges under $20.
  • By day, week (Monday to Sunday) or month: each row shows its dates, its fees, its effective rate and the change on the one before (week on week, month on month). A week or month that the range cuts short shows only the days it counts and is marked partial. It has no change figure, and neither does the week or month after it.
  • Splits: by kind of fee (card processing, GST on Stripe fees, Invoicing, Billing, Tax, Connect, disputes), by payment type, by club and by card (domestic, international, AMEX). Fees that are not on a card charge (Stripe's product fees and dispute fees) are their own row, so each split adds up to the total.
  • The lines behind a figure: select any row of a split to list its Stripe lines: the Stripe ID, date, type, amount, fee and whether it was paid through an invoice. No player names are shown.
  • Spikes: a day whose fees are more than twice the median of the 28 days before it is flagged on the tab and in the 7am daily ops email.
  • New kinds of fee: the first time Stripe charges a kind of fee it has not charged before, it is flagged on the tab for a week and at the top of the 7am daily ops email, with the date, the first amount and the total so far. The table at the foot of the tab lists every kind of Stripe fee charged since 1 July.
  • The Platform Revenue "Stripe fees" figure is Stripe's fee on each payment. This tab adds Stripe's other fees, so its total can be higher.

User analytics

  • New user registrations by role and period
  • User activation rate (users who complete onboarding and make/receive a first booking)
  • User retention by cohort

Booking analytics

  • Bookings by class type, sport, and state
  • Cancellation rates and patterns
  • Waitlist conversion rates
  • Participations — platform-wide (or narrowed to one club with the club filter), the same Participations measure described under Club Analytics: every player, at every non-cancelled session inside the selected date range, counted once each — separate from the Bookings made (all statuses) count sitting beside it (every booking made in the period, cancelled ones included). The admin home's Bookings made card leaves cancelled bookings out, so it is a different figure with a different name.

Financial

  • Total booking fees and platform fees collected
  • Payout volumes
  • Refund and credit volumes (including ledger entries on credit issuance and redemption)
  • Stripe processing fees

Reviews and moderation

  • Review submission rate (reviews per booking)
  • Average rating by club, coach, and sport
  • Reviews pending moderation

Taxonomy and content

  • Sports and class type distribution
  • Geographic distribution of clubs and players