# Sherdog MMA Fighters, Fights & Events Scraper (`artsiom_k/sherdog-scraper`) Actor

MMA fighter profiles with full fight histories, event cards and bout results from Sherdog - UFC, PFL, Bellator, ONE and hundreds of other promotions, back to the 1990s - with incremental runs.

- **URL**: https://apify.com/artsiom\_k/sherdog-scraper.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Other, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 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.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## sherdog-scraper

Scrapes MMA data from [Sherdog](https://www.sherdog.com): **fighter profiles with their complete fight
history**, **event fight cards** (upcoming and past) and **bout results** — for the UFC, PFL, Bellator, ONE
and hundreds of smaller promotions, back to the 1990s. No login required.

### Contents

- [Key features](#key-features)
- [Output](#output)
- [Input](#input)
- [Input examples](#input-examples)
- [Incremental mode](#incremental-mode)
- [FAQ](#faq)

### 🔑 Key features

- **Three views of the same data.** `fighters` (one row per fighter), `events` (one row per card) and
  `fights` (one flat row per bout, ready for a spreadsheet or a model).
- **Full fight histories.** Every professional fight with opponent, event, date, method (KO/TKO, submission,
  decision…), round, time and referee — plus amateur and pro-exhibition bouts, kept in separate divisions.
- **Record breakdowns.** Wins and losses split by KO/TKO, submission, decision and other.
- **Upcoming cards.** Future events with the full bout list, weight classes and fighter records, and each
  fighter's next scheduled fight.
- **Scope by promotion.** Pick UFC, PFL, Bellator, ONE, KSW, Oktagon, Rizin, Cage Warriors and more, or paste
  any Sherdog promotion URL. For fighters, that means "everyone who fought (or is booked) on these cards".
- **The whole database, too.** Leave the promotion list empty for every fighter (about 354,000) or event
  (about 77,000) Sherdog lists.
- **Incremental runs.** Schedule `events` or `fights`: after the first run you only receive new events and
  cards whose results changed.
- **`maxItems` defaults to 50** — a fast, cheap preview. Clear it (`null`) for everything in your selection.

### 📋 Output

See [`.actor/dataset_schema.json`](.actor/dataset_schema.json) for every field.

**`fighters`** — one row per fighter:

```json
{
  "source": "sherdog",
  "external_id": "27944",
  "name": "Jon Jones",
  "nickname": "Bones",
  "birth_date": "1987-07-19",
  "height_cm": 193.04,
  "weight_kg": 107.95,
  "weight_class": "Heavyweight",
  "association": "Jackson-Wink MMA",
  "nationality": "United States",
  "wins": 28, "losses": 1, "draws": 0, "no_contests": 1,
  "wins_ko": 11, "wins_submission": 7, "wins_decision": 10,
  "pro_fights": 30,
  "upcoming_fights": [],
  "fights": [
    {
      "division": "pro", "result": "win", "opponent": "Stipe Miocic", "opponent_id": 39537,
      "event": "UFC 309 - Jones vs. Miocic", "event_date": "2024-11-16",
      "method": "TKO", "method_detail": "Spinning Back Kick and Punches", "finish_type": "ko_tko",
      "referee": "Herb Dean", "round": 3, "time": "4:29", "time_seconds": 269
    }
  ]
}
```

**`events`** — one row per card, with `bouts` (match number, weight class, both fighters with ids and records
where shown, winner, method, round, time, referee) and a `status` of `completed`, `upcoming`, `no_results`
or `unknown`.

**`fights`** — one flat row per bout: event, promotion, date, weight class, `fighter_1` / `fighter_2` with
ids and results, `winner`, `method`, `finish_type`, `round`, `time_seconds`, `referee`.

### 🔧 Input

| Field | Type | Default | Description |
|---|---|---|---|
| `entityType` | string | `fighters` | `fighters`, `events` or `fights`. |
| `organizations` | array | `["ufc"]` | Promotions to scrape. **Empty = the entire database.** |
| `startUrls` | array | — | Specific fighter, event or promotion pages. Replaces the promotion selection. |
| `dateFrom` / `dateTo` | string | — | Only events in this window (`YYYY-MM-DD`). Use a future window for upcoming cards. |
| `maxItems` | integer | `50` | Stop after this many rows. `null` = everything selected. |
| `mode` | string | `auto` | `auto` / `full` / `incremental` — `events` and `fights` only. |
| `concurrency` | integer | `8` | Parallel page requests (max 25). |
| `impersonate` | string | `firefox` | Browser TLS fingerprint. Change only if requests are blocked. |
| `proxyConfiguration` | object | no proxy | Apify Proxy settings. Not needed in testing. |

### 📥 Input examples

**Default preview (50 UFC fighters):**

```json
{}
```

**Every UFC fight ever, one row per bout:**

```json
{ "entityType": "fights", "organizations": ["ufc"], "maxItems": null }
```

**Upcoming UFC and PFL cards:**

```json
{ "entityType": "events", "organizations": ["ufc", "pfl"], "dateFrom": "2026-09-21", "maxItems": null }
```

**Daily feed of new and changed events (schedule this):**

```json
{ "entityType": "fights", "organizations": ["ufc", "pfl", "bellator", "one"], "maxItems": null }
```

**Two specific fighters:**

```json
{ "entityType": "fighters", "startUrls": ["https://www.sherdog.com/fighter/Jon-Jones-27944", "https://www.sherdog.com/fighter/Stipe-Miocic-39537"] }
```

### 🔁 Incremental mode

`events` and `fights` only, and only for a run with `maxItems` cleared (`null`) — a capped run is a preview
and always returns rows. In `auto` mode the first uncapped run returns everything in scope. Later runs return
only events that are **new or whose card or results changed** in the last 90 days, plus upcoming ones
(`change_type` is `new` or `changed`); older events are history and are not repeated. A run limited by
`maxItems`, your spending limit, `startUrls`, a date window or an error does not update the memory.
`fighters` is always a fresh pull.

### ❓ FAQ

**How complete is fighter data?** Sherdog lists every fighter, but many are obscure: in a sample of 5,000
fighters, about 63% had a nationality, 54% a weight class and 22% a birth date. Fields Sherdog doesn't have
are `null`, never guessed.

**What are the divisions?** `pro`, `amateur` and `pro_exhibition`, matching Sherdog's sections. The win/loss
record fields are the professional record.

**Why does an old event have `no_results`?** Some 1990s events exist on Sherdog with an empty card. They are
returned with that status rather than being labelled upcoming.

**Do you cover boxing or Muay Thai?** Sherdog is an MMA site; a few boxing events exist (the "Boxing"
promotion), and promotions you paste into `startUrls` are scraped as listed.

# Actor input Schema

## `entityType` (type: `string`):

"fighters": one row per fighter with bio, record breakdown (KO/submission/decision), upcoming fights and the full fight history (pro, amateur and exhibition). "events": one row per event with its whole card. "fights": one flat row per bout (opponents, winner, method, round, time, referee).

## `organizations` (type: `array`):

Limit to these promotions. For events and fights that means their events; for fighters, the fighters on those cards. Leave EMPTY for the entire Sherdog database (about 354,000 fighters and 77,000 events - a very large run). For a promotion not listed, paste its Sherdog /organizations/... URL into Start URLs.

## `startUrls` (type: `array`):

Optional specific Sherdog URLs: fighter pages (https://www.sherdog.com/fighter/Jon-Jones-27944), event pages (.../events/UFC-309-Jones-vs-Miocic-103896) or promotion pages (.../organizations/Ultimate-Fighting-Championship-UFC-2). When set, they replace the promotion selection. A run with Start URLs never updates the incremental memory.

## `dateFrom` (type: `string`):

Only events on or after this date (events and fights; for fighters, those on matching cards). Fast with a promotion selected; with none it filters after fetching every event.

## `dateTo` (type: `string`):

Only events on or before this date. Use a future date range to get upcoming cards.

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

Stop after pushing this many rows. Defaults to 50 - a fast, cheap preview, and what keeps an unconfigured run within Apify's automated 5-minute QA check. Set to null for everything in your selection.

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

Applies to "events" and "fights" only. "auto": the first run returns everything in scope; later runs, with maxItems cleared, return only new events and events whose card or results changed in the last 90 days (or upcoming) - older events are history and are not repeated. A capped run (the default preview) always returns rows. "fighters" is always a fresh pull.

## `concurrency` (type: `integer`):

Parallel page requests (max 25).

## `impersonate` (type: `string`):

curl\_cffi browser TLS-impersonation target. Defaults to "firefox" internally; change only if requests are blocked.

## `proxyConfiguration` (type: `object`):

Apify Proxy settings. Not needed: Sherdog answered every request from Apify's infrastructure in testing without a proxy.

## Actor input object example

```json
{
  "entityType": "fighters",
  "organizations": [
    "ufc"
  ],
  "maxItems": 50,
  "mode": "auto",
  "concurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("artsiom_k/sherdog-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("artsiom_k/sherdog-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 '{}' |
apify call artsiom_k/sherdog-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,artsiom_k/sherdog-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/Ah8aa5NIA07rFzFtG/builds/Yhb7Og2HbD7Tgktff/openapi.json
