UFC Scraper - Fighters, Fights, Events and Rankings
Pricing
from $3.50 / 1,000 fight rows
UFC Scraper - Fighters, Fights, Events and Rankings
[$5.00 / 1K, no start fee] Every UFC fighter, bout, event and division ranking from ufc.com, normalized: records split into W-L-D, heights and reaches in cm as well as inches, and one row per bout instead of fights buried in an array. Optional bout-by-bout career history per fighter.
Pricing
from $3.50 / 1,000 fight rows
Rating
0.0
(0)
Developer
WebData Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
UFC Scraper
Every UFC fighter, bout, event and division ranking from ufc.com - as rows you can open in a spreadsheet, not JSON you have to unpack first.
Official UFC data is spread across four pages that do not agree on shape. The rankings board nests 13 divisions inside two HTML tables. A fighter's height is the bare string 76.00 with no unit printed anywhere on the page, and their record is 28-1-0 (W-L-D). An event page hides thirteen bouts inside one card. Most UFC scrapers hand you that mess back with the tags stripped: a division object containing a rankings array, an event object containing a fights array, and every number as a string. Then you write the flattening code yourself. This Actor does the flattening, so a run of fights is one row per bout with the winner, the method, the round and the end time already in their own columns.
✅ What you get / ❌ what this isn't
| ✅ What you get | ❌ What this isn't |
|---|---|
| One row per bout with both corners, winner, method, round and end time as columns | Not an event object with a fights array you have to explode before you can sort by anything |
| One row per ranked athlete, carrying its division, rank and rank movement | Not 13 nested ranking blocks that become 13 spreadsheet cells |
Records split into wins, losses, draws, noContests as integers, original string kept | Not "28-1-0 (W-L-D)" in one cell and a regex left for you |
| Heights, reaches and weights in cm and kg as well as inches and pounds | Not "76.00" with no unit stated anywhere on the page or in the output |
| 40+ career stat fields per fighter, including strikes by target and by position | Not the four numbers in the profile header |
| Full bout-by-bout fight history per fighter: opponent, date, result, method, round, time | Not a win/loss total with the fights left on the site |
UFC's official rankings and its Meta rankings, told apart by a rankingSet column | Not both boards silently merged into one list with every division duplicated |
| Bonus awards split out - "Fight of the Night", "Performance of the Night" - per bout | Not one banner string with two awards joined by a slash |
| Unranked corners stay unranked | Not an unranked opponent handed their opponent's number because the markup does not tag corners |
🔎 Why use this Actor
- The flattening is the product.
fightsreturns one row per bout carrying its event name, date, venue, card section, weight class, title-fight flag, both corners, the winner, the method, the round and the end time. That is the table a handicapping model or a fantasy scorer actually wants, and no amount of nested JSON is a substitute for it. - Units are stated, not implied. ufc.com prints height, weight, reach and leg reach as bare decimals with no unit anywhere on the page. Every one of them is emitted twice, named for its unit:
heightInchesandheightCm,weightLbandweightKg,reachInchesandreachCm. - Percentages are numbers. Striking accuracy, takedown accuracy, strike defence, takedown defence, strikes by position and strikes by target all arrive as integers you can average, not as
"58%"strings. - Both ranking boards, kept apart. ufc.com publishes the official rankings and a second "Meta rankings" board on the same page in identical markup. Merging them duplicates every division. Each row here carries
rankingSet, so you can take either or compare them. - Corner ranks are attributed correctly. The rank badge on a bout is the one field ufc.com does not tag by corner, and an unranked fighter renders as an empty slot. Ignore the empties and every unranked opponent inherits their opponent's number. This Actor keeps the empties, so a
nullrank means unranked. - Names are recovered, not guessed. A fight-history row abbreviates both fighters to surnames, and the headshot caption is sometimes a sentence ("UFC interim heavyweight champion Ciryl Gane") and sometimes missing. Names are reconciled against the athlete's own URL, so you get "Ciryl Gane" and "Thiago Santos" rather than "Gane" and "Santos".
- Pagination stops on evidence. ufc.com renders its "Load More" button on the last page too. Every list here stops when a page returns no athlete, event or bout it has not already seen - not when the button disappears, because it never does.
- Pay per row delivered. No start fee. Rows a filter removes are never written and never charged, and the run streams into the dataset as it goes, so an abort still leaves you the rows you paid for.
👥 Who it's for
MMA journalists and stats sites, betting and handicapping analysts, fantasy-MMA platforms, and sports researchers who need the official UFC record rather than a scraped aggregator.
- Build a fight-week preview table: the card, both corners, their records and their career stats.
- Feed historical method, round and end-time data into a handicapping or prop model.
- Score a fantasy-MMA league from per-fighter records, finish rates and strike volume.
- Track a division's rankings week over week and see who moved.
- Build a scouting list of active fighters in one division from one country.
- Answer "how does this fighter actually win" from strikes by position, strikes by target and win-by-method splits.
Example tasks
- Scrape the current UFC rankings for every division
- Get a UFC fighter's career stats and record
- Scrape a UFC fighter's full fight history
- Get upcoming UFC events with full fight cards
- Scrape past UFC fight results, methods and rounds
- Track the UFC lightweight division rankings
- Find UFC fighters from Brazil
- Scrape UFC title fights and champions
- Build the active UFC roster for one weight division
⚙️ How to scrape UFC data
- Pick What to scrape:
rankings,fighters,eventsorfights. Rankings is one request and covers all 13 divisions, so it is the cheapest first run. - For fighters, type names into Fighter or event names - one per line - or paste profile links into ufc.com URLs. Leave both empty to sweep the roster alphabetically.
- Narrow it with Weight division, Men's or women's divisions, Fighter status or Country of birth.
- For events, choose Upcoming or past events. Past events carry results; upcoming events carry the announced matchups.
- Leave Maximum results at 100 for a first run. Set it to 0 for everything.
- Click Start. Rows appear in the dataset as each page is parsed, so you can watch and stop early. Export from the Output tab as JSON, CSV, Excel, XML or an API feed.
Get a fighter's whole career
Set What to scrape to fighters, put the name in Fighter or event names, and turn on Include each fighter's fight history. Each row then carries a fightHistory array with every bout: opponent, date, win or loss, method, round and end time. ufc.com pages that list three bouts at a time, so a 25-fight career costs a handful of extra requests - which is why it is off by default.
Watch a division week to week
Save a task with What to scrape set to rankings and Weight division set to yours, then schedule it weekly. Each row carries rankChange, UFC's own movement marker, so a week-over-week diff of the dataset shows exactly who climbed.
📥 Input
{"dataType": "fights","eventType": "past","maxResults": 100}
dataType-rankings,fighters,eventsorfights. Defaults torankings. Singular forms (fighter,event) andathletesare accepted too.searchTerms- fighter or event names, one per line. UFC's own search is a loose match, so a surname can return several athletes; an exact name match is always delivered first. Aliases:queries,keywords.startUrls- ufc.com/athlete/or/event/URLs to scrape directly, skipping search. Anything else is logged and skipped. Aliases:urls,url.division- one of the 12 UFC weight divisions orPound-for-Pound. Matched exactly, soHeavyweightnever returns Light Heavyweights andFlyweightnever returns Women's Flyweights.gender-maleorfemale. Applies to fighters and rankings.fighterStatus-active,not fightingorretired. Reads each fighter's profile page, so it turns detail fetching on.country- country of birth as UFC prints it, for exampleBrazil,United States,Russia. Also reads each profile page.eventType-upcoming,pastorall. Defaultall.titleFightsOnly- keep only championship bouts. Applies tofights, read from the bout's own weight-class label, so it costs nothing extra. Alias:onlyTitleFights.includeDetails- fetch full profiles and fight cards. Defaulttrue. Turn it off for a fast, cheap roster or events sweep.includeFightHistory- add the bout-by-bout career history to each fighter row. Defaultfalse. Advanced: costs extra requests per fighter.maxResults- stop after this many rows. Default 100,0for unlimited. Aliases:maxItems,limit.
📤 Output
dataType: "fights" - one row per bout:
| eventTitle | eventDate | cardSection | weightClass | redCornerName | blueCornerName | winnerName | method | round | time |
|---|---|---|---|---|---|---|---|---|---|
| UFC 300: Pereira vs Hill | 2024-04-14T02:00:00.000Z | Main Card | Light Heavyweight Title Bout | Alex Pereira | Jamahal Hill | Alex Pereira | KO/TKO | 1 | 3:14 |
| UFC 300: Pereira vs Hill | 2024-04-14T02:00:00.000Z | Main Card | Lightweight Bout | Justin Gaethje | Max Holloway | Max Holloway | KO/TKO | 5 | 4:59 |
| UFC 300: Pereira vs Hill | 2024-04-14T02:00:00.000Z | Prelims | Featherweight Bout | Calvin Kattar | Aljamain Sterling | Aljamain Sterling | Decision - Unanimous | 3 | 5:00 |
Each fight row also carries fightId, eventSlug, eventVenue, eventUrl, eventStatus, boardOrder, isTitleFight, both corners' Slug, Url, Rank and Outcome, and awards - the per-bout bonus list, split so "Fight of the Night" and "Performance of the Night" are separate entries.
dataType: "fighters" - one row per fighter:
| name | nickname | division | status | record | wins | losses | birthCountry | heightCm | weightKg | reachCm |
|---|---|---|---|---|---|---|---|---|---|---|
| Jon Jones | Bones | Heavyweight | Active | 28-1-0 | 28 | 1 | United States | 193 | 107.8 | 214.6 |
| Islam Makhachev | Welterweight | Active | 29-1-0 | 29 | 1 | Russia | 177.8 | 77.1 | 178.4 |
Fighter rows additionally carry athleteSlug, gender, isChampion, pfpRank, draws, noContests, age, heightInches, weightLb, reachInches, legReachInches, legReachCm, hometown, birthCity, trainsAt, fightingStyle, octagonDebut (ISO) and octagonDebutRaw, fightWinStreak, winsByKnockout, winsBySubmission, firstRoundFinishes, and the full career stat set: sigStrikesLandedPerMin, sigStrikesAbsorbedPerMin, strikingAccuracyPct, sigStrikesLanded, sigStrikesAttempted, sigStrikeDefensePct, takedownAvgPer15Min, takedownAccuracyPct, takedownsLanded, takedownsAttempted, takedownDefensePct, submissionAvgPer15Min, knockdownAvg, averageFightTime, strikes by position (sigStrikesStanding, sigStrikesClinch, sigStrikesGround, each with a Pct sibling), strikes by target (sigStrikesToHead, sigStrikesToBody, sigStrikesToLegs, each with a Pct sibling), and win-by-method (winsByKoTko, winsByDecision, winsBySub, each with a Pct sibling). With includeFightHistory on, they also carry fightHistory, fightHistoryCount and fightHistoryTruncated.
dataType: "rankings" - one row per ranked athlete, carrying division, gender, rank (0 for a champion), isChampion, isPoundForPound, rankChange, rankingSet (official or meta), athleteName, athleteSlug and athleteUrl.
dataType: "events" - one row per event, carrying eventSlug, title, subtitle, shortName, status, date (ISO, from UFC's own timestamp), venue, venueName, city, country, imageUrl, fightCount, url and the full fights array.
💵 How much does it cost?
You pay per row delivered, with no Actor-start fee, so a run that returns nothing costs nothing. A rankings run returns about 380 rows for the whole board across both boards, or roughly 16 for one division. An event card is 10-15 rows. A single fighter lookup is one row, however many pages it took to build it - including the whole fight history.
Rows removed by a division, status, country or gender filter are never written and never charged: you pay for what you keep, not for what was scanned.
🔁 Run it on the Apify platform
Schedule it (weekly rankings, daily upcoming events), call it from the REST API or the JavaScript and Python clients, or wire the dataset into Make, Zapier, n8n, Google Sheets, Slack or a webhook. Proxy rotation, geo-routing and request pacing are handled internally and are included in the price - there is nothing to configure.
⚠️ Limits and caveats
- UFC does not offer server-side filters for division, status or country. Its roster page exposes only a free-text search. Those filters are applied here, after the data is fetched, which means a division sweep with no search term walks the alphabetical roster (about 3,200 athletes, 11 a page) until it has enough matches. Use a search term or
startUrlswhen you know who you want; it is dramatically cheaper. - A status or country filter has a scan budget. Those two are only decidable from a fighter's profile page, so the run reads one profile per candidate. It will read up to 20 profiles per row you asked for (minimum 250) and then stop with a message in the log rather than sweeping the entire roster for a handful of matches. Pair the filter with a division to stay well inside it:
divisionis settled from the listing card and costs nothing. - Road To UFC and Contender Series cards are published without weight classes or results. ufc.com renders those events with the class and result slots empty, so those rows come back with
weightClass,method,roundandwinnerNameasnull. That is the source, not the parser. - Fight history is capped at 12 pages (36 bouts) per fighter. Anything longer is flagged with
fightHistoryTruncated: truerather than silently cut. - Upcoming bouts have no result.
winnerName,method,roundandtimearenulluntil the fight happens. They are never guessed from odds or predictions. - There is no poster image. Event wordmarks on ufc.com are inline SVG with no image URL behind them, so
imageUrlis the event's hero photograph rather than the fight poster. No competitor has the poster either; some just relabel this same image. - Round-by-round statistics are not on ufc.com. UFC publishes career aggregates on the athlete profile and per-bout results on the event page, but the per-round strike tables live on ufcstats.com, a different site with a different data model.
- "Age" is the age UFC prints today, not a date of birth. UFC does not publish dates of birth on athlete profiles.
fightWinStreakandfirstRoundFinishesare only present when UFC chooses to show them in the profile header, which varies by fighter. They come backnullrather than0when absent, so you can tell "not published" from "none".- This Actor reads ufc.com only. Fighters who never fought in the UFC, and UFC bouts before the current site's records, are not on it.
🧩 Related Actors
- Google Search Results Scraper - find the news and coverage around a fight week that the official card does not carry.
- Reddit Signal Scraper - pull r/MMA sentiment on a card and join it to these bouts by fighter name.
- Bluesky Scraper - track what fighters and analysts post around an event.
- Website Contact Extractor - turn the
trainsAtgym names into contactable gyms. - Lead List Deduplicator - merge repeated roster pulls into one clean fighter list across runs.
- Bulk URL Status Checker - re-check a saved list of athlete URLs before a big enrichment run.
🤖 Use with AI agents via MCP
This Actor is available over Apify's MCP server, so an agent can call it as a tool.
Claude Code:
$claude mcp add apify --transport http https://mcp.apify.com/?actors=webdata_labs/ufc-scraper
Cursor or Claude Desktop, in your MCP config:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com/?actors=webdata_labs/ufc-scraper"}}}
Structured parameters exist precisely for this: an agent can fill {"dataType": "fights", "searchTerms": ["UFC 300"]} without knowing how to build a ufc.com URL.
🔗 Use this Actor in n8n
Add the Apify node, choose Run an Actor and get dataset, pick webdata_labs/ufc-scraper, and paste your input JSON. The node returns the rows directly, so a weekly rankings pull into Airtable or Postgres is three nodes.
❓ FAQ
Am I charged for rows a filter throws away?
No. Filtered rows are never written to the dataset and never charged. You pay only for rows delivered, and there is no Actor-start fee.
Why does searching a surname return several fighters?
Because that is what UFC's own search does - it is a loose match, not an exact one. The exact name match is always sorted first, so maxResults: 1 on "Jon Jones" gives you Jon Jones and not Jon Fitch.
Does it return round-by-round fight statistics?
No. ufc.com publishes career aggregates and per-bout results; per-round strike tables are on ufcstats.com, which is a different site. Everything ufc.com does publish is here.
Can I get every fighter on the roster?
Yes - set dataType to fighters, leave the search empty and set maxResults to 0. It is about 3,200 athletes at 11 a page, so turn includeDetails off unless you need career stats for all of them.
What is the difference between the official and Meta rankings?
UFC publishes two boards on the same page. The official rankings are the panel-voted ones; the Meta rankings are UFC's own composite. Both are returned, told apart by the rankingSet column, so you can take either or diff them.
How do I tell an unranked fighter from a missing value?
redCornerRank and blueCornerRank are null when UFC shows no rank badge for that corner. Champions show as C and ranked contenders as #1 through #15.
Which timezone are the dates in?
UTC. Event dates come from UFC's own unix timestamp, so they are exact. Fight-history and octagon-debut dates are day-precision on the source and are emitted as YYYY-MM-DD.
🛠️ Support
Open an issue on the Actor's Issues tab with the run URL, the input you used and what you expected. Include the run URL - it is what makes a report actionable.
⭐ Rate this Actor
If this saved you an afternoon, please leave a review on the Reviews tab. Review count is the main trust signal a new Actor has, and reviews are what decide which fields and sources get built next. If something is broken or missing, please open an issue first - it is usually fixed within a day, and that is faster than a low rating gets it fixed.
Changelog
0.1 - 2026-08-31
- First release. Four data types (
rankings,fighters,events,fights), the full ufc.com career stat set, optional bout-by-bout fight history, official and Meta rankings told apart, and cm/kg alongside inches/pounds throughout.
Is it legal to scrape UFC data?
This Actor reads only publicly available pages on ufc.com - the same pages any visitor sees, with no login and no paywall. It collects no personal data beyond the professional information UFC itself publishes about its athletes. Scraping public data is generally lawful, but you are responsible for how you use it: follow ufc.com's terms, applicable law and any data-protection rules that apply to you, and do not republish UFC's content in a way that competes with it.