Skip to content

ericosg/cardmarket-tools

Repository files navigation

Cardmarket CLI

A command-line tool for searching Magic: The Gathering cards on Cardmarket (EU) with advanced filtering and shipping cost calculations.

Features

  • 🔍 Search for MTG cards on Cardmarket
  • 📦 Export Data Mode - Uses daily Cardmarket export files by default (no API calls needed!)
  • 💰 Compare prices including shipping costs to your location
  • 🎁 Per-Booster Pricing - Automatic price-per-booster calculations for sealed products (boxes, bundles, prerelease packs)
  • 📈 Expected Value (EV) Calculator - Calculate expected value of booster boxes using real card prices from Scryfall
  • 🌍 Filter by seller country and shipping availability
  • ⚡ Dual data sources: Fast export data for basic searches, live API for advanced features
  • 📊 Display results in table or JSON format
  • 🎯 Advanced filtering (condition, foil, language, set, price range, product type)
  • 🔄 Automatic daily data updates with manual refresh option
  • 📦 Group offers by seller to optimize shipping
  • 🎨 Customizable display (hide foil column, show/hide per-booster pricing)
  • 🔍 Product type filtering (singles only, sealed products only, or both)

Prerequisites

  • Node.js >= 18.0.0
  • pnpm package manager
  • Cardmarket API credentials (optional - only required for live API mode with --live flag or advanced features)

Installation

  1. Clone the repository:
git clone <repository-url>
cd cardmarket-tools
  1. Install dependencies:
pnpm install
  1. Create a configuration file:
cp config.example.json config.json
  1. Edit config.json with your preferences. API credentials are optional - only needed for live API mode.

Getting Cardmarket API Credentials (Optional)

API credentials are only required if you want to use live API features (real-time seller offers, condition filtering, shipping calculations).

For basic price lookups using export data (default mode), you can skip this section entirely and remove the credentials section from your config.json.

To get API credentials for live mode:

  1. Log in to your Cardmarket account
  2. Visit: https://www.cardmarket.com/en/Magic/Account/API
  3. Create a new "Dedicated App" or "Widget" application
  4. You'll receive:
    • App Token (Consumer Key)
    • App Secret (Consumer Secret)
    • Access Token
    • Access Token Secret

For more details, see:

Configuration

Create a config.json file in the root directory:

{
  "credentials": {
    "appToken": "your-app-token",
    "appSecret": "your-app-secret",
    "accessToken": "your-access-token",
    "accessTokenSecret": "your-access-token-secret"
  },
  "preferences": {
    "country": "DE",
    "currency": "EUR",
    "language": "en",
    "maxResults": 20,
    "defaultSort": "avg",
    "hideFoil": true,
    "showPerBooster": true,
    "productFilter": "both"
  },
  "cache": {
    "enabled": true,
    "ttl": 3600
  },
  "export": {
    "enabled": true,
    "autoUpdate": true
  },
  "ev": {
    "enabled": true,
    "autoUpdate": true,
    "updateFrequency": "weekly",
    "bulkCardThreshold": 1.0,
    "showVariance": false,
    "confidenceThreshold": 0.7
  }
}

Configuration Options

  • credentials: Your Cardmarket API credentials (optional - only required for live API mode with --live flag or advanced features like --condition, --include-shipping, etc.)
  • preferences.country: Your country code for shipping calculations (ISO 3166-1 alpha-2)
  • preferences.currency: Preferred currency display (EUR, USD, GBP, etc.)
  • preferences.language: Interface language
  • preferences.maxResults: Default maximum number of results (default: 20)
  • preferences.defaultSort: Export data sort order - options: trend, low, avg, name, none (default: avg)
  • preferences.hideFoil: Hide foil price column in export results (default: true)
  • preferences.showPerBooster: Show per-booster price column for sealed products (default: true)
  • preferences.productFilter: Filter products by type - options: singles, nonsingles, both (default: both)
  • cache.enabled: Enable/disable response caching (default: true)
  • cache.ttl: Cache time-to-live in seconds (default: 3600)
  • export.enabled: Enable export data mode (default: true)
  • export.autoUpdate: Automatically download export data if missing or old (default: true)
  • ev.enabled: Enable Expected Value calculations (default: true)
  • ev.autoUpdate: Automatically download Scryfall data if missing or old (default: true)
  • ev.updateFrequency: How often to update Scryfall data - options: daily, weekly, manual (default: weekly)
  • ev.bulkCardThreshold: Minimum card price to include in EV calculations in EUR (default: 1.0)
  • ev.showVariance: Show variance range in EV results (default: false)
  • ev.confidenceThreshold: Minimum confidence for EV calculations (default: 0.7)

Data Sources

This tool supports two data sources:

