Methodology

Published,
so you can
argue with it

Every number Latent puts on a screen (this site, a post, a paid report) is derived by us from match-level data we hold, by the rules on this page. Nothing is licensed and rebadged. Where the data cannot support a claim, the claim is not made, and the gap is listed in section 08 rather than smoothed over.

615,070 Player-match stat rows
20,248 Finished matches
40,237 Player-seasons
13,656 Rankable players 270+ minutes in a season

Figures on this page are read from the database each time it is built. Last finished match in the data: 2026-09-21. Page built 2026-09-21.

01 · Sources

What the numbers are built from

Five layers, all held locally, all queried read-only by the scripts that generate this site.

  • Per-match player statistics 615,070 player-match rows across 20,248 finished matches in 22 competitions and 97 seasons: minutes, goals, shots, passes, duels, touches and more, per player per match. Every metric we publish is our own derivation from this layer. We never republish a third party's player rating.
  • Transfer records 105,268 completed moves in and out of our markets, 38,274 of them across a border, 6,098 with a disclosed fee. This is what grounds destination analysis, fee comparables and the ledger in transfers that actually happened.
  • Post-move outcomes 35,292 destination season rows: how much a player who left actually played afterwards. Minutes earned at the destination are the closest thing a transfer has to a verdict, and they calibrate the Latent Level.
  • Continental competition 18,157 player-match rows from 1,016 European matches played by 279 of our clubs across 5 competitions: real evidence of how these squads perform against stronger opposition, rather than a projection of it.
  • Second-tier and destination squads 13,449 stat rows from a second-tier feeder competition, and a squad snapshot of 6,207 players at 212 clubs in 12 destination markets, taken 2026-08-14.
02 · Coverage

Stated exactly, per competition

Coverage is uneven, because the underlying collection is. The honest response is to print the table, not to imply a depth that only exists in two of these competitions.

Player-statistic coverage by competition Data labels, not a ranking. Rankable = players with at least 270 minutes in a season.
CompetitionStats fromSeasons MatchesRankableStat rows
USL ChampionshipUnited States · USLC202072,8041,74584,579
Serbian SuperLigaSerbia · SRB20/2171,9431,30058,844
Croatian Football LeagueCroatia · CRO20/2171,11978334,380
EkstraklasaPoland · EKS21/2261,6081,14649,509
Romanian SuperLigaRomania · ROU22/2351,36092641,526
Czech First LeagueCzech Republic · CZE22/2351,19177136,789
Greek Super LeagueGreece · GRE22/23598788330,474
Erovnuli LigaGeorgia · GEO2022586866926,163
Bulgarian First LeagueBulgaria · BUL23/24494281028,628
Cypriot First DivisionCyprus · CYP23/24477673023,105
Kazakhstan Premier LeagueKazakhstan · KAZ2023472670822,034
VirslīgaLatvia · LAT2023470050020,814
MeistriliigaEstonia · EST2023469142720,402
A LygaLithuania · LIT2023468951720,677
Nemzeti Bajnokság IHungary · HUN23/24464155719,746
Slovak First LeagueSlovakia · SVK23/24463755319,495
Premier League of Bosnia and HerzegovinaBosnia and Herzegovina · BIH23/24461666418,995
Azerbaijan Premier LeagueAzerbaijan · AZE23/24459348617,854
Slovenian PrvaLigaSlovenia · SVN23/24457553417,257
Kategoria SuperioreAlbania · ALB24/25339739611,967
Ukrainian Premier LeagueUkraine · UPL25/2622964299,048
Canadian Premier LeagueCanada · CPL20261891562,784
The consequence, said plainly

The deepest histories we hold are not the markets the brand started in. There is no player-statistic history before the first season listed for each competition (not thin history, none), so multi-year trend work and "we would have seen him coming" evidence is only possible where the seasons column is large. Any page or report implying otherwise would be wrong.

Ball-carry data

Carry collection began part-way through our history and, in one competition, part-way through a season. Where it covers only part of a league-season, the carry percentile is suppressed for that whole season rather than ranking players measured on different match sets against each other. The rate survives, the ranking does not.

