UFC Scraper - Fighters, Fights, Events and Rankings avatar

UFC Scraper - Fighters, Fights, Events and Rankings

Pricing

from $3.50 / 1,000 fight rows

Go to Apify Store
UFC Scraper - Fighters, Fights, Events and Rankings

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

WebData Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

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 columnsNot 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 movementNot 13 nested ranking blocks that become 13 spreadsheet cells
Records split into wins, losses, draws, noContests as integers, original string keptNot "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 poundsNot "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 positionNot the four numbers in the profile header
Full bout-by-bout fight history per fighter: opponent, date, result, method, round, timeNot a win/loss total with the fights left on the site
UFC's official rankings and its Meta rankings, told apart by a rankingSet columnNot both boards silently merged into one list with every division duplicated
Bonus awards split out - "Fight of the Night", "Performance of the Night" - per boutNot one banner string with two awards joined by a slash
Unranked corners stay unrankedNot an unranked opponent handed their opponent's number because the markup does not tag corners

🔎 Why use this Actor

  • The flattening is the product. fights returns 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: heightInches and heightCm, weightLb and weightKg, reachInches and reachCm.
  • 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 null rank 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

⚙️ How to scrape UFC data

  1. Pick What to scrape: rankings, fighters, events or fights. Rankings is one request and covers all 13 divisions, so it is the cheapest first run.
  2. 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.
  3. Narrow it with Weight division, Men's or women's divisions, Fighter status or Country of birth.
  4. For events, choose Upcoming or past events. Past events carry results; upcoming events carry the announced matchups.
  5. Leave Maximum results at 100 for a first run. Set it to 0 for everything.
  6. 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, events or fights. Defaults to rankings. Singular forms (fighter, event) and athletes are 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 or Pound-for-Pound. Matched exactly, so Heavyweight never returns Light Heavyweights and Flyweight never returns Women's Flyweights.
  • gender - male or female. Applies to fighters and rankings.
  • fighterStatus - active, not fighting or retired. Reads each fighter's profile page, so it turns detail fetching on.
  • country - country of birth as UFC prints it, for example Brazil, United States, Russia. Also reads each profile page.
  • eventType - upcoming, past or all. Default all.
  • titleFightsOnly - keep only championship bouts. Applies to fights, read from the bout's own weight-class label, so it costs nothing extra. Alias: onlyTitleFights.
  • includeDetails - fetch full profiles and fight cards. Default true. Turn it off for a fast, cheap roster or events sweep.
  • includeFightHistory - add the bout-by-bout career history to each fighter row. Default false. Advanced: costs extra requests per fighter.
  • maxResults - stop after this many rows. Default 100, 0 for unlimited. Aliases: maxItems, limit.

📤 Output

dataType: "fights" - one row per bout:

eventTitleeventDatecardSectionweightClassredCornerNameblueCornerNamewinnerNamemethodroundtime
UFC 300: Pereira vs Hill2024-04-14T02:00:00.000ZMain CardLight Heavyweight Title BoutAlex PereiraJamahal HillAlex PereiraKO/TKO13:14
UFC 300: Pereira vs Hill2024-04-14T02:00:00.000ZMain CardLightweight BoutJustin GaethjeMax HollowayMax HollowayKO/TKO54:59
UFC 300: Pereira vs Hill2024-04-14T02:00:00.000ZPrelimsFeatherweight BoutCalvin KattarAljamain SterlingAljamain SterlingDecision - Unanimous35: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:

namenicknamedivisionstatusrecordwinslossesbirthCountryheightCmweightKgreachCm
Jon JonesBonesHeavyweightActive28-1-0281United States193107.8214.6
Islam MakhachevWelterweightActive29-1-0291Russia177.877.1178.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 startUrls when 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: division is 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, round and winnerName as null. That is the source, not the parser.
  • Fight history is capped at 12 pages (36 bouts) per fighter. Anything longer is flagged with fightHistoryTruncated: true rather than silently cut.
  • Upcoming bouts have no result. winnerName, method, round and time are null until 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 imageUrl is 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.
  • fightWinStreak and firstRoundFinishes are only present when UFC chooses to show them in the profile header, which varies by fighter. They come back null rather than 0 when 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.

🤖 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.

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.