# Ufc Stats Scraper (`normdata/ufc-stats-scraper`) Actor

Get official UFC fighter records, event cards and full round by round fight breakdowns, strikes, takedowns and control time included. No login. Built for bettors backtesting models, fantasy MMA players, analysts and content creators who need accurate fight stats fast.

- **URL**: https://apify.com/normdata/ufc-stats-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 🥊 UFC Stats Scraper

Extract official UFC fight statistics (**fighter profiles, event cards, and full fight-by-fight strike and grappling breakdowns**) as clean, structured records. Career averages, complete
fight history, and per-fight totals (knockdowns, significant strikes, takedowns, control time),
with an optional round-by-round split. No login, no account, no manual copying.

### 🎯 Who uses it?

#### 🎮 Fantasy MMA players

Compare fighter stats to set weekly DraftKings / FanDuel lineups.

#### 🎲 Bettors & model builders

Backtest betting angles and build predictive models from career-long striking and grappling
data, down to the individual round.

#### 📊 Analysts & researchers

Track career trajectories, finishing rates, and stylistic matchups across a fighter's entire
UFC record.

#### ✍️ Content creators

Pull accurate fight records and stats for pre-fight previews, graphics, and recaps.

### ✨ What it does

- **Fighter profiles:** bio (height, weight, reach, stance, date of birth), career averages
  (significant strikes landed/absorbed per minute, strike accuracy & defense, takedown average,
  accuracy & defense, submission average), and full fight history.
- **Events:** every completed or upcoming UFC event: date, location, and the full fight card.
- **Fight breakdowns:** knockdowns, significant strikes (landed/attempted/accuracy), total
  strikes, takedowns, submission attempts, reversals, and control time, for the whole fight,
  or split out **round by round**.
- **Find fighters by name**, paste fighter profile links directly, or browse an entire A–Z
  directory letter.
- **Filter by stance and minimum career wins/losses** so only relevant fighters land in your
  dataset.
- **CRM-ready layout:** keep fight history nested inside each fighter row, or flatten it to one
  row per past fight.
- Heights/weights/reach are normalized to metric (cm / kg) alongside the raw record.

### Why this scraper

- **Find fighters by name.** The other UFC scrapers on Apify only search a single word at a
  time. This one takes a full name like "Israel Adesanya".
- **Round-by-round breakdowns.** Strikes, takedowns, control time and more, split per round,
  not just fight totals.
- **Three entities in one actor:** fighter profiles with full history, event cards, and
  fight-level breakdowns.
- **Filters that narrow the dataset:** stance, minimum career wins or losses, and a whole A-Z
  directory letter at a time.
- **CRM-ready output:** nested fight history, or flattened to one row per past fight.
- **No login, no API key, no proxy.**

### How it compares

| Capability | This actor | Other UFC scrapers on Apify |
|---|:--:|:--:|
| Fighter profiles, events, fight breakdowns | yes | some |
| **Search by full fighter name** | **yes** | **single word only** |
| **Round-by-round strike / takedown / control splits** | **yes** | **rare** |
| Filter by stance, minimum wins / losses | yes | no |
| Nested or flattened fight history | yes | no |
| Metric heights / weights / reach alongside the raw record | yes | no |
| Declared dataset schema + free-plan preview | yes | no |

### 📦 What data you get

| Entity | Useful fields |
| --- | --- |
| Fighter | Name, record (W-L-D), height, weight, reach, stance, date of birth, significant-strike & takedown career averages, and full fight history. |
| Event | Name, date, location, and the fight card (both fighters, weight class, method, round, time, per fight). |
| Fight | Both fighters, winner, weight class, method, round, time, referee, finish details, and full strike/takedown totals, optionally per round. |

Every record includes `scraped_at` (UTC) and `source`. Download your dataset from Apify as CSV,
JSON, Excel, or XML.

### 💡 Use cases

#### 🎮 Build a fantasy lineup from career stats