Where carry data exists at all Competitions and seasons not listed have no carry data whatsoever.
Competition / seasonPlayers with a rate Percentile published
CPL 2026156 of 156● ranked
CRO 25/26201 of 253◐ rate only
CRO 26/27135 of 135● ranked
CZE 25/26320 of 408◐ rate only
CZE 26/27224 of 224● ranked
EKS 25/26321 of 420◐ rate only
EKS 26/27247 of 247● ranked
GRE 25/26297 of 362◐ rate only
GRE 26/27128 of 128● ranked
HUN 25/26222 of 288◐ rate only
HUN 26/27147 of 147● ranked
ROU 25/26314 of 405◐ rate only
ROU 26/27227 of 227● ranked
SRB 25/26316 of 415◐ rate only
SRB 26/27201 of 201● ranked
SVK 25/26220 of 298◐ rate only
SVK 26/27162 of 162● ranked
USLC 202511 of 529◐ rate only
USLC 2026514 of 514● ranked
A rate that exists for a handful of players in a season is not a basis for a claim about that season. Where the count is small the percentile is deliberately absent, and no carry comparison should be drawn from the rate alone.
03 · Rates

How a per-90 is computed

  • Honest denominators A statistic is divided only by the minutes in which that statistic was actually collected, never a partial numerator over full-season minutes. Getting this wrong is how a player with eleven recorded carries in one match ends up at the 97th percentile for a season, which is exactly the defect this rule was written to kill.
  • 270 collected minutes, per statistic Each rate has its own gate. Below it the rate is reported unavailable, not estimated. A player used in short substitute cameos may clear the gate for one statistic and not another; his rolling form line is then drawn with gaps rather than filled with zeros.
  • Missing is never zero A statistic a competition did not record renders as "not recorded" on the site, in graphics and in reports. Gaps are never filled with zeros, league averages or model output.
  • Goals and assists are the one exception, deliberately Some feeds omit the goals field entirely for a player who did not score, rather than writing zero. Treated naively that removes every goalless player from the goals ranking, so they are never penalised for not scoring. We treat an absent goal field as a genuine zero, so a goalless player ranks last instead of vanishing.
04 · Percentiles

The peer group is exact, or there is no percentile

  • Scope Same competition, same season, same position group, minimum 270 minutes. Every percentile we print is printed with the size of the cohort it was computed against.
  • Never across competitions A 90th percentile in one league and a 90th in another are not the same claim, so they are never blended, averaged or compared. Cross-competition comparison is what the Latent Level exists for, and it is a separate number with its own published test.
  • Cohort floor of 10 If fewer than ten players survive the minutes gate in a peer group, no percentile is published at all. The smallest cohort currently behind any published percentile is 10 players. Early in a season this means a competition publishes few percentiles or none. That is the floor working, not missing data.
  • No mixed cohorts If a statistic covers only part of a league-season, its percentile is suppressed for the whole season. A percentile whose peer group is "whoever the provider happened to cover" is not the ranking the number claims to be.
05 · Export Index

The flagship number, defined

One score per player per season: the mean of five per-90 output percentiles (goals, assists, progressive carries, key passes and duel win rate) against the peer group above, then multiplied by an age factor that favours youth (×1.15 at 21 or under, ×1.05 from 22 to 24, ×1.00 after that), because the same output from a younger player is worth more to the buyer. 27,118 player-seasons currently carry one.

  • An index, not a percentile Like the Latent Level, the Export Index is a score on its own scale: whole numbers running about 58 to 1,107, averaging 509. It is deliberately not on a 0–100 scale, because a mean of percentiles carrying an age multiplier will exceed 100 and then invites the question "out of what?". It is never printed with a percent sign, never described as a percentile, and never drawn on a shared axis with the percentile bars it is built from. Nor is it clamped: clamping would destroy the ordering exactly at the top, where the ordering is the whole point.
  • Goalkeepers are not ranked by it The index contains no shot-stopping, so a goalkeeper's index would be a ranking of how well he does things he is not there to do. Goalkeepers carry no index at all: 0 of them appear in any index or leaderboard on this site. Their 2,470 ranked seasons are ranked keeper against keeper instead.
  • A season is scored only on components available to all of it Where a component covers part of a season, the whole season is scored on the remaining components, so every player in a league-season sits on the same scale. The cost is real and we took it anyway: one season lost its carry ranking entirely.
