How the numbers work
Where every number on this site comes from, what we calculate ourselves, and what the data can and cannot tell you. Definitions live in the glossary.
Data sources
AFC1903 uses publicly available match data from sources including WhoScored, FotMob and Sofascore. WhoScored’s match data is powered by Opta.
Recorded match events — such as passes, shots, defensive actions and duels — provide the starting point for AFC1903’s analysis.
Many of the metrics shown on this site are calculated by AFC1903 rather than taken directly from the source data. These include inferred ball carries, progressive actions, expected threat (xT), field-position metrics, possession sequences and other analytical measures.
AFC1903 transforms the underlying match information into its own models, visualisations and tactical analysis. The site does not provide or redistribute the underlying raw event dataset.
Where the data comes from
Three providers, each used for what it does best. WhoScored (Opta) supplies on-ball event data — every pass, touch, carry, tackle — which powers the pass maps, chance-creation chains, progressive passes, high regains and xT. Full event coverage runs from 2021-22; pass-level detail (the season pass map, F3 passes, touch maps) exists from 2025-26 onward.
Sofascore supplies shot-level detail (location, situation, body part, xGOT), player season stats (minutes, goals, ratings, duels) and team match stats (possession, passing splits, goal kicks, PPDA inputs). FotMob supplies match xG and xGA, which we use for every season — every season since 2021-22 on one xG model, so cross-season trends compare like for like.
xG is always FotMob’s — including while a match is being played. The live card on the front page reads FotMob too, so the xG shown at half time is the same number, from the same model, as the one in the match report after the whistle. It is provisional until then: xG gets revised in play as shots are reviewed, and nothing from a match in progress enters the season figures until it has finished.
League results, fixtures and tables are cross-checked against official SPFL records.
What we calculate ourselves
Derived on this site rather than taken from a provider: xG difference, xG per shot and xGA per shot, points per game, per-90 rates, conversion rates, build-up chain lengths (passes from possession win to shot), the direct ↔ possession style index, territory heatmaps, all correlations (Pearson r with a Fisher-z 95% confidence interval and significance test), squad percentiles and ranks, and the xT credit assigned to passing, receiving and carrying (explained below).
Read with care
Providers disagree. Different companies define events differently and xG models vary — a gap under ~10% between seasons or sources can be the model, not the football. Small samples lie. Conversion and finishing numbers swing hard on few shots; we flag or floor low-minute players, and correlations always show n and significance — grey means the sample is too small to trust, whatever the r value. Correlation isn’t causation. Teams that are winning pass more; passing more doesn’t make you win. Nothing here is controlled for opponent quality or game state, and we say so on the charts. Build-up chains are the tracked subset. Penalties, corners, set pieces and solo goals have no passing move to measure, so chain stats describe open-play passing moves only. PPDA is a proxy. It counts how often defensive actions happen relative to opponent passes — it cannot see whether the press is well-structured.
Pressing and defensive actions
A ball-win means winning the ball. Tackles won, interceptions and recoveries count. A foul does not — it stops an attack but hands possession back — and nor does a lost tackle or a “challenge”, which in this data means the defender was beaten. Fouls conceded sit in their own column beside ball-wins, because a player whose defending is mostly fouls is a different profile and adding the two together reads as a compliment.
A provider quirk worth knowing: WhoScored records a foul from the point of view of the player it happened to, so “successful” means the player won the foul and “unsuccessful” means they gave it away. Only fouls conceded belong in a defensive-action set. We checked that against the match totals rather than assuming it.
PPDA is opponent passes allowed per defensive action in the pressing zone — the standard zoned calculation, counting tackles, interceptions, challenges and fouls conceded in the opponent’s own 60% of the pitch. Lower means a harder press. Five 2025-26 matches have no event data and previously carried a whole-pitch approximation; those now show no PPDA rather than a number that isn’t comparable, because mixing the two made it look as though the press changed late in the season when it hadn’t.
Counter-pressing is a rate, not a count. Regains within five seconds of losing the ball, divided by the number of times we lost it. The raw count is close to a measure of how often a side gives the ball away — it tracks our own turnovers far more strongly than possession — so a sloppier team scores better on it. The rate answers the question people think the count is answering.
Tackles and interceptions are possession-adjusted when managers or seasons are compared. A side that keeps the ball gets fewer chances to tackle, so raw counts partly rank teams rather than the people in them. PPDA and the counter-press rate are already ratios and are left alone.
Passing: what counts as open play
Corners, free kicks, throw-ins and goal kicks are restarts, not a team choosing how to play. Every major provider types them separately and style metrics normally exclude them, so pass maps default to open play only. It matters more than it sounds: in one match, 28% of our “long balls” and 24% of our “crosses” were actually set pieces.
Goal kicks get their own bucket. They are a restart, but going long from one is a real choice about directness, so excluding them understates how direct a side is. The pass map lets you pick: open play, open play plus goal kicks, or everything.
A progressive pass moves the ball about ten yards closer to goal from outside your own defensive 40%, or into the penalty area from outside it. The defensive-40% exclusion is the important part — without it, a centre-back clearing his lines counts as progression.
Shooting and where chances come from
The central high-value zone is inside the penalty area and in the central channel — the six-yard-box width extended out to the penalty spot. Chance quality is highest there, so the share of shots taken from it says more than shot volume does. A big chance here means a shot worth 0.30 xG or more; the shot feed carries no separate big-chance flag, so we set that threshold ourselves.
Where goals come from sorts every shot by how the chance was made: a progressive pass in open play, individual play with no key pass at all (rebounds, deflections, solo runs), a set-piece delivery to a team-mate, a shot straight from the dead ball, or a penalty. The category comes from the shot feed, which covers every shot. Whether a pass created it comes from the event feed, which only records assisted chances — so an open-play shot missing from it genuinely had no key pass. That asymmetry is the signal, not a gap. The type of pass is only known where the two feeds join.
The benchmark
The homepage tracker measures the season against 60 points, taken from our own Setting the benchmark article. It is framed on points rather than a finishing position deliberately: the points total is the part Aberdeen control, where it places them is up to everyone else. The per-game targets are what an average third-place SPFL finisher manages. From the article: 1.62 points a game, 1.66 expected points, +0.32 goal difference, 4.2 shots on target and 14 clean sheets. Ours, not the article’s (marked with a dagger on the tracker): 1.50 xG and 1.18 xG conceded, which simply decompose the goal-difference target into the two halves that produce it, and 20 open-play assists a season — Aberdeen’s own five-season baseline, with 22 in 2022-23 the best on record.
Projections start at six games. Stretching a rate over 38 games before that produces a number that is arithmetically correct and useless — a single opening win is “on pace for 114 points”. Until then the tracker shows running totals and says so.
Expected points comes straight from FotMob, the same source the article took the 1.66 target from — so target and actual are the same measure. We previously computed it ourselves with a Poisson model; the two agreed closely (1.97 against FotMob’s 1.96 on the opening day), but using FotMob’s number directly removes the need to explain the difference at all.
When two numbers disagree
Some metrics exist in more than one feed and the feeds do not agree. Key passes and assistscome from WhoScored on the squad pages, and WhoScored counts fewer of them than Sofascore does — consistently, for every player we can check. The new-signings panel uses Sofascore, because no WhoScored record exists of what a player did at Dundee or Kilmarnock. It is internally consistent, but a number there should not be read against one on the squad table. Long balls are the same story: season totals include every restart, while the match pass map counts open play only.
Not-measured is never zero. Several stats only begin partway through our history — touches in the box are only real from 2024-25, for instance, and are stored as 0 before that. Averaging those in invents a very low number for an older manager, so each metric carries the season it genuinely starts and anything earlier is left blank. A dash means we hold no data, not that the value was nil.
Match reports: the “In context” strips
Shots, passing and defending each get a strip comparing the match to Aberdeen’s own history, matched by period — a first half against other first halves. 5-year is the mean across every match with WhoScored event data, 2021-22 onward, and is the only column with a sample worth trusting early in a season. This season is the current season alone, so read it as a direction of travel rather than a settled average while it is still a handful of games. SPFL average answers a different question — “is that normal, or just normal for us” — but only appears on the six rows (shots, shots on target, shots in the box, tackles won, interceptions, fouls) where Aberdeen’s WhoScored figures and the rest of the league’s Sofascore figures are demonstrably counting the same thing; everywhere else the column is hidden rather than dashed, because an empty cell reads as zero or as us not bothering, and neither is true.
“About normal” is a real verdict, not a placeholder — a strip that only knows how to announce extremes will invent them, so a match is only called one when it genuinely is. Two rows are left deliberately uncoloured rather than marked good or bad: fouls conceded (the one defensive row where a high number is the bad one) and passes/long balls (going long more often is a choice, not a failing).
The idea: every spot on the pitch has a danger level
Imagine the pitch as a heat map. With the ball deep in your own half, almost nothing happens next — a goal in the next few moves is very unlikely. At the edge of the opponent’s box, the temperature is completely different. Expected threat (xT) simply puts a number on that: for each zone of the pitch, how often does having the ball there lead to a goal within the next handful of actions?
Once every zone has a danger value, you can score any action that moves the ball: value of where the ball ended up, minus value of where it started. A pass from halfway to the edge of the box moves the ball from a cold zone to a hot one — that difference is the threat the pass added. We use the same zone values for every match and every season.
The zone values come from a published grid (Karun Singh’s 12×8 expected-threat grid, built from hundreds of thousands of top-flight matches). We deliberately did not fit our own grid from Aberdeen’s ~200 matches — one club’s sample is far too noisy, and a home-made grid would just bake in our own quirks.
How each category is credited
Passing. Completed passes that move the ball somewhere more dangerous. The credit for a threat-adding pass is split 50/50 between the passer and the receiver — a through-ball only works because someone made the run to take it. Safe sideways or backward passes score zero, not negative: we measure threat created, we don’t punish keeping the ball.
Receiving. The receiver’s half of those same passes. This rewards players who get into dangerous spots to take the ball. Honest caveat: with event data we only know where the ball was received, not the quality of the run that got them there — that would need tracking data nobody publishes for Scotland.
Carrying. Opta-style event feeds don’t record carries directly, so we read them from the gaps: when the same move’s next touch happens five or more metres from where the last action ended, somebody moved the ball there with their feet. The player who carried it gets the change in danger between the two spots. Successful dribbles past an opponent show up through the same mechanism.
Parked idea: a per-match, per-player scatter of progressive passes vs. progressive carries (same gap-detection logic, same “10 yards from x≥40, or into the box” threshold as Progressive Passes) was prototyped for match reports and pulled back out before shipping. Revisit here if it comes up again rather than rebuilding the carry-detection logic from scratch.
Shooting. Shots deliberately get no threat credit — shot quality is what expected goals (xG) is for, and mixing the two would double-count. Shooting is shown as goals (all seasons) plus real xG — FotMob’s for every season from 2021-22, and Sofascore’s shot-level xG for 2025-26 onward where per-shot detail is needed. We never estimate xG for a season that lacks it.
Ball-winning. Tackles won, interceptions, recoveries, clearances and blocked passes, counted per 90. This is a simple count, not a threat value — putting an honest value on defensive actions needs a possession model we’re not pretending to have. It answers “who does the interrupting?”, not “how much is it worth?”.
Percentiles: read the small print
The small numbers (and the player wheels) are percentiles vs same-position players in our own dataset — every Aberdeen player-season with 450+ minutes since 2021-22. A 90 means “90% of comparable Aberdeen player-seasons did less of this per 90”. It does not mean top 10% of the league: this is a single club’s sample, a few dozen players per position, so treat percentiles as a fingerprint of a player’s style and role, not a league rating.
Roles and “plays like”
The role label on each profile (“ball-winning destroyer”, “deep-lying playmaker”, “goal poacher”…) is a plain-English description, not a new score. It reads the same five percentiles — this time against the player’s finer slot (centre-backs vs centre-backs, full-backs vs full-backs, and so on) — and names the trait that stands out. A defensive midfielder whose ball-winning percentile towers over his passing is a destroyer; one whose passing leads is a deep-lying playmaker. When nothing stands out, we just use the position word. No made-up numbers, no ratings — the label only puts a name to what the percentiles already show.
“Plays like” finds the nearest player-seasons in our own history by those five percentiles, within the same position. It answers “who in recent Aberdeen sides had this shape?” — a similarity within one club’s data, not a global comp.
What this data is — and isn’t
Built from on-ball event data (every pass, touch, shot, tackle) for 2021-22 onward — every league match since 2021-22; 2020-21 predates our event coverage and has no value layer. Event data sees the ball, not the other 21 players: no off-ball runs, no pressing traps, no shape. Per-90 numbers use minutes in covered matches only, and players need meaningful minutes before per-90 figures mean much.
The recruitment ledger
How every signing since 2020-21 got its verdict in the recruitment ledger — a look back at whether each one worked, not a crystal ball. (The ledger page is currently retired from the nav; the method is kept here because the same value layer powers the player profiles.)
Three things we score, two things we don’t
1. Did they play? Minutes are the cheapest and most honest test of a signing — managers pick players they trust. We use the player’s best single-season share of available minutes: 55%+ of minutes earns full marks, 30%+ partial.
2. Did they add threat? The value layer above, compared with positional peers: percentile for passing, receiving and carrying — plus finishing for forwards, ball-winning for defenders and midfielders. 60th+ percentile earns full marks, 35th+ partial. Signings without enough minutes in event-covered matches (and everything in 2020-21, before our event data starts) show a dash and are scored on the other dimensions only.
3. What happened to the money? Fee out vs fee in. Sold at a profit of £0.5m+ is full marks; sold at any profit, or still at the club and playing, is partial; bought for a fee and released for nothing is zero. Known hole: we have no wages data, so every signing’s true cost is understated — a “free” on big wages is not free. We say this rather than pretend otherwise.
Age is context, not points. A 20-year-old development buy and a 30-year-old win-now buy fail differently: one was bought to resell, the other to produce immediately. The ledger labels each signing’s profile so you read the verdict in the right light, but doesn’t pretend to price it.
Regimes are the rollup. Five recruiting regimes in six seasons — signings grouped by the manager they arrived under, with hit rates per regime. With samples this small the windows tell the story as much as the rate.
Why tiers, not scores
Each signing lands in one of four tiers — Hit / Solid / Squad-filler / Miss — from its share of available points (75%+ / 50%+ / 25%+ / below). A 0-100 rating on a sample of 19 signings would be false precision; coarse tiers are what the evidence can actually support.
Also deliberately excluded: on/off-pitch splits (too noisy at one club), any guess at what a different signing would have done (no counterfactual is knowable), and wage estimation (we’d be making numbers up).