← All guides
Product Release

Snap Share Is Now in the API

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.

Watch it run: the season-replay script below, on Amon-Ra St. Brown's 2021 rookie year (1:00, with captions).

Why snap share

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.

The lead signal: his 2021 rookie breakout

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:

WeekSnap sharePPRSnap 3wkPPR 3wk
873%7.671.08.6
1061%10.165.38.8
1185%5.873.07.8
1298%6.381.37.4
1396%24.893.012.3
1475%15.389.715.5
1569%23.580.021.2
1688%26.077.321.6
1784%35.480.328.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.

This is the honest case for snap share, and note that it cuts against the obvious use. The weeks where snap share is most valuable are exactly the weeks it disagrees with the box score. If you only trust it when it confirms the points, you've thrown away the edge.

What shipped

Coverage: 2020–2026 regular season (the current season updates weekly) (weeks 1–18) for every fantasy-relevant player in the dataset — roughly 1,200 players and 3,900 player-seasons. Percentages are returned as 0–100. Sourced from nflverse / Pro-Football-Reference game-level snap counts, which begin in 2013 league-wide.

1. Pull one player

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:

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).

2. The floor: don't panic-sell a bad week

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.

SeasonSeason snap%Worst PPR weekSnap% that week
202389.85.1 (Wk 14)88%
202488.34.3 (Wk 1)98%
202585.26.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 }
  }
}

3. Replay a season as it happened

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}")
⚠️ Weeks played ≠ weeks with snaps. St. Brown's Week 7 2021 is a live example: 43 offensive snaps, no fantasy line in the table. A blocking tight end hits the same case routinely, and the reverse happens too — a special-teams score with zero offensive snaps. Weeks missing from one side omit the corresponding fields rather than reporting a misleading zero, so check for the key rather than trusting a 0.

4. Spot the injury weeks

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.

5. Scan a whole position for role changes

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.

Ask Claude instead

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?"

Notes and caveats

Next steps