06 · Latent Level

Cross-league rating, with the backtest attached

Percentiles stop at the league border. The Latent Level is the cross-competition number: a player's within-league output, adjusted for the opposition he produced it against, then translated onto one scale by a league multiplier. That multiplier is calibrated on 2,183 season-pairs from players who actually played a qualifying season in two of our competitions — the same man, measured on both sides of the border, is the only direct evidence of what the border is worth. 27,036 player-seasons carry a Level.

  • It is an index out of 1,000, and never out of 100 The Level is a score on a stated 0 to 1,000 scale: 1,000 is the ceiling, and a value is clamped there rather than allowed past it. Published values run about 12 to 997; the average across every player-season that carries one is 401, and the average of a single competition-and-position cohort runs from about 338 to 480 depending on which cohort it is. That spread is the reason a Level is only readable next to the cohort average printed beside it, which is how every Latent report prints it. It is never a percentage and never out of 100. Method level-v2.3 maps the raw composite onto that 0 to 1,000 scale linearly to remove exactly that ambiguity; ordering, correlations and every backtest figure below are unchanged by it.
  • The validation rule No Level appears in any Latent report until its backtest against real post-move outcomes is published on this page, with the method version it applies to. Revise the method and the backtest re-runs and republishes here. A rating whose accuracy you cannot check is marketing.

The backtest, published in full

Run on 3,597 completed moves abroad where we hold both a pre-move Level and the player's post-move league minutes, plus 1,257 permanent moves with a disclosed fee. Reproduce it with pipeline/level.py backtest against the same database.

Method
level-v2.3, run 2026-09-21
Fee correlation
Spearman(pre-move Level, fee actually paid) = +0.241 on 1,257 permanent exports with a disclosed fee. This is the strongest receipt: the ordering the Level produces lines up with what buyers paid.
Retention correlation
Spearman(Level, share of a nominal season played at the destination) = +0.105 raw, and +0.075 once destination difficulty, loan status and age are accounted for. The within-league performance composite on its own scores +0.091.
Quartiles
Holding a place is defined as dest league minutes >= 1350 in best of first two seasons. Top Level quartile 39% (n = 892) versus bottom quartile 28% (n = 905).
Exactly what we claim, and what we do not

The Latent Level is a corridor-calibrated cross-league rating with a published backtest. What the receipts support is that its ordering is consistent with the fees the market paid, and that its cross-league component carries a real if small association with minutes retention. What they do not support, on our own published numbers, is predicting whether an individual player will hold a place after a transfer. Once destination difficulty, loan status and age are accounted for, the player-specific part of the Level adds essentially nothing to that. So no Latent report will tell you a player is going to stick, and any provider who tells you theirs does should be asked for this page.

Limits of the validation set

The join between transfer records and our match data is by name and birth year, because no shared identifier exists, so transliterated names silently fail to match and the tested set skews toward the competitions whose names survive the join. By origin: SRB 443, CRO 368, GRE 273, ROU 233, CYP 222, BUL 210, GEO 191, EKS 188, BIH 180, CZE 161, SVN 154, KAZ 145, USLC 132, SVK 126, LIT 118, HUN 118, LAT 97, AZE 87, ALB 85, EST 56, UPL 10 ; the competition the brand is best known for contributes 10 of 3,597 tested moves, because our history there is two seasons deep. Retention also counts an injury as a failure, because we hold no injury data to separate it out.

The league coefficients, and what they are not

Each factor below is fitted from players who played a qualifying season in both competitions, comparing a man against himself across the border and removing the shared drift of a year's ageing. Where a pair has too few such players to carry itself, the fit leans on two public references — UEFA's five-year country coefficients and Transfermarkt's average squad value — blended in at the weight of 15 crossings, with the exchange rate between those references and our own scale fitted from the crossings rather than assumed. Nothing here is hand-set.