Export Data (Default)

  • What it is: Daily snapshots of all MTG products and price trends from Cardmarket
  • Includes: Singles AND sealed products (booster boxes, prerelease packs, bundles, etc.)
  • Size: ~41MB total (18MB singles + ~23MB sealed products + 23MB price guide)
  • Update frequency: Daily (automated download on first run, manual updates available)
  • Storage: Local ./data directory (gitignored)
  • Default sorting: By average price (ascending) - configurable in config.json
  • Advantages:
    • ⚡ Extremely fast searches (no API calls)
    • 🆓 No API rate limits
    • 📊 Includes price trends and statistics
    • 🎁 Includes sealed products (boosters, boxes, packs)
    • 📈 Smart sorting (cheapest options first)
  • Limitations:
    • No individual seller offers
    • No condition/foil/signed filtering
    • No real-time shipping calculations
    • Data refreshed daily (may be slightly outdated)

Live API (On-Demand)

  • What it is: Real-time queries to Cardmarket's API
  • Advantages:
    • 🔴 Live seller offers with real-time availability
    • 🎯 Full filtering (condition, foil, signed, altered)
    • 📦 Real shipping cost estimates
    • ⚡ Most up-to-date prices
  • Limitations:
    • Requires API credentials
    • Subject to rate limits (30,000 requests/day)
    • Slower than export mode

Automatic Mode Switching

The tool automatically chooses the best data source:

Uses Export Data when:

  • Basic card searches (name only)
  • Price range filtering
  • No shipping calculations needed
  • Export mode is enabled (default)

Switches to Live API when:

  • --include-shipping flag is used
  • Condition filtering (--condition NM)
  • Special card attributes (--foil, --signed, --altered)
  • Country filtering (--filter-country)
  • Seller grouping (--group-by-seller)
  • --live flag is explicitly set
  • Export mode is disabled

Usage

Build the Project

pnpm run build

Search Commands

Basic search (uses export data):

pnpm start search "Black Lotus"

Update export data:

# Update Cardmarket export data if old (>24 hours)
pnpm start update-data

# Update Scryfall EV data if old (>7 days)
pnpm start update-data --scryfall-only

# Update both Cardmarket and Scryfall data
pnpm start update-data --force

Force live API mode:

# Get real-time seller offers
pnpm start search "Black Lotus" --live

# Live mode with condition filtering
pnpm start search "Mox Pearl" --live --condition NM

Search with filters:

# Search for Near Mint cards (switches to API automatically)
pnpm start search "Lightning Bolt" --condition NM

# Search for foil cards in English (uses API)
pnpm start search "Tarmogoyf" --foil --language EN

# Search with price range (uses export data)
pnpm start search "Mox Pearl" --min-price 100 --max-price 500

# Search for specific set
pnpm start search "Force of Will" --set ALL

Sealed products with per-booster pricing and EV:

# Find booster boxes with per-booster cost and expected value
pnpm start search "Bloomburrow Play Booster Box" --show-ev

# Calculate EV for multiple sets
pnpm start search "booster box" --show-ev --top 10

# Search only sealed products (no singles)
pnpm start search "Bloomburrow" --product-filter nonsingles --top 10

# Search only singles (no sealed products)
pnpm start search "Lightning Bolt" --product-filter singles

# Show foil prices too (overrides hideFoil preference)
pnpm start search "Foundations Bundle" --show-foil

# Hide per-booster column (overrides showPerBooster preference)
pnpm start search "Duskmourn Collector Booster Box" --hide-per-booster

Include shipping costs:

# Show total price including shipping
pnpm start search "Volcanic Island" --include-shipping

# Only show sellers who ship to your country
pnpm start search "Underground Sea" --include-shipping --filter-country

# Show top 10 offers by total cost
pnpm start search "Tundra" --include-shipping --top 10

Output formats:

# Table format (default)
pnpm start search "Birds of Paradise"

# JSON format
pnpm start search "Birds of Paradise" --json

# Save to file
pnpm start search "Birds of Paradise" --json > results.json

Advanced options:

# Group by seller to optimize shipping
pnpm start search "Sol Ring" --include-shipping --group-by-seller

# Sort results
pnpm start search "Counterspell" --sort price
pnpm start search "Dark Ritual" --sort seller-rating

# Disable cache for fresh results
pnpm start search "Brainstorm" --no-cache

Command Options

Option Description Values Default
--condition Card condition (forces API mode) NM, EX, GD, LP, PL, PO -
--foil Only foil cards (forces API mode) boolean false
--signed Only signed cards (forces API mode) boolean false
--altered Only altered cards (forces API mode) boolean false
--language Card language EN, DE, FR, IT, ES, JP, etc. -
--set Expansion set code 3-letter set codes -
--min-price Minimum price number -
--max-price Maximum price number -
--include-shipping Include shipping costs (forces API mode) boolean false
--filter-country Filter sellers by shipping to your country boolean false
--top Show top N offers number -
--group-by-seller Group offers by seller boolean false
--sort Sort results price, condition, seller-rating -
--json Output in JSON format boolean false
--live Force live API mode instead of export data boolean false
--no-cache Disable caching for this request boolean false
--max-results Maximum results to show number from config
--show-foil Show foil price column (overrides hideFoil) boolean from config
--hide-per-booster Hide per-booster column (overrides showPerBooster) boolean from config
--product-filter Filter by product type singles, nonsingles, both both
--show-ev Show expected value for sealed products boolean false

