UFC & MMA Stats Scraper — Fighters, Fights, Events & Rankings avatar

UFC & MMA Stats Scraper — Fighters, Fights, Events & Rankings

Pricing

from $50.00 / 1,000 results

Go to Apify Store
UFC & MMA Stats Scraper — Fighters, Fights, Events & Rankings

UFC & MMA Stats Scraper — Fighters, Fights, Events & Rankings

Build MMA betting models, fantasy tools and fight databases on clean data: bout results with method and round, 42 measured stats per fighter per fight, reach, stance and gym per athlete. 19 promotions — UFC, PFL, ONE, Bellator, plus defunct PRIDE and Strikeforce. UFC back to 1994.

Pricing

from $50.00 / 1,000 results

Rating

0.0

(0)

Developer

Muhamed Didovic

Muhamed Didovic

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Pull complete MMA data from ESPN's public API: every bout with its winner, method, round and finish time, the full 42-stat striking and grappling breakdown for each fighter in each fight, fighter profiles with reach, stance and gym, and every event card with venue. Covers 19 promotions — UFC, PFL, ONE, Bellator, Cage Warriors, KSW, RIZIN and more, including defunct PRIDE, Strikeforce and WEC. UFC history runs back to 1994.

How it works

Why Use This Scraper

Most MMA scrapers give you the UFC and stop there. This one covers 19 promotions and reaches back to 1994, so a training set or a betting model is not capped at one organisation's calendar.

It also returns the real statistical line, not just results. Every bout carries 42 measured values per fighter — significant strikes split by head, body and leg across distance, clinch and ground positions; takedowns attempted, landed and their accuracy; guard passes and positional advances; reversals, submissions, knockdowns and time in control. That is the depth serious models need, and it comes from an API with no key, no login and no scraping challenge to defeat.

Overview

SourceESPN public MMA API
Promotions19 (see Supported Inputs)
HistoryUFC from 1994; other promotions vary
ModesFights, Fight stats, Fighters, Fighter career, Rankings, Events
Auth neededNone
OutputJSON, CSV, Excel, XML

Supported Inputs

Promotions accepted in the promotions field:

SlugPromotionSlugPromotion
ufcUltimate Fighting ChampionshippancrasePancrase
pflProfessional Fighters Leaguem1M-1 Global
bellatorBellatortfcTitan FC
ofcONE ChampionshipstrikeforceStrikeforce
lfaLegacy Fighting AlliancewecWorld Extreme Cagefighting
cage-warriorsCage WarriorspridePRIDE Fighting Championships
kswKonfrontacja Sztuk WalkixfcXtreme Fighting Championships
rizinRizin Fight Federationk1K-1
ifcInvicta FCdreamDream
iflInternational Fight League

You can also target a run by year, by an explicit YYYYMMDD date range, by specific ESPN event IDs, or by specific fighter IDs.

Use Cases

Betting and prediction models. Per-fighter striking accuracy, takedown defence and control time across a fighter's whole history are the standard feature set for MMA modelling. Pull several seasons in one run.

Fantasy MMA. Finish method and round drive most scoring systems. Fights mode gives both for every bout on a card.

Sports media and stat pages. Event cards with venue, plus fighter bios with reach, stance and gym, populate a fight preview without manual entry.

Historical research. PRIDE, Strikeforce and WEC data lets you compare eras rather than only the current UFC roster.

Fighter scouting. Filter the roster by weight class, stance, reach or gym association.

How It Works

The actor talks to ESPN's core sports API. It lists events for each promotion and year you request, then walks each event down to its bouts, and each bout down to its two competitors, their athlete profiles and their statistical lines. Requests are spaced apart and run at low concurrency by default, because ESPN rate-limits bursts and will refuse traffic for several minutes if pushed too hard. Rows are pushed as they are produced, so a run that hits its result cap still returns everything gathered up to that point.

Input Configuration

FieldTypeDefaultNotes
modeselectfightsfights, fightStats, fighters, fighterCareer, rankings, events
promotionsarray["ufc"]Any of the 19 slugs above
yearsarraycurrent yearSeveral years per run
fromDate / toDatestringYYYYMMDD; overrides years
eventIdsarrayRestrict to specific ESPN event IDs
fighterIdsarrayRestrict Fighters mode to specific athletes
searchQuerystringFind a fighter by name or nickname; resolves in seconds
stanceselectOrthodox, Southpaw, Switch, Open Stance, Sideways
minWins / minLossesintegerFilter by career record
proxyConfigurationproxyoffRotating IPs for long runs; ESPN throttles per address
maxItemsinteger1000Caps run size and cost
concurrencyinteger4Raise carefully — ESPN rate-limits
throttleMsinteger120Minimum gap between requests

