UFC Stats Scraper: MMA Fights, Fighters, Events, Round-by-Round avatar

UFC Stats Scraper: MMA Fights, Fighters, Events, Round-by-Round

Pricing

from $18.25 / 1,000 record returneds

Go to Apify Store
UFC Stats Scraper: MMA Fights, Fighters, Events, Round-by-Round

UFC Stats Scraper: MMA Fights, Fighters, Events, Round-by-Round

For MMA betting models, fantasy tools and analytics: official ufcstats.com data covering 788 events back to UFC 2 in March 1994. Every fight round by round, with significant strikes split by head, body and leg and by distance, clinch and ground, takedowns, control time and judges' scorecards.

Pricing

from $18.25 / 1,000 record returneds

Rating

0.0

(0)

Developer

NeverEmpty

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

UFC Stats Scraper - fights, fighters, events, round by round

For MMA analytics, betting models, fight previews and fighter scouting: official UFC fight statistics from ufcstats.com, the site the UFC itself publishes its numbers on — events, fights, fighters and every single round.

Most UFC scrapers give you the fight summary: who won, by what method, in which round. This one also opens every round and returns the significant strikes split by where they landed (head, body, leg) and from what position (distance, clinch, ground), for both fighters, plus control time and takedowns — the numbers you need to say how a fight was won, not just that it was. Judges' scorecards come back per judge, per fighter.

The whole history, in one request. UFCStats lists 788 events — the oldest is UFC 2 on 11 March 1994, the newest the card announced for next week (measured 8 September 2026) — and the entire event list comes back in a single request.

No API key, no login. Export as JSON, CSV or Excel.

What you get

Fights (default)

One row per fight, with:

  • The card: event name, date, location, weight class, whether it was a title fight
  • Both fighters: name, UFCStats id, nickname, and their result written out (win, loss, draw, no contest)
  • The finish: method (KO/TKO, Submission, Decision - Unanimous, …), the detail (Punch to Head At Distance), the exact round and time, the time format, the referee
  • Judges' scorecards when it went to a decision - each judge with both fighters' points as numbers, not a single string you have to split yourself
  • Totals per fighter: knockdowns, significant strikes landed/attempted and accuracy, total strikes, takedowns landed/attempted and accuracy, submission attempts, reversals, control time (also in seconds)
  • Significant strikes broken down: head / body / leg, and distance / clinch / ground - landed and attempted
  • The same numbers for every round, in a rounds array

Events

One row per UFC event: name, date, location, and whether it has already happened. UFCStats lists 788 events - the oldest is UFC 2, on 11 March 1994 - and the whole list comes back in a single request.

Fighters

One row per fighter: height, reach, stance, date of birth, the win-loss-draw record, and the career rates UFCStats publishes (strikes landed and absorbed per minute, striking accuracy and defence, takedown average, accuracy and defence, submission average) - plus that fighter's full fight list with opponent, event, date, method, round and time.


Example output (one fight, shortened)

{
"recordType": "fight",
"eventName": "UFC 324: Gaethje vs. Pimblett",
"eventDate": "2026-01-24",
"weightClass": "Featherweight",
"fighter1": "Arnold Allen", "fighter1Result": "loss",
"fighter2": "Jean Silva", "fighter2Result": "win",
"winner": "Jean Silva",
"method": "Decision - Unanimous",
"endRound": 3, "endTime": "5:00", "referee": "Chris Tognoni",
"judges": [
{ "judge": "Ron McCarthy", "fighter1Score": 27, "fighter2Score": 30 },
{ "judge": "Chris Lee", "fighter1Score": 28, "fighter2Score": 29 },
{ "judge": "Mike Bell", "fighter1Score": 28, "fighter2Score": 29 }
],
"fighter1SigStrikesLanded": 56, "fighter1HeadLanded": 37, "fighter1BodyLanded": 11, "fighter1LegLanded": 8,
"fighter1DistanceLanded": 53, "fighter1ClinchLanded": 3, "fighter1GroundLanded": 0,
"fighter1ControlTimeSeconds": 54,
"fighter2SigStrikesLanded": 74, "fighter2HeadLanded": 43, "fighter2TakedownsLanded": 4,
"rounds": [
{ "round": 1, "fighter1": { "headLanded": 12, "bodyLanded": 4, "legLanded": 6, "…": "…" }, "fighter2": { "…": "…" } },
{ "round": 2, "…": "…" },
{ "round": 3, "…": "…" }
]
}

Input

FieldKeyWhat it does
What to collectmodefights (default), events or fighters
How many events to readmaxEventsEvents are read newest first; each holds roughly 10-14 fights
Maximum recordsmaxRecordsThe most rows this run may return and charge for
Open each fight pagefetchFightDetailsOn (default) gives the round-by-round breakdown, the referee and the scorecards. Off uses only the totals on the event page - fewer requests
Include upcoming eventsincludeUpcomingOff by default, see below
UFCStats URLsstartUrlsPoint the run at specific event, fight or fighter pages
Fighter last-name letterslettersWhich letters of the alphabet index to walk in fighters mode
Weight classesweightClassesKeep only fights in these weight classes; case-insensitive and partial
Fighter namesfighterNamesKeep only records involving these fighters
Keywords / match / excludekeywords, keywordMatch, excludeKeywordsText filters over event name, bout, weight class, fighter names, location and method
Only return new recordsmonitoringModeFor a schedule that watches for new fights
Forget what was returnedresetMonitoringStateClears that memory once
Maximum requestsmaxRequestsA hard ceiling on how many pages this run fetches
Use a proxy if askeduseProxyOff by default; this Actor clears the site's browser check itself

Things this Actor is careful about

The "completed" list is not all completed. UFCStats puts the next event at the top of its completed-events list. Its result columns are empty because the fights have not happened yet. This Actor marks that event isUpcoming: true and skips it by default, so an empty card never arrives looking like a finished one. Turn on Include upcoming events to get the announced card on purpose.

Empty is not zero. When UFCStats has no number for something - an unfought bout, a fighter whose striking accuracy is blank - the field comes back null, never 0. A 0 in this dataset means the site really printed a zero.

"Could not read" is never reported as "no data". If a page fails, if the site's markup changes shape, or if its browser check is not cleared, you get a row that says exactly which of those happened, with the URL. Those rows are not charged. The same is true for a run where filters matched nothing, or where your maximum cut the result short - each is its own labelled, free row.

The limit does not delete whole events. When Maximum records cuts the result, rows are taken evenly from every event that was read, so you never get three events in full and a fourth silently missing. A free row tells you how many were left out and from where.

Repeat runs remember what was already returned. In monitoring mode, filtering happens before the new-only step, so a fight you filtered out is not held back from a later run.


Frequently asked

Where does the data come from? ufcstats.com, the UFC's own statistics site. No login, no third-party data broker. The site has no robots.txt.

How far back does it go? The event list holds 788 events, from UFC 2 on 11 March 1994 to the card announced for next week (measured 8 September 2026).

Can I watch for new fights? Yes - schedule the Actor with Only return records that are new since the last run turned on. Each run then returns only fights it has not returned before.

Why is eventDate empty on some fight rows? A fight page does not carry its own date; the date comes from the event. If you point the Actor straight at a fight URL, run it in events mode too, or read the fight through its event, to get the date.

Does it handle draws and no contests? Yes. isDraw and isNoContest are set from the fight's own result flags, and winner stays empty rather than naming whoever happens to be listed first.


Pricing

Pay per event: you are charged for each record returned. Rows that explain a problem - an unreadable page, an empty answer, a filter that matched nothing, a result cut by your maximum - are never charged.