The earlier version of this number was fitted on how each league's exporters fared abroad, and we replaced it because that question is not the same question. Exporters are not a random sample: a league that sells a few well-chosen players into a friendly corridor scored higher than one that sends many squad players into hard ones. It buried whole competitions — the best Ukrainian season in this database ranked 411th, the best Canadian one 4,517th — and rated Latvia above Ukraine on what were really wartime distress moves. Both versions, and this reasoning, stay published.

League translation factors An exchange rate between competitions, not a verdict on them. A factor is only as good as the crossings behind it — the right-hand column is that evidence.
NodeFactorCrossings in fit
GRE1.16239
EKS1.13334
CZE1.09205
CRO1.08371
CYP1.07288
UPL1.0752
ROU1.06283
HUN1.05212
AZE1.02146
SVN1.02203
SVK1.01214
SRB1.01384
UPL21.000
BUL0.99194
KAZ0.98233
USLC0.9450
BIH0.94295
ALB0.9390
LAT0.92127
CPL0.9223
GEO0.91182
LIT0.90195
EST0.8746

Read the crossings column before the factor. Leagues that trade players with the rest of the portfolio have their number set by their own crossings; the thinnest ones are carried mostly by the public references, and their factor should be treated as provisional and will move as players cross. We publish the whole table, with its evidence, because the alternative is a hidden coefficient doing the same work unexamined.

Mean published Level by competition Shown so a Level you see elsewhere on this site has somewhere to be read against. Cohort averages differ by position too.
CompetitionPlayer-seasons Mean Level
GRE1,394462
EKS2,144448
CZE1,630427
UPL518422
CYP985421
CRO1,530421
ROU1,666419
HUN914412
AZE780404
SRB2,510399
SVK936398
SVN831394
KAZ1,131394
BUL1,302393
USLC3,607376
ALB521370
CPL142369
BIH951366
LAT867365
GEO1,040360
LIT829357
EST808346

See the flag ledger

07 · Audit gates

What runs before a number is allowed out

Every refresh passes automated integrity checks before anything reaches this site or a report. A competition that fails a blocking check does not publish until it is repaired. This has happened, and it held a publish.

  • Goal-attribution guard Goals credited to individual players are reconciled against match scorelines for every season of every competition. The expected band is roughly 0.95–0.98; the shortfall is own goals, which are correctly credited to nobody. Anything below it is investigated down to the individual match. This check caught a current season missing two entire matchdays of statistics, at 0.78.
  • Coverage detection Every statistic is checked, in every season, for partial coverage, so a statistic that phased in mid-season can never masquerade as a full-season rate.
  • Staleness recheck Recently played matches are re-queried against the source, because a match ingested within days of kickoff can be cached before its statistics exist and would otherwise stay empty forever.
Goal attribution, current state Player-credited goals over scoreline goals, all finished matches with a score. Not a league table and not derived from one.
CompetitionCreditedScoreline Ratio
KAZ1,7771,8240.974
HUN1,8521,9030.973
CRO2,8282,9100.972
BUL2,2002,2650.971
CPL2552630.970
BIH1,5251,5720.970
ALB8718980.970
USLC7,5887,8500.967
SRB5,0005,1700.967
ROU3,2543,3680.966
CZE3,1813,2980.965
EKS4,1544,3080.964
GRE2,4582,5490.964
UPL7127390.963
AZE1,4471,5030.963
LIT1,6541,7190.962
LAT1,9872,0670.961
GEO2,3032,4020.959
EST1,9512,0380.957
SVK1,7231,8070.954
SVN1,5581,6420.949
CYP1,9732,1300.926
08 · Stated limits

What we don't have, and won't fake