Example — every 2024 and 2025 UFC bout:

{
"mode": "fights",
"promotions": ["ufc"],
"years": [2024, 2025],
"maxItems": 2000
}

Example — full striking breakdown for one event:

{
"mode": "fightStats",
"promotions": ["ufc"],
"eventIds": ["600039893"],
"years": [2024]
}

Output Overview

Each mode produces one row per entity: one per bout in fights, one per fighter per bout in fightStats (so a bout yields two rows), one per fighter in fighters and fighterCareer, one per ranked fighter in rankings, one per card in events. Every row is flat and one level deep, so it reads the same as JSON or as spreadsheet columns.

Output Samples

Fights

{
"recordType": "fight",
"promotion": "ufc",
"promotionName": "Ultimate Fighting Championship",
"fightId": "401623977",
"eventId": "600039893",
"eventName": "UFC Fight Night: Ankalaev vs. Walker 2",
"date": "2024-01-13T21:00Z",
"weightClass": "Flyweight",
"scheduledRounds": 3,
"roundLengthSeconds": 300,
"fighter1Id": "4916248",
"fighter1Name": "Felipe Bunes",
"fighter2Id": "5120301",
"fighter2Name": "Joshua Van",
"winnerId": "5120301",
"winnerName": "Joshua Van",
"loserId": "4916248",
"loserName": "Felipe Bunes",
"isDraw": false,
"isNoContest": false,
"method": "KO/TKO",
"methodDetail": "Punches",
"methodTarget": "Head",
"endRound": 2,
"endClock": "4:31",
"statusType": "STATUS_FINAL",
"url": "https://www.espn.com/mma/fightcenter/_/id/600039893/league/ufc"
}

Fight stats (trimmed — 55 fields per row)

{
"recordType": "fightStats",
"fightId": "401623977",
"eventName": "UFC Fight Night: Ankalaev vs. Walker 2",
"weightClass": "Flyweight",
"fighterId": "4916248",
"fighterName": "Felipe Bunes",
"opponentName": "Joshua Van",
"won": false,
"knockDowns": 0,
"totalStrikesAttempted": 101,
"totalStrikesLanded": 57,
"sigStrikesAttempted": 91,
"sigStrikesLanded": 50,
"sigDistanceHeadStrikesLanded": 28,
"takedownsLanded": 0,
"takedownAccuracy": 0,
"submissions": 0,
"timeInControl": 0
}

Fighters

{
"recordType": "fighter",
"fighterId": "2354359",
"fullName": "Jason Reinhardt",
"nickname": null,
"weightClass": "Bantamweight",
"heightInches": 66,
"displayHeight": "5' 6\"",
"weightPounds": 145,
"reachInches": null,
"stance": "Orthodox",
"association": null,
"gender": "MALE",
"active": false,
"record": "20-3-0",
"url": "https://www.espn.com/mma/fighter/_/id/2354359/jason-reinhardt"
}

Events

{
"recordType": "event",
"eventId": "600039893",
"name": "UFC Fight Night: Ankalaev vs. Walker 2",
"date": "2024-01-13T21:00Z",
"season": 2024,
"venueName": "Meta APEX",
"venueCity": "Las Vegas",
"venueState": "NV",
"venueCountry": "USA",
"boutCount": 11
}

