Skip to content
MMA Calendar
MMA Fight Data API · Code guide

How do I get UFC fight stats round by round?

Request a bout's rounds from the MMA Fight Data API: api.fight_rounds(fight_id) in Python or fightRounds(fightId) in JavaScript. You get one row per fighter per round with knockdowns, significant and total strikes landed and attempted, takedowns, submission attempts, reversals and control time, plus target and position splits where the record carries them. A bout's id is on its event's card.

Free plan: 1,000 requests a month, no card. Paid plans from $19/mo.

Endpoints used

Endpoints used
Method & pathWhat it returnsPlan
GET /v1/fights/{id}/roundsOne bout with its result, per-fight totals for both corners, and round-by-round statistics.All plans
GET /v1/fights/{id}/statsPer-fight totals for both corners: strikes by target and position, takedowns, control time.All plans
GET /v1/events/{slug}One event with its full fight card (both corners, results when completed), venue and event-level broadcasts.All plans
GET /v1/fights/searchSearch completed bouts by title fight, finish method, division, fighter, winner or date range: the last title fight to end by knockout in one call.All plans

The code

curl fetches the ten round rows of Petr Yan vs Merab Dvalishvili at UFC 333. The Python block pivots them into a round-by-fighter table with pandas; the JavaScript block prints accuracy, takedowns and control time per round.

Every block runs as shown with your API key in the UFCAL_API_KEY environment variable. Python uses pip install ufcalendar and JavaScript or TypeScript uses npm install @ufcalendar/sdk; any HTTP client works too.

curl
curl "https://api.ufcalendar.com/v1/fights/83680/rounds" \
  -H "Authorization: Bearer $UFCAL_API_KEY"
Python
# pip install ufcalendar pandas
import pandas as pd
from ufcalendar import FightAPI

api = FightAPI()  # reads UFCAL_API_KEY from the environment

# Find the bout on its card (or use GET /v1/fights/search)
card = api.event("ufc-333-2026-10-24")["card"]
fight = next(f for f in card if f["fighter_b"]["slug"] == "merab-dvalishvili")
names = {"a": fight["fighter_a"]["name"], "b": fight["fighter_b"]["name"]}

df = pd.DataFrame(api.fight_rounds(fight["id"]))  # one row per fighter per round
df["fighter"] = df["corner"].map(names)

print(df.pivot_table(index="round", columns="fighter", values="sig_strikes_landed"))
print(df.groupby("fighter")[["sig_strikes_landed", "takedowns_landed", "control_time_sec"]].sum())
JavaScript
// npm install @ufcalendar/sdk
import { FightAPI } from "@ufcalendar/sdk";

const api = new FightAPI(); // reads UFCAL_API_KEY from the environment

const fight = await api.fight(83680); // Petr Yan vs Merab Dvalishvili, UFC 333
const name = { a: fight.fighter_a.name, b: fight.fighter_b.name };

for (const r of await api.fightRounds(fight.id)) {
  const acc = r.sig_strikes_attempted ? Math.round((100 * r.sig_strikes_landed) / r.sig_strikes_attempted) : 0;
  console.log(`R${r.round} ${name[r.corner]}: ${r.sig_strikes_landed}/${r.sig_strikes_attempted} sig. strikes (${acc}%), ` +
    `${r.takedowns_landed}/${r.takedowns_attempted} takedowns, ${r.control_time_sec}s control`);
}

Sample response

A real response from the live API, trimmed for length. … marks removed fields.

GET /v1/fights/83680/rounds
{
  "data": [
    {
      "round_number": 1,
      "fighter_id": 360,
      "knockdowns": 0,
      "sig_strikes_landed": 6,
      "sig_strikes_attempted": 11,
      "takedowns_landed": 0,
      "takedowns_attempted": 0,
      "control_time_sec": 5,
      "head_landed": null,
      "body_landed": null,
      "leg_landed": null,
      "corner": "a",
      "round": 1
    },
    {
      "round_number": 1,
      "fighter_id": 194,
      "knockdowns": 0,
      "sig_strikes_landed": 8,
      "sig_strikes_attempted": 40,
      "takedowns_landed": 1,
      "takedowns_attempted": 10,
      "control_time_sec": 41,
      "head_landed": null,
      "body_landed": null,
      "leg_landed": null,
      "corner": "b",
      "round": 1
    },
    …
  ],
  "meta": { "fight_id": 83680 }
}

Notes and pitfalls

  • corner is a or b and matches fighter_a and fighter_b on the bout; round is the round number. The bout's totals for both corners come from the stats endpoint, with the same columns.
  • A value the record does not carry is null, never 0. Per-round target and position splits can be null on a bout whose totals have them, so test for null before you chart.
  • Control time is in seconds. The rounds add up to the fight totals for strikes, takedowns and control time.
  • The same endpoint works for every promotion with per-round stats; check capabilities.rounds on GET /v1/orgs. Bare-knuckle bouts carry punch counts, not takedowns.

Related pages

More code guides

All code guides →

UFCalendar is an independent publication, not affiliated with UFC/Zuffa/TKO, PFL, OKTAGON MMA, BKFC, RIZIN FF or any promotion. Organization names are used to describe the data. Terms of service · Refund Policy

How do I get UFC fight stats round by round? | UFCalendar