These are the limits of the data underneath every Latent product. Each is stated in any report it touches. None is ever papered over with an invented number, and this list is maintained as the working defect log, not as marketing.

  • No event locations, so no expected goals, heatmaps or pass maps We hold event counts, not pitch coordinates. Producing those charts would mean inventing the underlying geometry, so we don't produce them at all.
  • No physical or tracking data No distances, sprint counts or load. Where a question needs them, the report says the data does not exist rather than proxying it from something else.
  • No injury data: minutes gaps are an availability signal only We flag stretches where a player's club played at least three matches without him. The cause (injury, suspension, registration, selection) is not recorded anywhere in our sources and is never asserted. Calling these "injury history" would be a false claim.
  • No contract data in the match database Where contract status matters to a valuation, the report says it must be verified with the club or agent. In the destination-squad snapshot, contract end dates are published by the source for a large minority of players in two of the destination markets (58% and 64% coverage), so "contracts expiring" counts there are floors, never totals. Every other destination market: 82%+.
  • No league tables A table rebuilt from our match results can disagree with the official one, because awarded and technical results appear in a standings feed and not in match data. Rather than publish a table a visitor could check and find wrong, we publish none. The same figures are still safe as an opposition-strength weight, which is the only place they are used. Observed: 5 of 10 clubs off by 1–3 points in one in-progress season.
  • Ball-carry data exists only where it is collected See the table in section 02. Where it is absent or partial, carry metrics are suppressed rather than estimated, and no carry-based claim is made about a competition that has none.
  • Goalkeepers have no index, style, comparables or valuation Our metric set contains no shot-stopping, so a goalkeeper archetype or valuation would be fabricated. Goalkeepers get keeper-against-keeper percentiles on what we do measure, and nothing else, until a goalkeeping metric set exists.
  • Market value is matched by name, and the value model has no support at the top Our match database holds no market-value field, so values come from the transfer source, joined by name. The valuation residual model is fitted on a market whose mass sits well below €3m; above that it is out of support and we say so on the output. A large positive residual on an expensive player means the market is pricing something domestic percentiles do not measure; it does not mean "overpriced". Fit: R²(log) 0.41, median absolute log residual 0.17 (about ±50%), n = 2,864.
  • Corridor median fees are frequently zero On most corridors out of our markets the median fee is literally €0: free transfers dominate. A median like that describes the corridor's habit, not a player's worth, so fee ranges are built only from comparables that carried an actual fee, and a €0 median is never presented as a valuation.
  • Post-move minutes are a reference share, not an exact one We do not hold destination-league match counts, so post-move playing time is expressed against a 34-match reference season. The shares are comparable with each other and captioned as such, never as "share of his club's minutes".
  • Destination squads are a point-in-time snapshot Squad depth, ages and values behind any destination shortlist are current as of the snapshot date printed with them (2026-08-14). A snapshot older than 14 days re-scrapes automatically before a shortlist is computed, but a report read months later is reading that day's squads.
  • Identity between our data and the transfer records is a name match No shared identifier exists between the two, so players are joined by accent-stripped name plus birth year, and ambiguous names are dropped rather than guessed. Transliterated names fail silently. This limits the backtest, the ledger and every comparable-player outcome, in the same direction each time: it loses real matches, it does not invent them.
  • The opposition adjustment is coarse Opponent quality is points-per-match from our own results, bounded to ±5% of the composite. Squad-value data for our own clubs was never collected, so nothing finer is available, and early in a season the input is noisy.
  • A handful of matches carry no usable data, permanently Three matches across the database are recorded as finished with no scoreline and no statistics at source; two more carry a scoreline but no player statistics and cannot be repaired. Four goals are unattributable as a result. No player metric is affected (no statistics means nothing enters a season total), but a match count is off by those matches where they fall.
  • The statistics source is an unofficial public endpoint It is undocumented and could close. We mitigate by caching everything we read, requesting slowly, and publishing only our own derived metrics, never the source's own player rating. Licensed event data is the upgrade path once revenue justifies it, and it would remove several of the limits above.
09 · Reproducing it

Check us

The two pages that exist to be checked are this one and the ledger. Everything on both is generated from the databases at build time, so neither can drift from what the data says without the build changing.

Ledger
446 published flags, 136 of them gradeable, with the date each was first published and an explicit "too early to grade" state. Open the ledger · the raw flag record.
Level backtest
pipeline/level.py backtest: rebuilds the numbers in section 06 from the same tables, including the per-move rows behind them.
Percentiles
Every percentile on the site is printed with its cohort size. If a cohort looks too small to you, it is stated rather than hidden, and below ten it is not published at all.
Contradictions
If a number on this site disagrees with something you can verify, tell us and we will publish the correction here rather than quietly change it. info@latentscouting.com

Commission a report The flag ledger