Help Command

pnpm start help
pnpm start --help
pnpm start search --help

Examples

Find the cheapest Near Mint Black Lotus including shipping:

pnpm start search "Black Lotus" --condition NM --include-shipping --sort price --top 5

Find foil Lightning Bolts in English under 10 EUR:

pnpm start search "Lightning Bolt" --foil --language EN --max-price 10

Compare booster box values by expected value:

pnpm start search "Foundations Play Booster Box" --show-ev
# Output includes EV data:
# Foundations Play Booster Box | €124.88 avg | €3.47 per booster | Box EV: €799.54 | Ratio: 6.40x | ✓ Pos

Find the best EV booster boxes:

pnpm start search "booster box" --show-ev --top 10 --product-filter nonsingles
# Compares EV ratios across different sets

Export search results to JSON:

pnpm start search "Mana Crypt" --json > mana-crypt-prices.json

Project Structure

cardmarket-cli/
├── src/
│   ├── index.ts                 # Main CLI entry point
│   ├── config.ts                # Configuration loader
│   ├── api/
│   │   ├── client.ts            # API client with OAuth
│   │   ├── auth.ts              # OAuth signature generation
│   │   └── endpoints.ts         # API endpoint methods
│   ├── export/
│   │   ├── types.ts             # Export data TypeScript types
│   │   ├── downloader.ts        # Export file downloader
│   │   └── searcher.ts          # Export data searcher
│   ├── ev/
│   │   ├── types.ts             # EV TypeScript types
│   │   ├── scryfall-downloader.ts  # Scryfall bulk data downloader
│   │   ├── scryfall-loader.ts   # Card data loader with indexing
│   │   ├── expansion-mapper.ts  # Maps Cardmarket to Scryfall sets
│   │   ├── collation-engine.ts  # Booster pack composition engine
│   │   └── ev-calculator.ts     # Main EV calculation logic
│   ├── commands/
│   │   ├── search.ts            # Search command implementation
│   │   ├── help.ts              # Help command
│   │   └── types.ts             # Shared TypeScript types
│   └── utils/
│       ├── shipping.ts          # Shipping cost calculations
│       ├── formatter.ts         # Output formatting
│       ├── cache.ts             # Caching utilities
│       └── booster-count.ts     # Per-booster pricing lookup
├── data/                        # Data files (gitignored)
│   ├── products_singles.json    # Singles export data
│   ├── products_nonsingles.json # Sealed products export data
│   ├── price_guide.json         # Price guide export data
│   ├── booster-counts.json      # Booster count database
│   ├── scryfall_cards.json      # Scryfall card data with EUR prices
│   ├── scryfall_metadata.json   # Scryfall data metadata
│   ├── expansion_mapping.json   # Cardmarket to Scryfall mapping
│   └── booster_collation.json   # Pack composition rules
├── config.example.json          # Example configuration
├── package.json
├── tsconfig.json
└── README.md

Development

Watch mode for development:

pnpm run watch

Clean build artifacts:

pnpm run clean

API Rate Limits

Cardmarket API has rate limits:

  • Standard accounts: 30,000 requests/day
  • Professional sellers: 100,000 requests/day

This tool includes built-in caching to minimize API calls. Cache is enabled by default with a 1-hour TTL.

Documentation

Official Cardmarket Resources

Troubleshooting

"Failed to load export data" error:

  • Run pnpm start update-data to download export files
  • Check internet connection (files are ~41MB total)
  • Verify ./data directory is writable

"Export data is more than 24 hours old" warning:

  • Run pnpm start update-data to refresh data
  • Or use --live flag to bypass export data

EV calculation showing "N/A":

  • Run pnpm start update-data --scryfall-only to download Scryfall data
  • Ensure product is a sealed booster product (not singles)
  • Check that the set is supported (recent sets preferred)

"Invalid OAuth signature" error:

  • Verify your API credentials in config.json
  • Ensure your system clock is synchronized (OAuth uses timestamps)
  • Note: Only needed for live API mode, not export mode

"Rate limit exceeded" error:

  • Use export data mode (default) to avoid rate limits
  • Enable caching (default)
  • Reduce the number of requests
  • Wait for the rate limit to reset (daily)

No results found:

  • Check card name spelling
  • Try without filters first
  • Some cards may not be available in the specified condition/language
  • Export data includes singles and sealed products, but not all product types

License

MIT License - See LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Disclaimer

This tool is not affiliated with or endorsed by Cardmarket. Use responsibly and in accordance with Cardmarket's Terms of Service and API usage policies.

About

Some useful stuff for MTG info on Cardmarket (EU)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors