Team Rankings
Team Rankings are organization-level leaderboards that aggregate team performance across multiple competitions — unlike a single competition's standings table, which only ranks teams within one league or cup. A federation can use a ranking to crown a "club of the year", a recreational league can publish a multi-season power table, or a regional body can rank affiliated clubs across dozens of child competitions.
Overview & Plan Tier
A ranking is configured at the organization level (see Organization Profile). The organizer picks a ranking model, chooses which competitions feed into it, sets per-competition weights, and publishes. Every time a match result is confirmed anywhere inside a contributing competition, the ranking engine updates the affected teams and recomputes positions.
Creating and editing a Team Ranking is a PRO Plan feature (plan tier 2). Free-tier organizers see the Rankings screen with an upgrade gate. Viewing a published ranking is free for everyone — fans, players, and teams do not need a PRO subscription to see the leaderboard or share their position.
Live position shuffles during a match are not surfaced on the web client because the live-score feature itself is mobile-only. Post-match recomputes still happen on every platform: when any user submits a final score — including a referee or organizer entering the final result from the web — the ranking engine fires the same event hook the mobile clients use. The web table will reflect the new positions on the next refresh.
Key vocabulary
| Term | What it means |
|---|---|
| Ranking system | A configured leaderboard belonging to one organization. Each organization runs at most one ranking system — attempting to create a second returns a 409 conflict with code rankingAlreadyExists; to switch templates an organizer must update the existing ranking instead. |
| Contributing competition | A competition the organizer has flagged as feeding the ranking. Only results from these competitions count. |
| Base points | The raw points awarded for each result type (win / draw / loss / participation), before any multipliers. |
| Competition weight | A multiplier applied to every event inside one competition — used to say "a match in Division 1 is worth more than a match in Division 3". |
| Affiliate coefficient | A multiplier tied to a sub-organization (a child federation or club), propagated across every competition that sub-org runs. |
| Preview / publish | Config changes land in a preview snapshot first; the organizer must explicitly publish for them to affect the live table. |
Lifecycle — create, disable, never delete
Once created, a ranking system stays attached to its organization permanently. There is no delete endpoint; the only way to take a ranking out of public circulation is to disable it by setting enabled: false on the ranking system — the table stops being computed and the public reads return nothing, but the configured rules, scoring, and event history remain in place. A disabled ranking can be re-enabled later without losing its history, and an organizer can keep editing all the same dials (scoring rules, competition values, org coefficients) while it is disabled.
The full set of organizer-side actions exposed by the API:
- Create — pick a template (local, regional, national, international) and the ranking is provisioned with that template's defaults. Fails with a conflict if one already exists.
- Update — edit any top-level setting (model type, visibility, season scope, rolling window, decay, tiebreakers); the same endpoint is used to disable the ranking by passing
enabled: false. - Edit scoring rules, edit competition values, edit org values — each is its own endpoint.
- Manual event — an organizer can add a one-off ranking event (a bonus, a sanction).
- Preview → publish or discard — the staged workflow that lets the organizer see the new table before it goes live.
- Recalc — rebuild every event's
finalPointsfrom the current rules; safe to run anytime.
Ranking Models
A ranking is configured along two independent dimensions: its model type (how points are aggregated) and its season scope (which events are considered). Organizers pick both when creating the ranking and can switch later via the preview flow.
| Dimension | Values | What it controls |
|---|---|---|
| Aggregation method | Standard, Weighted, Rolling | How raw points are calculated per event and which multipliers apply |
| Season scope | Calendar year, Season year, Current + previous season, All time, Rolling window | Which events feed the ranking — see Season scope below for the five values and how to choose |
Standard
Best for: recreational leagues, single-competition power tables, social leagues with no tiering.
Awards flat base points for each match result and sums them across contributing competitions. No per-competition weight is applied — a win is a win regardless of which competition it happened in. Competition weight and affiliate coefficient sliders are ignored by this model.
A city organizer runs a summer 7-a-side league and a winter 11-a-side league under the same organization. Both should count equally toward the "Club of the Year" table. Standard model, 3-1-0 base points — simple and obvious to everyone.
Weighted
Best for: federations with tiered competitions (Div 1 / Div 2 / Cup), regional bodies aggregating results across affiliated clubs.
Same as Standard plus two multipliers — the competition weight and the affiliate coefficient. The final points for each event equal the base points multiplied by the competition weight and then by the affiliate coefficient.
This lets a federation say "a win in Division 1 is worth 1.5x a win in Division 3", or "matches played by the youth academy branch count at 0.5x for the senior club-of-the-year table".
A Weighted ranking can also use a rolling season scope — this is how the built-in "international" preset is configured (24-month rolling window with tiered competition weights). Use this when a federation needs both tiered multipliers and a form-style time window; reach for the Rolling model (below) instead when the main feature you want is the time window itself.
A regional federation runs Division 1, Division 2, a regional cup, and a U19 competition. The committee agrees the power ranking should weight Division 1 at 1.5x, Division 2 at 1.0x, the cup at 1.2x, and U19 at 0.3x. Weighted model, one per-competition weight slider per league, done.
Rolling
Best for: seasonal-form tables, "who's hot right now" rankings, federations that want positions to reflect recent form rather than a team's all-time total.
A first-class model type focused on a time window: only events from the last 6 months, 12 months, or 24 months count (or the last two completed seasons). An optional time decay can also be enabled — events older than today are exponentially down-weighted, so a win three months ago is worth less than a win last week, but still more than one a year ago.
Competition weight and affiliate coefficient sliders are still available but most Rolling deployments leave them at 1.0 — the whole point of this model is that recency, not tiering, drives the position.
Most federations that want "recent form" pick a 12-month rolling window with decay off — simple and easy to explain to teams. Decay is useful when the ranking is published weekly and the audience expects it to react quickly to new results.
A streaming league that runs back-to-back monthly tournaments uses the Rolling model with a 6-month window so that the top-of-table teams always reflect "who has been winning lately". A team that dominated 18 months ago but hasn't played since naturally drops off the leaderboard — no manual archiving needed.
Competition Value (Weight)
Each contributing competition has a weight — a multiplier that scales every ranking event originating in that competition. It is the main knob an organizer turns to encode "this competition is more prestigious than that one".
| Property | Value |
|---|---|
| Range | 0.3 – 3.0 (slider steps in 0.1) |
| Default | 1.0 (neutral — no multiplier) |
| Where it lives | Organization → Rankings → Competitions tab, per competition row |
| Ignored by | Standard model only uses the default 1.0; Weighted and Rolling apply it to every event |
Alongside the weight, the same row exposes:
- Contributes to ranking — toggle to include or exclude a competition entirely. Toggling off keeps the competition's own standings table intact; it just stops feeding the ranking.
- Participation points — a flat number of points a team receives for merely taking part in the competition (useful for cup-style formats where not every team plays every matchday).
Are weight changes retroactive?
Yes. When the organizer publishes a new weight, the ranking engine recomputes every historical event from that competition using the new multiplier. A team that was sitting 3rd yesterday with Division 1 at weight 1.2 may be 2nd tomorrow if the organizer publishes a change to 1.5. This is by design — the ranking always reflects the current ruleset applied to the full history.
Weight edits always land in a preview snapshot. The organizer can inspect the resulting table and either publish or discard. Nothing appears to fans until publish is pressed — this prevents mid-season surprises.
Affiliated-Organization Coefficient
Larger federations run child organizations (regional bodies, affiliated clubs, academies). The affiliate coefficient is a multiplier attached to a child organization, not to a specific competition. It propagates automatically to every competition that child organization runs — past, present, and future.
| Property | Value |
|---|---|
| Range | 0.0 – 2.0 |
| Default | 1.0 (neutral) |
| Where it lives | Organization → Rankings → Affiliates tab |
| Propagation | Applies to every event where the team's home organization matches the affiliate entry — including competitions added after the coefficient was set |
A disabled affiliate entry is greyed out — its coefficient is not consulted, and teams whose home org matches it are treated as if the coefficient were 1.0.
A national federation runs a power ranking across every child federation (North, South, East, West). The national board decides the Northern region is historically stronger and sets its coefficient to 1.2. All Northern teams — across every competition the Northern federation runs — earn 1.2x ranking points automatically, without the national board having to hunt down and edit each individual competition.
Weight vs coefficient — how to choose
- Use a competition weight when the distinction is between competitions (Division 1 vs Division 3, senior vs U19).
- Use an affiliate coefficient when the distinction is between organizations (Northern federation vs Southern federation, main club vs academy branch).
- Both multiply together. A team playing in Division 1 (weight 1.5) under the Northern federation (coefficient 1.2) earns 1.8x points per event (base points × 1.5 × 1.2).
How Points Are Computed
For each event the engine emits, it stores three multiplier inputs and a derived finalPoints:
| Input | What it is | Range / default |
|---|---|---|
basePoints |
The points for this event's outcome, looked up in the scoring rules by key — win, draw, loss, noShow, participation, stageFinal, stageSf, stageQf, title, disciplinary, fairplay. |
Set per ranking on the scoring rules tab; defaults come from the chosen template. |
competitionWeight |
The Weighted-model multiplier for the source competition. Standard mode forces this to 1. | 0.3 – 3.0; default 1.0. |
organizationCoefficient |
The Weighted-model multiplier for the team's home (sub-)organization. Standard mode forces this to 1. | 0.0 – 2.0; default 1.0. |
The stored value is finalPoints = basePoints × competitionWeight × organizationCoefficient. A team's total is the sum of finalPoints across every non-voided event that falls inside the season scope — the breakdown modal shows the same per-competition totals the engine sees.
Read-time overlays (not baked into finalPoints)
Two settings affect the table but are not stored on each event — they are applied when the ranking is read:
- Time decay (Rolling model with
decayEnabled: true): older events are exponentially down-weighted bydecayRatePerDay. Because the multiplier depends on "today", the API recomputes the table on every read for this combination rather than summing the storedfinalPoints. previousSeasonPartialPercent(only valid when season scope iscurrent-plus-previous): an integer 0–100 that scales every previous-season event at read time. A value of 50 means a team's previous season contributes at half weight; 0 ignores it entirely.
Everything else — basePoints, competition weight, organization coefficient — is rewritten onto every affected event when the organizer publishes a change. That is what makes weight edits truly retroactive: the same formula has already been re-applied to every historical event by the time the new table appears.
Season scope — which events feed the table
Independent of the model type, the ranking has a season scope that filters which events the engine considers. An event whose date falls outside the scope is ignored on read; nothing is deleted — if the organizer later widens the scope, the older events appear again automatically.
| Scope value | What it includes | Typical use |
|---|---|---|
calendarYear |
Events dated in the current calendar year (Jan–Dec). | Federations whose competition cycle aligns with the calendar year. |
seasonYear |
Events in the current Jul–Jun season window. | Traditional football season (autumn–spring). |
current-plus-previous |
The current season plus the previous one. Previous-season events are scaled by previousSeasonPartialPercent (an integer 0–100) so an organizer can fade them down without dropping them. |
Smooths the transition between seasons so a single tournament doesn't reshuffle the whole table. |
all-time |
Every event ever recorded for the ranking. | Historical "club of the decade" tables that should never drop a result. |
rolling |
Events in the last rollingMonths — only the values 6, 12, 24, or last-2-seasons are accepted. With decayEnabled: true a per-day exponential decay is layered on top so older events count for less. |
"Who's hot right now" form tables; the international preset uses a 24-month rolling window. |
Tiebreakers — how equal finalPoints totals are resolved
When two teams have the same finalPoints total, the engine walks an ordered list of tiebreakers chosen on the ranking template. The current options are:
| Tiebreaker | How it resolves |
|---|---|
headToHead |
Compares results of matches played directly between the tied teams across contributing competitions. |
goalDifference |
Net goal difference across all contributing matches. |
goalsFor |
Total goals scored across contributing matches. |
totalWins |
Number of wins across contributing matches. |
alphabetical |
Last-resort stable fallback so the table never has an undefined order. |
The default order is template-specific — the local/regional preset starts with headToHead, then goalDifference; the national/international preset prioritizes headToHead then goalDifference then totalWins. Organizers can re-order or remove entries from this list on the ranking system settings.
Who Can Create / Edit / Delete
Endpoints fall into two families, and they are gated very differently.
Public reads
The ranking table, a team's breakdown, and a team's history are exposed as public reads with no auth gating — fans, players, team managers and referees all consume the same endpoints. The ranking's visibility setting (public, private, or members) then filters what callers actually see; a private ranking is not surfaced outside the organization.
Admin writes
Every mutation (create, update, scoring rules, competition values, org values, manual event, preview, publish, discard, recalc) requires organization-admin rights on the specific organization. That maps to the organizer role plus an admin grant on that org — a referee or a team manager from a contributing competition does not have access to these endpoints. Creating or editing a ranking is additionally gated by the PRO Plan check noted above.
Deleting a ranking
There is no delete endpoint. To take a ranking out of public circulation, an organization admin issues the standard update endpoint with enabled: false; the table stops being computed and the public reads return nothing, but the configured rules, scoring, and event history are preserved and the ranking can be re-enabled later without losing any data. See Lifecycle — create, disable, never delete for the full set of mutations and the staged preview/publish flow.
Team Breakdown Modal
Tapping a team's row on the ranking table opens the breakdown modal — the most useful view when you want to understand why a team is where it is.
| Field | How to read it |
|---|---|
| Total points | The final aggregated score after all multipliers. Matches the team's row on the main table exactly. |
| Position | Current rank in the published table (1 = top). |
| Position change (▲/▼) | Movement since the previous daily snapshot. A team that rose from 7th to 5th shows ▲2. No change shows a dash. |
| History chart | Points over the last 30 or 90 days (toggle in modal). Flat line = no new events; steps = results coming in. |
| Per-competition contribution | How many points the team earned from each contributing competition, after weight and coefficient are applied. The sum equals total points. |
| Share button | Native share — generates a poster with the team's position, points, and delta. Useful for sharing on social or for capturing a specific state at a moment in time. |
The breakdown shows the final per-competition total, not per-match detail. If a team disputes an individual match result, that is a competition-level scoring issue — fix it in the competition, and the ranking will pick up the corrected result on the next recalculation.
The same per-team position and delta feed the Smartwatch Companion's ranking-position widget, so a fan following one team can glance at their watch and see the same number that appears in the breakdown modal. A daily ranking update notification deep-links into the ranking table when a team's position changes.
Common Questions
Three situations come up most often. In each case, start by opening the breakdown modal: it shows exactly what the ranking is using, and most questions answer themselves once you can see the per-competition contribution.
1. A team thinks their ranking position is wrong
If a Team Manager believes their club is 6th when they "should" be 3rd, open the ranking, tap the team row, and read the per-competition contribution. Check (a) every competition the team plays in is set to Contributes to ranking, (b) the competition weights match what was last published, (c) no match results are still in dispute at the competition level. Most of these cases turn out to be a single competition with Contributes turned off, or a match the referee never confirmed.
2. You want to change weights mid-season
Halfway through the year, the committee decides Division 1 should weight 1.8x instead of 1.5x. Remember that weight changes are retroactive — the whole season recomputes on publish, not just future matches. Use the preview step to eyeball the new table before publishing, and post a news item so affected teams aren't blindsided when their position shifts.
3. A new child competition isn't being counted
If you added a new cup to your organization last week and a Team Manager notices the cup's results aren't showing up in the ranking, that's expected: new competitions are not automatically included. Open Organization → Rankings → Competitions, find the new row, toggle Contributes to ranking on, and publish. If the new competition also belongs to a child organization with an affiliate coefficient set, the coefficient will apply to it automatically — no second step needed on the Affiliates tab.
If the breakdown looks right but the main table disagrees, run a manual recalculation. Rankings update automatically on every confirmed result, but a forced recalc is the fastest way to refresh the table when something looks off.