Fighter career (computed from that fighter's own bouts)

{
"recordType": "fighterCareer",
"fighterId": "5120301",
"fullName": "Joshua Van",
"nickname": "The Fearless",
"weightClass": "Flyweight",
"stance": "Orthodox",
"reachInches": 65,
"association": "4oz Fight Club",
"record": "17-2-0",
"fightsFound": 20,
"fightsWithStats": 12,
"totalFightMinutes": 145.83,
"sigStrikesLanded": 1230,
"sigStrikesAttempted": 2144,
"sigStrikesAbsorbed": 849,
"sigStrikesLandedPerMin": 8.43,
"sigStrikesAbsorbedPerMin": 5.82,
"strikingAccuracy": 0.5737,
"strikingDefense": 0.5826,
"takedownsPer15Min": 0.82,
"takedownAccuracy": 0.6154,
"takedownDefense": 0.7568,
"submissionsPer15Min": 0.21,
"controlSeconds": 640
}

Rankings

{
"recordType": "ranking",
"rankingName": "Men's Pound for Pound Rankings",
"rankingType": "pound-for-pound",
"gender": "MALE",
"isChampionGroup": false,
"rank": 1,
"trend": "-",
"titleDefenses": 2,
"hasAccolade": true,
"fighterName": "Kamaru Usman",
"weightClass": "Welterweight"
}

Key Output Fields

FieldDescription
method / methodDetail / methodTargetHow the fight ended — "KO/TKO", "Submission", "Decision - Unanimous"; detail and target are populated for finishes only
endRound / endClockRound and clock at the finish; a decision reads as the final round at full time
winnerId / loserIdResult, by fighter ID rather than by corner
isDraw / isNoContestKept separate on purpose — a no contest is struck from official records, a draw is not
weightClassContracted weight class for the bout
sigStrikes*Significant strikes, split by target (head/body/leg) and position (distance/clinch/ground)
takedownsLanded / takedownAccuracyGrappling volume and efficiency
timeInControlControl time, in seconds
reachInches / stance / associationFighter reach, stance and gym; null when ESPN has no value
recordCareer record summary, e.g. "20-3-0"
sigStrikesLandedPerMin / AbsorbedPerMinCareer striking volume, per minute of cage time
strikingAccuracy / strikingDefenseLanded ÷ attempted, and the inverse for strikes faced
takedownAccuracy / takedownDefenseGrappling efficiency both ways
fightsFound / fightsWithStatsHow many bouts were seen versus how many had a stat line — every rate uses only the latter
rank / trend / titleDefensesRanking position, movement, and title defences for champions

FAQ

Do I need an API key or ESPN account? No. The source API is public.

Why are methodDetail and methodTarget empty on some rows? They describe the finishing blow. A fight that goes to the judges has no finishing strike, so both are null on decisions. That is correct, not missing data.

Why is reachInches sometimes null? ESPN stores unknown measurements as 0. Reporting a 0 would corrupt any average or filter, so unknowns are returned as null instead.

What is the difference between isDraw and isNoContest? A draw is an official result both fighters keep on their record. A no contest (an illegal blow, or a result overturned afterwards) is struck from the record entirely. Treating them as one value skews win-rate features, so they are separate booleans.

How far back does history go? UFC to 1994. Other promotions vary — PRIDE and Strikeforce cover their active years, PFL and LFA are recent. Ask for a year a promotion did not run and you get an empty result rather than an error.

Why is the default concurrency only 4? ESPN refuses traffic after a burst and stays cold for minutes. The conservative default finishes large runs faster than an aggressive one that gets throttled.

Can I get a single event? Yes — pass its ESPN ID in eventIds along with the year it took place.

Are rankings included? Yes — rankings mode returns 24 groups: every division's rankings and champions, plus men's and women's pound-for-pound, with rank, movement and title defences.

Where do the career rate metrics come from? ESPN publishes no career aggregate for MMA, so fighterCareer sums the fighter's own per-bout stat lines and derives the rates from those totals. Both the totals and the rates ship in the row, so any number can be recomputed or re-weighted. fightsWithStats tells you how many bouts actually carried a stat line — older and regional fights often do not, and those are excluded from every rate rather than counted as zeros.

Why is fighter search fast but an unfiltered fighter run slow? ESPN's roster index returns bare references with no names, so an unfiltered walk fetches every profile. A searchQuery goes through ESPN's search service instead and resolves to ids in one call.

Support

Issues and feature requests go to the actor's Issues tab on Apify Console.

Additional Services

Need a different site scraped, or this data pushed into your own pipeline? Get in touch through the Apify contact form on the actor page.

Explore More Scrapers

🤖 For AI Agents & LLM Apps

This actor is a clean data source for agent pipelines. Every row is flat, typed and one level deep, so it drops straight into a vector store, a dataframe or a tool-call result without reshaping.

Call it from an agent with the Apify MCP server, or directly:

{
"mode": "fights",
"promotions": ["ufc"],
"years": [2025],
"maxItems": 500
}

Field names are stable and self-describing (winnerName, method, endRound, sigStrikesLanded), which keeps prompt overhead low — an LLM can read a row without a schema doc. recordType on every row lets an agent route mixed datasets without inspecting keys.

⚠️ Disclaimer

This actor collects publicly available data from ESPN's public API. It does not access private data, bypass authentication, or defeat access controls. You are responsible for using the collected data in line with ESPN's terms, applicable law, and any restrictions on redistribution. This actor is not affiliated with, endorsed by, or connected to ESPN, the UFC, or any promotion named above. All trademarks belong to their respective owners.

SEO Keywords

UFC scraper, MMA scraper, UFC stats API, MMA stats API, UFC fighter data, UFC fight results scraper, MMA fight statistics, UFC event scraper, fighter profile scraper, significant strikes data, takedown statistics, MMA betting data, fantasy MMA data, PFL scraper, Bellator scraper, ONE Championship data, PRIDE FC historical data, Strikeforce results, Cage Warriors data, KSW scraper, RIZIN data, Invicta FC scraper, MMA historical database, combat sports data, UFC API no key, ESPN MMA API, MMA machine learning dataset, fight card scraper