← All guides

Player News & Injury Feed

The News feature gives every player a running feed of recent headlines — each one tagged by impact so you can tell an injury designation apart from a puff piece. This guide covers the data model, how to pull and filter it, how to seed coverage for players the dataset hasn't picked up yet, and how to render it as a live feed.

What you'll build: a compact, impact-tagged news feed for any watchlist of players — the kind you'd drop into a dashboard, a Discord bot, or a pre-kickoff check.

Endpoints used

A player ID is "{Player Name}#{POS}" — e.g. Malik Nabers#WR. URL-encode it (the # becomes %23).

The news data model

Each item in the news array is one headline:

{
  "headline": "Nabers (knee) full participant at Wednesday practice",
  "impact": "injury",
  "source": "espn-nfl",
  "url": "https://www.espn.com/nfl/story/_/id/00000000",
  "published_at": "2026-09-10T17:22:00Z"
}

The impact tag is what makes the feed useful — it lets you color, filter, or prioritize headlines by what they actually mean for a lineup:

impactWhat it covers
injuryInjury designations, practice participation, IR / activations, game-time decisions
roleDepth-chart moves, snap/target/touch share, promotions and benchings
transactionSignings, trades, releases, suspensions, roster moves
generalEverything else — previews, features, and analysis

1. Pull news for a player

curl -H "x-api-key: YOUR_KEY" \
  "https://api.gridirondata.com/api/v1/news/Malik%20Nabers%23WR?days=7"
{
  "player_id": "Malik Nabers#WR",
  "days": 7,
  "count": 2,
  "news": [ /* newest first */ ]
}

Three query params shape the response:

2. Filter to what matters

Ask the API for a single category server-side, or pull everything and group client-side. Server-side filtering keeps payloads small when you only care about, say, injuries:

curl -H "x-api-key: YOUR_KEY" \
  "https://api.gridirondata.com/api/v1/news/Malik%20Nabers%23WR?impact=injury&days=14"

3. Seed coverage for a player with no news

Tracking a deep-bench player or a just-promoted backup the dataset hasn't covered yet? A count: 0 response hands you a ready-made link to request one:

{
  "player_id": "Max Bredeson#RB",
  "count": 0,
  "news": [],
  "message": "No news found for Max Bredeson#RB in the last 14 days.",
  "request_scrape": { "method": "POST",
    "href": "https://api.gridirondata.com/api/v1/news/Max%20Bredeson%23RB/request" }
}
curl -X POST -H "x-api-key: YOUR_KEY" \
  "https://api.gridirondata.com/api/v1/news/Max%20Bredeson%23RB/request"
# 202 Accepted — the scrape runs asynchronously; poll GET /news again shortly after
🔁 Coverage grows as you use it: every player you request through POST /news/{player_id}/request is added to the automated scraper — so your first lookup seeds them, and every run after that stays fresh with no extra work.

4. Build the feed

Pull news for a watchlist, merge into one timeline, and render newest-first with an impact label. Swap the print for HTML, a Discord embed, or a dashboard card — the shape is the same.

import requests
from urllib.parse import quote

API = "https://api.gridirondata.com/api/v1"
H = {"x-api-key": "YOUR_KEY"}

WATCHLIST = ["Malik Nabers#WR", "Bijan Robinson#RB", "Trey McBride#TE"]
LABEL = {"injury": "🔴 INJURY", "role": "🟠 ROLE",
         "transaction": "🔵 MOVE", "general": "⚪ NEWS"}

def player_news(pid, days=7, limit=10):
    r = requests.get(f"{API}/news/{quote(pid, safe='')}",
                     headers=H, params={"days": days, "limit": limit})
    r.raise_for_status()
    return r.json()

feed = []
for pid in WATCHLIST:
    data = player_news(pid)
    if data.get("count", 0) == 0:                 # no coverage yet — seed it
        link = data.get("request_scrape")
        if link:
            requests.request(link["method"], link["href"], headers=H)
        continue
    for item in data["news"]:
        feed.append((pid, item))

# One timeline, newest first
feed.sort(key=lambda x: x[1]["published_at"], reverse=True)

print("=== PLAYER NEWS FEED ===")
for pid, item in feed:
    name = pid.rsplit("#", 1)[0]
    tag = LABEL.get(item["impact"], item["impact"].upper())
    print(f"{tag:12} {name:20} {item['headline']}")
    print(f"{'':12} {item['url']}  ({item['source']})")

Keeping it fresh

News items refresh throughout the day and roll off after ~30 days, so a small days window (5–7) keeps the feed tight and current. For a live dashboard, poll every 15–30 minutes; for a weekly check, run it Sunday morning with days=3 to catch just the pre-kickoff updates. Because on-demand scrapes are asynchronous, request any uncovered players on the first pass, then re-poll them a minute later.

Next steps