```json
{
  "mode": "fighters",
  "fighterNames": ["Islam Makhachev", "Ilia Topuria", "Alex Pereira"],
  "includeFightHistory": false
}
```

#### 🎲 Backtest a betting model on full round-by-round data

```json
{
  "mode": "fights",
  "fighterNames": ["Jon Jones"],
  "maxFightsPerFighter": 0,
  "includeRoundByRound": true
}
```

#### 📅 Get every event this year

```json
{
  "mode": "events",
  "eventStatus": "completed",
  "eventStartDate": "2026-01-01"
}
```

#### 🗂️ Spreadsheet-ready fight history

```json
{
  "mode": "fighters",
  "fighterNames": ["Alexander Volkanovski"],
  "includeFightHistory": true,
  "flattenHistory": true
}
```

#### 📖 Browse the fighter directory, filtered

Directory letters group fighters by **last name**, not weight class or division. The official
record doesn't expose a weight-class filter, so narrow the pool with stance and career win/loss
minimums instead:

```json
{
  "mode": "fighters",
  "letters": ["a", "b", "c"],
  "stance": "Southpaw",
  "minWins": 10,
  "includeFightHistory": false,
  "maxItems": 500
}
```

#### 🔗 Refresh a past run from saved fighter links

Every row this Actor returns includes a `fighter_url`. Save those links from an earlier run
and paste them back in later to re-scrape exactly those fighters, skipping the name search:

```json
{
  "mode": "fighters",
  "fighterUrls": ["<a fighter_url from a previous run>"],
  "includeFightHistory": true
}
```

### ⚙️ How the input is organised

The input form is split into four numbered sections:

| Section | What it's for |
| --- | --- |
| **1 · What do you want to scrape?** | Pick one **type of data**: Fighter profiles, Events, or Fight breakdowns. |
| **2 · Who or what to get** | Fill in **only** the field that matches your choice: **fighter names**, **fighter links** (Fighter profiles / Fight breakdowns), a **directory letter** + optional **stance / min wins / min losses** filters (Fighter profiles), or **event status** + date range (Events). |
| **3 · How much to collect** | **Maximum rows** for the whole run, and **fights per fighter** for Fight breakdowns (`0` = their entire UFC record). |
| **4 · What to include** | Full fight history (and whether to flatten it to one row per fight), and a round-by-round breakdown for Fight breakdowns. |

> **Apify Free plan:** every run is limited to a fixed 10-row sample. Upgrade your Apify plan to
> run your own settings.

### 🛡️ Limits & responsible use

This Actor collects only publicly available, official UFC fight statistics. It never signs in
and never accesses anything gated behind an account.

If a fighter, event, or fight page can't be loaded, that row is skipped with a warning in the
run log. The rest of the run continues.

### 🧪 Local development

```powershell
bun install
bun run typecheck
bun test
bun run start
```

Test with a sample `storage/key_value_stores/default/INPUT.json`, e.g.:

```json
{ "mode": "fighters", "fighterNames": ["Jon Jones"], "maxItems": 5 }
```

# Actor input Schema

## `mode` (type: `string`):

**Fighter profiles** — bio, career stats and full fight history for one or more named fighters, or an entire A–Z directory letter.
**Events** — event cards: date, location and every fight on the card.
**Fight breakdowns** — full round-by-round strike and grappling stats (knockdowns, significant strikes, takedowns, control time) for a fighter's past fights.

*On the Apify **Free** plan every run is limited to a fixed 10-row sample; upgrade to run your own settings.*

## `fighterNames` (type: `array`):

One or more fighter names, e.g. `Jon Jones`. Matched against the official fight record.

## `fighterUrls` (type: `array`):

Already have fighter profile links (e.g. the `fighter_url` field from a previous run)? Paste them here to scrape exactly those, skipping the name search. Can be combined with the names above.

## `letters` (type: `array`):

No names or links? Pick one or more A–Z letters to pull every fighter whose last name starts with it. Can be combined with the fields above. Warning: even one letter can be hundreds of fighters — set a maximum rows below.

