← All methods

Build-up & Directness

Summary

Per-team-season aggregates describing how teams move the ball forward. The standing pass-accuracy number on the team-stats pages can't tell the difference between a possession side knocking it sideways accurately and a direct side hitting completed long balls — both score high on accuracy. The build-up page splits the question into long-ball share, forward-zone pass share, and a per-match own-to-opposition long-pass rate.

A composite directness index is z-scored within each season (mean of the three rate z-scores) so positive = more direct than the league average for that season. The index is bounded the same way every season, but is not directly comparable across seasons in absolute terms.

The feature lives at /analysis/build-up and the underlying ratios are also exposed on the team quadrant page (Directness, Forward vs Backward).

Inputs

Stored column SDP key Meaning
total_pass totalPass Pass attempts. Denominator for accuracy + long-ball share.
accurate_pass accuratePass Completed passes. Denominator for fwd-zone share.
total_long_balls totalLongBalls Long balls attempted.
accurate_long_balls accurateLongBalls Long balls completed.
long_pass_own_to_opp longPassOwnToOpp Long passes that crossed the halfway line.
open_play_pass openPlayPass Open-play passes (excludes set pieces).
accurate_fwd_zone_pass accurateFwdZonePass Completed passes into the forward zone.
backward_pass backwardPass Backward passes.
fwd_pass fwdPass Forward passes.
directness_index derived Z-scored composite (within season). See below.

Sums are over regular-season team-matches only (matches.is_playoff = 0), matching every other team-season aggregate.

All nine keys are present in every season the feed covers (2019-2025+), so there is no per-season metric availability gap.

Derived rates

Computed server-side on read from the stored counters. None when the denominator is zero.

  • Long-ball share = total_long_balls / total_pass — share of attempted passes that were long. The headline directness signal.
  • Long-ball accuracy = accurate_long_balls / total_long_balls — informational; used to disambiguate "direct and accurate" from "direct and chaotic" on the quadrant.
  • Forward-zone share = accurate_fwd_zone_pass / accurate_pass — share of completed passes that went into the forward zone. Read as "how vertical is the build-up".
  • Own → Opp / match = long_pass_own_to_opp / matches — long passes that crossed the halfway line, per match. The "switch / over the top" signal. No clean share denominator (see caveats).
  • Fwd / Back ratio = fwd_pass / backward_pass — unitless directness check; immune to volume.
  • Pass accuracy = accurate_pass / total_pass — exposed for context so users can see the standing pass-accuracy alongside directness on the same page.

Directness index

A composite axis for cross-team comparison within a season:

directness_index = mean(
    z(long_ball_share),
    z(forward_zone_share),
    z(own_to_opp_per_match),
)

Z-scores are computed within each season's cohort (typically 8 teams). Components with a zero standard deviation in a given season (rare) are dropped from that season's average rather than treated as 0, so a team isn't penalised for a flat metric.

Range varies by season but typically [−1.5, +1.5]. Positive = more direct than the league mean for that season.

Data caveats

  • Z-scored within season, so not cross-season-comparable in absolute terms. A team's directness_index of +1.0 in 2024 is not "the same" as +1.0 in 2025; both mean "1 SD more direct than that season's league." Same caveat as team_style already documents. Within a season, the ranking is comparable directly. The underlying rates (long-ball share, fwd-zone share) are absolute and cross-season- comparable.
  • longPassOwnToOpp has no clean share denominator. The feed doesn't separate "long passes attempted from own half" from all longs, so we can't compute a "share of own-half longs that crossed halfway" rate. We surface a per-match volume instead. This per-match rate is sensitive to tempo (a team that gets the ball more in their own half will hit more own-to-opp longs), but it's the honest available signal.
  • Forward-zone share denominator is accurate_pass, not total_pass. SDP only emits the accurate count for fwd-zone passes, so the matching denominator is also accurate-only. This means the two share ratios on the page (long-ball share vs fwd-zone share) live on different denominators — read them independently, not as add-up shares.
  • Open-play vs all passes. total_pass includes set-piece deliveries (corners, free-kick crosses), so a team that plays a lot of set pieces will have a slightly inflated long-ball share. The effect is small in CPL (set-pieces account for under 5% of passes most seasons) but worth noting.
  • 2020 Island Games had 7-11 matches per team in a neutral bubble without travel, rest variance, or crowds. Rows from 2020 are flagged on the page and should not be compared directly to other seasons.

Why this is z-scored but pressing isn't

Pressing has a natural bounded composite ((att − def) / total is already in [−1, 1]) so z-scoring would hide a clean signal behind a dimensionless score. Directness has no comparable natural composite — the three component rates live on different denominators (total_pass, accurate_pass, matches), so z-scoring is the only honest way to combine them into a single ranking axis. The trade-off is the loss of absolute cross-season comparability.