Released September 2026 · Available on every plan, no version bump required
In Week 12 of 2021, Amon-Ra St. Brown played 98% of Detroit's offensive snaps and scored 6.3 points. Two weeks later he started a run that made him a WR1. Snap share knew first — and it's now in the API for every fantasy-relevant player back to 2020, on a new /snaps endpoint and joined onto the stats you already pull.
Fantasy points are a lagging indicator. A receiver can win a starting job in Week 11 and still post 5.8 points, because targets, game script and touchdown luck all sit between "on the field" and "in the box score." Snap share skips that noise. If the coaching staff moved a player from 60% of offensive plays to 95%, the decision has already been made — whatever the stat line says that Sunday.
Amon-Ra St. Brown's career is the best single illustration of this in the dataset, because it contains all three ways snap share earns its keep: it caught his breakout two weeks early, it has confirmed his workhorse role ever since, and it flags his injury weeks cleanly. We'll walk through each.
Everyone remembers the finish — six straight double-digit weeks, a 35.4-point Week 17. Almost nobody could act on it, because by the time the points arrived he was rostered everywhere. Here's what the API returns for that season, with a trailing 3-week average on both columns:
| Week | Snap share | PPR | Snap 3wk | PPR 3wk |
|---|---|---|---|---|
| 8 | 73% | 7.6 | 71.0 | 8.6 |
| 10 | 61% | 10.1 | 65.3 | 8.8 |
| 11 | 85% | 5.8 | 73.0 | 7.8 |
| 12 | 98% | 6.3 | 81.3 | 7.4 |
| 13 | 96% | 24.8 | 93.0 | 12.3 |
| 14 | 75% | 15.3 | 89.7 | 15.5 |
| 15 | 69% | 23.5 | 80.0 | 21.2 |
| 16 | 88% | 26.0 | 77.3 | 21.6 |
| 17 | 84% | 35.4 | 80.3 | 28.3 |
Look at Weeks 11 and 12. Snap share jumps to 85% and then 98% — the highest marks of his season — while he scores 5.8 and 6.3. His trailing 3-week PPR average actually fell over those two weeks, from 8.8 to 7.4. Any manager reading the box score dropped him. Any manager reading snap share saw Detroit had just handed a rookie a near-every-down role, and got him for free.
Week 13 is when the points caught up: 24.8, and he never looked back. The signal led the payoff by two weeks — which is the entire window in which a waiver claim is cheap.
/api/v1/snaps/{player_id}?season=2021&trend=4 — per-week snap share, season average, and a trailing-window trend/api/v1/snaps?name=Amon-Ra+St.+Brown&position=WR — same thing by name and position/api/v1/stats/{player_id}/{season} — now carries snap_pct on every weekly entry plus a snap_counts block0–100. Sourced from nflverse / Pro-Football-Reference game-level snap counts, which begin in 2013 league-wide.
curl -H "x-api-key: YOUR_KEY" \
"https://api.gridirondata.com/api/v1/snaps/Amon-Ra%20St.%20Brown%23WR?season=2021&trend=4"
{
"player_id": "Amon-Ra St. Brown#WR",
"player_name": "Amon-Ra St. Brown",
"position": "WR",
"season": "2021",
"games": 17,
"games_with_snaps": 17,
"season_snap_pct_avg": 74.8,
"recent_snap_pct_avg": 84.0,
"trend_weeks": 4,
"trend_delta": 9.2,
"totals": {
"games": 17,
"offense_snaps": 816,
"offense_pct_avg": 74.8,
"st_snaps": 81,
"st_pct_avg": 18.6
},
"weekly_snaps": [
{ "week": 1, "offense_snaps": 59, "snap_pct": 64.0, "st_snaps": 9,
"st_pct": 29.0, "team": "DET", "opponent": "SF" },
{ "week": 12, "offense_snaps": 48, "snap_pct": 98.0, "st_snaps": 3,
"st_pct": 13.0, "team": "DET", "opponent": "CHI" }
],
"source": "nflverse / Pro-Football-Reference game-level snap counts"
}
The three fields that do the work:
season_snap_pct_avg — his baseline role across the seasonrecent_snap_pct_avg — his role over the last trend weeks he actually playedtrend_delta — the difference. Positive means the role is growing.Weeks with zero offensive snaps are inactives, not "played but never on the field," so they're excluded from both averages. That keeps a bye or a healthy scratch from faking a collapse in the trend.
trend_delta is damped on a completed season. For 2021 it reads +9.2, not the +25 you'd expect from the Week 11–12 jump — because the season average it compares against already includes those late weeks. On a season still in progress the stored data only holds weeks played so far, so the comparison is naturally as-of-now and the signal is sharper. For historical replay, compute your own split (see §3).
The unglamorous use of snap share is the one you'll reach for most. St. Brown opened 2024 with 4.3 points against the Rams. Panic in every league chat. His snap share that week was 98% — the highest of his season. Nothing had changed about his role; he'd had a bad game against a good defense.
| Season | Season snap% | Worst PPR week | Snap% that week |
|---|---|---|---|
| 2023 | 89.8 | 5.1 (Wk 14) | 88% |
| 2024 | 88.3 | 4.3 (Wk 1) | 98% |
| 2025 | 85.2 | 6.2 (Wk 11) | 97% |
In all three cases the role was untouched. That's the check worth running before you trade or bench anyone: did the snaps move, or just the points? If the snaps held, the bad week is noise.
You don't need a second request to run it. Snap share is joined onto the stats endpoint you're already calling:
curl -H "x-api-key: YOUR_KEY" \
"https://api.gridirondata.com/api/v1/stats/Amon-Ra%20St.%20Brown%23WR/2024"
{
"weekly_stats": {
"1": { "points": 4.3, "opponent": "LA", "snap_pct": 98.0, "offense_snaps": 60 }
},
"snap_counts": {
"weekly": { ... },
"totals": { "games": 17, "offense_snaps": 1010, "offense_pct_avg": 88.3 }
}
}
To see the signal the way a manager would have in real time, compute the trailing averages yourself from weekly_snaps. This is the script that produced the 2021 table above:
import requests
from urllib.parse import quote
API = "https://api.gridirondata.com/api/v1"
H = {"x-api-key": "YOUR_KEY"}
PID, SEASON, WINDOW = "Amon-Ra St. Brown#WR", "2021", 3
enc = quote(PID, safe="")
snaps = requests.get(f"{API}/snaps/{enc}", headers=H,
params={"season": SEASON}).json()["weekly_snaps"]
stats = requests.get(f"{API}/stats/{enc}/{SEASON}", headers=H,
params={"scoring": "ppr"}).json()["weekly_stats"]
print(f"{'WK':>3} {'SNAP%':>6} {'PPR':>6} {'SNAP 3wk':>9} {'PPR 3wk':>8}")
history = []
for w in snaps:
if not w["snap_pct"]: # inactive — not a role change
continue
entry = stats.get(str(w["week"]))
# A week can have snaps but no fantasy line. Keep it as None rather than
# coercing to 0.0, which would fake a bad game.
pts = float(entry["points"]) if entry and entry.get("points") is not None else None
history.append((w["snap_pct"], pts))
recent_snaps = [s for s, _ in history[-WINDOW:]]
recent_pts = [p for _, p in history[-WINDOW:] if p is not None]
print(f"{w['week']:>3} {w['snap_pct']:>6.0f} "
f"{('%.1f' % pts) if pts is not None else '—':>6} "
f"{sum(recent_snaps) / len(recent_snaps):>9.1f} "
f"{(sum(recent_pts) / len(recent_pts)) if recent_pts else 0:>8.1f}")
0.
A snap share that collapses without hitting zero is almost always an in-game exit, not a benching. St. Brown's 2025 Week 13 reads 6% — 4 snaps, with no fantasy line at all. His 2022 has two more: 32% in Week 5 and 17% in Week 7, both ankle.
def injury_flags(player_id, season, floor=0.4):
"""Weeks where snap share fell well below the player's own baseline."""
d = requests.get(f"{API}/snaps/{quote(player_id, safe='')}",
headers=H, params={"season": season}).json()
baseline = d["season_snap_pct_avg"]
return [
(w["week"], w["snap_pct"], w["opponent"])
for w in d["weekly_snaps"]
# Zero means inactive (already known). A partial week is the signal.
if 0 < w["snap_pct"] < baseline * floor
]
print(injury_flags("Amon-Ra St. Brown#WR", "2025"))
# [(13, 6.0, 'GB')]
print(injury_flags("Amon-Ra St. Brown#WR", "2022"))
# [(7, 17.0, 'DAL')] <- Week 5 (32%) is missed: see below
Run that on 2022 and you get Week 7 but not Week 5. His baseline was 77.6%, so floor=0.4 puts the cutoff at 31.0% — and Week 5's 32% clears it by a single point. That's not a bug to paper over; it's the honest shape of the problem. A fixed fraction of a season average is a blunt threshold, and where you set it decides whether you catch a limited-snap game or only a full exit. Loosen to floor=0.5 and both weeks flag, along with more false positives from blowouts and rest. Tune it against your own tolerance rather than trusting the default.
This matters most for the week after. A player who left early last Sunday but practiced in full is a buy; the snap log tells you the exit happened, and the news endpoint tells you what it was.
The same logic across a position group finds the players whose roles are expanding right now — the next St. Brown, in the two-week window before the points arrive:
SEASON, MIN_GAMES, TREND = "2024", 8, 4
def snaps(player_id):
r = requests.get(f"{API}/snaps/{quote(player_id, safe='')}", headers=H,
params={"season": SEASON, "trend": TREND})
return r.json() if r.status_code == 200 else None
pool = []
for pos in ("RB", "WR", "TE"):
r = requests.get(f"{API}/players", headers=H, params={"position": pos})
pool += [p["player_id"] for p in r.json()["players"]]
risers = []
for pid in pool:
d = snaps(pid)
# 404 simply means no snap data for that player-season.
if not d or d["games_with_snaps"] < MIN_GAMES:
continue
risers.append((d["trend_delta"], pid, d["position"],
d["season_snap_pct_avg"], d["recent_snap_pct_avg"]))
risers.sort(reverse=True)
print(f"{'DELTA':>6} {'PLAYER':26} {'POS':4} {'SEASON':>7} {'LAST 4':>7}")
for delta, pid, pos, season_avg, recent in risers[:10]:
print(f"{delta:+6.1f} {pid.rsplit('#', 1)[0]:26} {pos:4} "
f"{season_avg:7.1f} {recent:7.1f}")
Run against 2024, that returns:
DELTA PLAYER POS SEASON LAST 4
+37.2 Daniel Bellinger TE 33.1 70.2
+33.6 Payne Durham TE 39.7 73.2
+32.0 Parker Washington WR 55.3 87.2
+28.8 Malik Washington WR 44.7 73.5
+28.8 Cedric Tillman WR 54.9 83.8
+26.0 Chase Brown RB 62.8 88.8
+25.0 Isaac Guerendo RB 24.5 49.5
+24.6 Nick Westbrook-Ikhine WR 69.9 94.5
+24.2 Stone Smartt TE 20.6 44.8
+23.7 Olamide Zaccheaus WR 42.1 65.8
Note what this list is and isn't. It surfaces role change, not value. Chase Brown at +26.0 was a genuine backfield takeover. Daniel Bellinger at the top was a blocking tight end whose snaps ballooned without the targets to match — on the field, but not in the offense. Snap share tells you a player is playing; you still have to ask what he's doing there. Cross-reference target share from /stats and the two separate cleanly.
The 2021 St. Brown version of this list would have had him at a similar delta in Week 12 — alongside plenty of Bellingers. That's the honest cost of the signal: it is early, and being early means being wrong more often. Size your waiver claims accordingly.
If you use the MCP server, snap share landed there too as get_snap_share. Update to the latest server and you can just ask:
"Did Amon-Ra St. Brown's snap share move before his 2021 breakout,
or at the same time as the points?"
/stats before acting.st_snaps / st_pct. St. Brown's 2021 carries 81 ST snaps as a rookie returner and almost none after — a decent proxy for how a coaching staff sees a young player's role.