## `stance` (type: `string`):

Keep only fighters with this stance. Leave empty for every stance.

## `minWins` (type: `integer`):

Keep only fighters with at least this many wins. Leave empty for no minimum.

## `minLosses` (type: `integer`):

Keep only fighters with at least this many losses. Leave empty for no minimum.

## `eventStatus` (type: `string`):

Past (completed) events, upcoming (scheduled) events, or both.

## `eventStartDate` (type: `string`):

Only events on or after this date. Format: `YYYY-MM-DD`.

## `eventEndDate` (type: `string`):

Only events on or before this date. Format: `YYYY-MM-DD`.

## `maxItems` (type: `integer`):

Stop once this many rows are in the dataset. Leave empty to get everything. *(Free plan: always capped at 10.)*

## `maxFightsPerFighter` (type: `integer`):

Most recent first. Use `0` for a fighter's entire UFC record.

## `includeFightHistory` (type: `boolean`):

Include every past fight (opponent, result, method, round, time) on each fighter's row. Turn off for a quick, cheap run with just the bio and career averages.

## `flattenHistory` (type: `boolean`):

When on, each past fight becomes its own row (fighter details repeated) — ready for a spreadsheet. When off, the fight history stays nested inside one row per fighter.

## `includeRoundByRound` (type: `boolean`):

Add the strike and grappling totals for every individual round, not just the fight-wide totals. Slightly slower.

## Actor input object example

```json
{
  "mode": "fights",
  "fighterNames": [
    "Jon Jones",
    "Islam Makhachev"
  ],
  "fighterUrls": [],
  "letters": [
    "a",
    "b"
  ],
  "eventStatus": "completed",
  "maxItems": 10,
  "maxFightsPerFighter": 1,
  "includeFightHistory": true,
  "includeRoundByRound": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per fighter, event, or fight, depending on the selected mode.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "fights",
    "fighterNames": [
        "Jon Jones",
        "Islam Makhachev",
        "Alex Pereira",
        "Ilia Topuria",
        "Khabib Nurmagomedov",
        "Israel Adesanya",
        "Conor McGregor",
        "Amanda Nunes",
        "Alexander Volkanovski",
        "Sean O'Malley"
    ],
    "fighterUrls": [],
    "letters": [],
    "stance": "",
    "eventStatus": "completed",
    "maxItems": 10,
    "maxFightsPerFighter": 1,
    "includeFightHistory": true,
    "flattenHistory": false,
    "includeRoundByRound": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/ufc-stats-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "fights",
    "fighterNames": [
        "Jon Jones",
        "Islam Makhachev",
        "Alex Pereira",
        "Ilia Topuria",
        "Khabib Nurmagomedov",
        "Israel Adesanya",
        "Conor McGregor",
        "Amanda Nunes",
        "Alexander Volkanovski",
        "Sean O'Malley",
    ],
    "fighterUrls": [],
    "letters": [],
    "stance": "",
    "eventStatus": "completed",
    "maxItems": 10,
    "maxFightsPerFighter": 1,
    "includeFightHistory": True,
    "flattenHistory": False,
    "includeRoundByRound": True,
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/ufc-stats-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "fights",
  "fighterNames": [
    "Jon Jones",
    "Islam Makhachev",
    "Alex Pereira",
    "Ilia Topuria",
    "Khabib Nurmagomedov",
    "Israel Adesanya",
    "Conor McGregor",
    "Amanda Nunes",
    "Alexander Volkanovski",
    "Sean O'\''Malley"
  ],
  "fighterUrls": [],
  "letters": [],
  "stance": "",
  "eventStatus": "completed",
  "maxItems": 10,
  "maxFightsPerFighter": 1,
  "includeFightHistory": true,
  "flattenHistory": false,
  "includeRoundByRound": true
}' |
apify call normdata/ufc-stats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,normdata/ufc-stats-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hWBul5HnbUDW6vrrE/builds/GzbcBCAws4n5z7OTp/openapi.json
