# MTG Metagame Scraper (`martoeporedia/mtg-metagame-scraper`) Actor

Get MTG metagame JSON: meta share per archetype, recent events with standings, main+side decklists. MTGTop8 and MTGGoldfish sources

- **URL**: https://apify.com/martoeporedia/mtg-metagame-scraper.md
- **Developed by:** [Marco Martorana](https://apify.com/martoeporedia) (community)
- **Categories:** Developer tools, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.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/platform/actors/running/actors-in-store#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

## MTG Metagame Scraper

Apify Actor that scrapes **Magic: The Gathering competitive metagame data**:
archetype meta shares, recent tournaments with an importance rating, standings
with player names, and full decklists of the top finishes.

Supported formats: `standard`, `modern`, `legacy`, `vintage`, `pioneer`,
`commander`, `pauper`.

### Data sources

| | MTGTop8 (default) | MTGGoldfish |
|---|---|---|
| Archetype meta shares | ✅ | ✅ |
| Archetype key cards | ❌ | ✅ |
| Real tournaments with standings | ✅ | ❌ |
| Tournament importance (1–5 stars) | ✅ | ❌ |
| Full decklists (main + sideboard) | ✅ | ❌ |

Pick the source with the `source` input option (`mtgtop8`, `mtggoldfish`, or
`both`).

### Input

```json
{
    "formats": ["modern", "standard"],
    "source": "mtgtop8",
    "maxEvents": 8,
    "minPlayers": 100,
    "decklistsPerEvent": 2,
    "includeDecklists": true,
    "requestDelaySecs": "1.0",
    "incremental": false,
    "stateRetentionDays": 30
}
```

- **formats** — which formats to scrape.
- **source** — data source: `mtgtop8` (tournaments + decklists), `mtggoldfish`
  (meta shares + key cards), or `both`.
- **maxEvents** *(MTGTop8 only)* — tournaments per format, picked by importance
  (star rating) then recency.
- **minPlayers** *(MTGTop8 only)* — skip tournaments below this size. Player
  counts are only visible on event pages, so up to 3× `maxEvents` events are
  probed. Tip: use `50` for smaller formats like Vintage or Legacy.
- **decklistsPerEvent** *(MTGTop8 only)* — full decklists (top finishes)
  downloaded per tournament.
- **requestDelaySecs** — polite delay between requests (keep ≥ 1.0).
- **incremental** *(MTGTop8 only)* — remember tournament ids across runs (in
  the named key-value store `mtg-metagame-seen-events`) and only emit NEW
  events. MTGTop8's format page only shows the last few days, so a scheduled
  incremental run accumulates tournament history over time with no duplicates
  — and already-seen tournaments cost no extra requests (fewer paid results,
  faster runs). The `metagame` item (meta shares) is always emitted: it is a
  point-in-time snapshot, not an accumulating stream.
- **stateRetentionDays** — days before a seen tournament id is forgotten
  (keeps the incremental state from growing forever). Default 30.

### Output

Dataset items come in two shapes, discriminated by `type`.

**`metagame`** — one per format+source:

```json
{
    "type": "metagame",
    "format": "modern",
    "source": "mtgtop8",
    "fetched_at": "2026-07-15T10:00:00+00:00",
    "total_archetypes": 49,
    "archetypes": [
        {"name": "Boros Aggro", "meta_share": 0.11, "category": "Aggro"}
    ]
}
```

MTGGoldfish archetypes have `key_cards` instead of `category`.

**`event`** — one per qualifying tournament (MTGTop8 only):

```json
{
    "type": "event",
    "format": "modern",
    "source": "mtgtop8",
    "id": "88185",
    "name": "MTGO Showcase Challenge",
    "stars": 3,
    "importance": "major",
    "date": "12/07/26",
    "online": true,
    "players": 448,
    "decks": [
        {
            "deck_id": "869090",
            "rank": "1",
            "archetype": "Ruby Storm",
            "player": "Fatone",
            "decklist": {
                "mainboard": [{"qty": 4, "card_name": "Ruby Medallion"}],
                "sideboard": [{"qty": 4, "card_name": "Orim's Chant"}]
            }
        }
    ]
}
```

Only the first `decklistsPerEvent` decks carry a `decklist`.

`rank` is a **string, possibly composite** (`"1"`, `"3-4"`, `"5-8"`): shared
placements are how MTGTop8 reports brackets below the finals. Don't parse it
as an integer — sort by its first number if you need an ordering.

Note: no source exposes reliable per-archetype **win rates** for free; that is
why the output deliberately has no win-rate field.

### Notes on importance (stars)

MTGTop8 rates events 1–5 stars. The scraper prioritizes tournaments by stars,
then recency, and maps them to labels: `minor` (≤1★), `competitive` (2★),
`major` (3★), `premier` (4–5★). Use this to weight results: a Top 8 at a
premier event says more about the metagame than a win at a small local.

### Use as a library

The parsers live in the installable `mtg_metagame` package — this repo is the
single source of truth for them (the DeckAssistant backend consumes it as a
pip dependency):

```bash
pip install "mtg-metagame @ git+ssh://git@github.com/MartoEporedia/mtg-metagame-actor.git"
```

```python
from mtg_metagame import MTGTop8Client

client = MTGTop8Client()
data = await client.fetch_metagame_full("modern", max_events=8, min_players=100)
```

Override `PoliteClient.fetch` to plug in your own caching or transport.

### Running locally

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
apify run   # or: python -m src (reads storage/key_value_stores/default/INPUT.json)
```

### Fair use

The scraper enforces a ≥1s delay between requests and fetches a bounded number
of pages per run (roughly `formats × (1 + 3×maxEvents + maxEvents×decklistsPerEvent)`
worst case). Please keep the delay at 1 second or higher. MTGGoldfish sits
behind Cloudflare: if requests get blocked on the platform, enable Apify Proxy.

# Actor input Schema

## `formats` (type: `array`):

MTG formats to scrape. Supported: standard, modern, legacy, vintage, pioneer, commander, pauper.

## `source` (type: `string`):

MTGTop8: meta shares + real tournaments with importance rating and full decklists. MTGGoldfish: meta shares + key cards only (no tournaments). 'both' fetches from the two sources.

## `maxEvents` (type: `integer`):

(MTGTop8 only) How many qualifying tournaments to include per format, picked by importance (star rating) and recency.

## `minPlayers` (type: `integer`):

(MTGTop8 only) Tournaments with fewer players are skipped. Set to 0 to include everything. Tip: use 50 for smaller formats like Vintage or Legacy.

## `decklistsPerEvent` (type: `integer`):

(MTGTop8 only) How many full decklists (top finishes) to download per tournament. Each decklist costs one extra request.

## `includeDecklists` (type: `boolean`):

(MTGTop8 only) Disable to skip decklist downloads entirely (faster, fewer requests).

## `requestDelaySecs` (type: `string`):

Polite rate limiting towards mtgtop8.com. Keep at 1.0 or higher.

## `incremental` (type: `boolean`):

Remember tournament ids across runs (named key-value store) and only emit NEW events. Ideal for scheduled runs: results accumulate over time without duplicates, and already-seen tournaments cost no extra requests. Meta shares are always emitted.

## `stateRetentionDays` (type: `integer`):

How long (days) a tournament id stays in the incremental state before being forgotten. Only used with incremental mode.

## Actor input object example

```json
{
  "formats": [
    "modern",
    "standard"
  ],
  "source": "mtgtop8",
  "maxEvents": 8,
  "minPlayers": 100,
  "decklistsPerEvent": 2,
  "includeDecklists": true,
  "requestDelaySecs": "1.0",
  "incremental": false,
  "stateRetentionDays": 30
}
```

# Actor output Schema

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

All scraped items (metagame snapshots and tournaments with decklists) in the default dataset.

# 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 = {
    "formats": [
        "modern",
        "standard"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("martoeporedia/mtg-metagame-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 = { "formats": [
        "modern",
        "standard",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("martoeporedia/mtg-metagame-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "formats": [
    "modern",
    "standard"
  ]
}' |
apify call martoeporedia/mtg-metagame-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=martoeporedia/mtg-metagame-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/iUFFwsiOY8NwGp6eb/builds/38shm6O5B3ieCqR0J/openapi.json
