The surface changes how hard it is to hold serve, and it changes it a lot. Across 2,239,440 service games in completed singles matches, the server held 74.43% on grass, 69.95% on hard and 65.98% on clay — a spread of 8.45 percentage points. What it does not meaningfully change is whether a match can be recovered: the rate of winning after losing the first set moves only 0.73 points across the same three surfaces.
Put together, that is the finding: the surface decides how the points go, not who ends up winning.
How often is serve held on each surface?
| Surface | Service games | Held | Robustness check |
|---|---|---|---|
| Grass | 74,673 | 74.43% | 74.78% |
| Hard | 1,222,994 | 69.95% | 70.26% |
| Clay | 941,773 | 65.98% | 66.23% |
A server on grass wins roughly three service games in four; on clay, closer to two in three. Over a ten-game set that is the difference between a comfortable hold pattern and a set where breaks are routine.
The right-hand column is a robustness check, not a second measurement. Holds are identified by walking the point-by-point tape and attributing each completed game to whoever was serving during it; the check re-runs the same calculation using only games where the server provably alternated to the next game, which is the signature of a cleanly recorded game. It moves every figure by less than a third of a point, so the ordering is not an artefact of how games are detected.
Who holds serve, by tour — and the check that matters
| Tour | Service games | Held |
|---|---|---|
| ATP | 230,715 | 78.62% |
| Challenger (men) | 622,018 | 74.10% |
| ITF (men) | 529,948 | 70.26% |
| WTA | 266,503 | 64.36% |
| Challenger (women) | 92,396 | 60.40% |
| ITF (women) | 553,157 | 58.93% |
This is the external check on everything above. Tour-level hold rates are widely published: roughly 79% for the ATP tour and roughly 64% for the WTA tour. The method here — walking a point-by-point tape, crediting each completed game to whoever was serving — was not tuned to reproduce either, and lands on 78.62% and 64.36%. Two independent figures, both matched, from data that knows nothing about them.
It also shows the surface is not the biggest thing on the board. The gap between the men's and women's main tours is 14.26 points, against 8.45 between grass and clay. And hold rate falls with the tier inside each: 78.62 → 74.10 → 70.26 for the men, 64.36 → 60.40 → 58.93 for the women. Serve dominance is mostly about who is serving, then about how far down the rankings you are, and only then about the court.
One consequence worth keeping in mind when reading the surface table: it pools every tour, and the tours do not play the same surface mix. The surface ordering holds because the method and its possible biases apply identically to all three, but a grass figure drawn mostly from one tier is not directly comparable to a clay figure drawn mostly from another.
Does that show up in tiebreaks?
Directly, and in the same order.
| Surface | Sets reaching a tiebreak | Matches with at least one |
|---|---|---|
| Grass | 15.91% | 31.73% |
| Hard | 12.31% | 25.28% |
| Clay | 10.72% | 22.52% |
This is the same fact told twice. If serve is harder to break, more sets arrive at 6-6, and grass produces about half again as many tiebreaks per set as clay. Two independent measurements — one counting games, one counting sets — put the surfaces in the same order, which is the main reason to believe either.
So does the surface decide matches?
Barely. On the same corpus, the rate at which a player wins after losing the first set is:
| Surface | Matches | Comeback rate |
|---|---|---|
| Grass | 3,593 | 17.20% |
| Clay | 47,944 | 16.79% |
| Hard | 61,751 | 16.47% |
0.73 percentage points, top to bottom. For comparison, the same measurement varies by 3.03 points between tours and by 14.74 points depending on how close the first set was. Surface is the weakest of the three by a wide margin — about a twentieth of the effect of the first-set margin.
That is not a contradiction. Holding serve more often on grass helps both players roughly equally, so it changes the texture of the match — longer hold sequences, more tiebreaks, fewer breaks — without much changing who is ahead. The first-set margin, by contrast, is information about the two players rather than about the court.
How this was measured
- Corpus. Completed best-of-three singles matches on ATP, WTA, Challenger and ITF, 2023-01-01 to 2026-09-14, counted 14 September 2026. Only matches the feed marks
Finished— retirements and walkovers are excluded. - A game is counted when the game score advances by exactly one for one player and is unchanged for the other, within the same set. It is credited to the player shown as serving on the preceding tape row.
- Tiebreak games are excluded from hold rates. Serve alternates within a tiebreak, so "who held" is not a meaningful question there; tiebreaks are counted separately in the table above.
- The absolute level is corroborated, not assumed. Games are identified from tape transitions, so a tape with gaps contributes fewer detectable games — which is why the tour table above matters: it reproduces the widely published ATP (~79%) and WTA (~64%) hold rates to within half a point, on a method tuned to neither. The pooled surface figures are lower than the ATP number because the corpus is mostly ITF and Challenger, where serve is held less often.
Reproducing it
Both numbers come from one endpoint on the Basic ($9.99/mo) tier. Every tape row carries the game score and the server, which is all a hold calculation needs:
import os, requests
BASE = "https://api.livetennisapi.com/api/public/v1"
H = {"X-API-Key": os.environ["LIVE_TENNIS_API_KEY"]}
tape = requests.get(f"{BASE}/history/matches/18953", headers=H, timeout=30).json()
held = played = 0
prev = None
for row in tape.get("states", []):
if prev and not row.get("is_tiebreak"):
g, pg = row["games"], prev["games"] # games per set, current set last
if sum(g) == sum(pg) + 1 and len(g) == len(pg):
winner = 1 if g[-1] > pg[-1] else 2 # whoever's game count advanced
played += 1
held += (winner == prev["server"]) # the server DURING that game
prev = row
print(played, held, round(100 * held / played, 1) if played else None)
Note the two details that matter: the game score is an array per set, so compare the last element and only within one set; and the server to credit is the one on the previous row, because by the time the game count advances the serve has already passed to the other player.
Endpoint detail is on the point-by-point history page and the full reference. Tiers and limits: pricing.