# GET /v2/fixtures/{id}/tracking/players

Group: Tracking data

Player tracking on NBA games (since 2026-11-13): every player on the court and the ball, five frames a second, in frame order — who has the ball, the game and shot clocks, each player’s name, shirt number, side and position. Without a cursor the newest frames (the last 30 seconds by default); after a cursor a page. Enterprise plan only.

Plans: Enterprise (other plans get 403 endpoint_not_in_plan).

Note: NBA games only — TrackingSummary.players says whether a fixture has it; empty for every other fixture. Positions are in the court frame of the other basketball data: x 0–100 along the court, y 0–100 across, the home side shooting at x = 100 in every period (the teams change baskets at half-time; the frame does not). The direction each team plays is read per period from where its shots go up, so in the first seconds of a match, before its first shot, a live frame can be mirrored; a later read is corrected. Half-time has no frames. ball.height is in metres (the rim is at 3.05). Frames are received about 1–2 seconds behind play in batches of five a second that share their at: play them in frame order, 0.2 s apart. Recorded live only: a game not recorded live has none. Live: playerFrame frames on tracking:{id}.

## Parameters

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `id` | path | yes | our numeric id (positive integer) |
| `after` | query | no | only frames after this frame counter (PlayerFrame.frame; exclusive) — meta.next of the previous page |
| `since` | query | no | only frames received after this instant (ISO-8601, any offset; exclusive); ignored with after |
| `limit` | query | no | frames per page, 1–3000 (default 150 — 30 seconds) |
| `fps` | query | no | 5 (every frame, the default) or 1 (one frame a second) |

## Response

- `data`: `PlayerFrame[]`
- `meta`: count, hasNextPage, next (the after of the next page, or null)
- Objects: PlayerFrame (https://sportsapi.app/markdown/en/reference.md#playerframe)

## Errors

- 400 bad_request — after, since, limit or fps malformed
- 403 endpoint_not_in_plan — every plan but Enterprise
- 404 not_found — an id we never issued

Plus the common errors (https://sportsapi.app/markdown/en/docs.md#errors).

## Request

cURL:

```bash
curl -H "Authorization: Bearer sk_live_…" \
    "https://api.sportsapi.app/v2/fixtures/{id}/tracking/players"
```

TypeScript:

```ts
const { data, meta } = await client.tracking.players(id);
```

Python:

```python
res = client.tracking.players(id)
```

Go:

```go
res, err := client.Tracking.Players(ctx, id, &sportsapi.TrackingPlayersParams{})
```

CLI:

```bash
$ sportsapi tracking players <id>
```

## Example response

```json
{ "data": [
    { "frame": 731569, "at": "2026-11-13T03:00:06.453Z", "period": 4, "clock": 541, "shotClock": 20, "running": true,
      "possession": { "side": "home", "player": { "name": "John Doe", "shirtNumber": 9, "side": "home" } },
      "ball": { "x": 44.45, "y": 86.75, "height": 0.9 },
      "players": [ { "side": "home", "name": "John Doe", "shirtNumber": 9, "x": 43.86, "y": 90.03 }, … ] }, … ],
  "meta": { "count": 150, "hasNextPage": false, "next": null } }
```

---

Base URL: https://api.sportsapi.app. Send your API key as `Authorization: Bearer <key>` on every /v2 request; keys are created in the dashboard (https://sportsapi.app/dashboard).
HTML: https://sportsapi.app/docs/tracking/players · All docs: https://sportsapi.app/markdown/en/docs.md
