Scryfall LLC · Magic: The Gathering only
Scryfall alternative — beyond Magic
Scryfall is the best Magic API there is, and it is free. TCGGraph is what you reach for when your app also needs Pokémon, One Piece or Lorcana behind one key.
What Scryfall does well
- Free, generous and genuinely excellent for Magic. No key required.
- The best full-text search syntax in the hobby, and a huge community around it.
- Complete Oracle text, every printing, every language, plus bulk data dumps.
- Run by people who care deeply about Magic data quality.
Where TCGGraph differs
- Scryfall covers Magic and only Magic, by design. If your product is Magic-only, that is not a limitation.
- TCGGraph carries nine games behind one schema, so adding a second game costs you an enum value rather than a second integration.
- TCGGraph normalises prices across Cardmarket, TCGplayer, Card Kingdom and Manapool with daily history; Scryfall surfaces marketplace links and current prices.
- TCGGraph offers signed webhooks for set releases, spoilers and legality changes, so you do not have to poll.
Side by side
Feature comparison
| Feature | Scryfall | TCGGraph |
|---|---|---|
| Games covered | Magic only | 9 games |
| Consistent schema across games | ||
| Price history | Current prices | Daily, accumulating |
| European prices (Cardmarket) | Magic only | 8 games |
| US prices (TCGplayer) | Magic only | All 9 games |
| Normalised multi-marketplace prices | 4 sources | |
| GraphQL | ||
| Webhooks | ||
| Bulk data files | Paged, 2 credits per 100 cards | |
| Image CDN | ||
| Price | Free | From $29/mo |
When to use Scryfall instead
If you are building a Magic-only product, use Scryfall. It is free, the data is excellent and the search syntax is unmatched. Come back when you add a second game, a second currency, or a price you need to put in front of a paying customer.
Migration
What the change looks like
Concepts map closely. Most migrations are a single afternoon of find-and-replace plus a test pass.
# Scryfall
curl "https://api.scryfall.com/cards/search?q=c:red+cmc<=2"# TCGGraph — same query, and the shape survives adding a second game
curl "https://api.tcggraph.com/v1/cards?game=magic-the-gathering&colors=R&manaValue=2" \
-H "Authorization: Bearer $TCGGRAPH_KEY"Signals
When it is worth switching
None of these are reasons on their own. Two or three together usually are.
- You are adding a second game and do not want to write a second ingestion layer, a second cache and a second price model.
- You need price history rather than a spot price — for a portfolio chart, a repricing job or a trend alert.
- You want to be told when a set publishes or a card's legality changes, instead of diffing bulk files on a cron.
- You need an uptime commitment and a support contact, because something you sell depends on the data being there.
Migration
Moving off Scryfall, step by step
The honest version, including the parts that are not one-to-one.
Step 1
Map the search syntax
Scryfall's query language is more expressive than any parameter-based API, and that is the part you will miss. Common ones translate directly: c:u becomes colors=U, id:u becomes colorIdentity=U, cmc<=3 becomes maxManaValue=3, kw:flash becomes keywords=Flash, and filters combine with AND. What does not translate is OR, negation, text search and format legality. t:dragon has no equivalent either, because typeLine matches the whole line. Read legalities on the cards you fetch, and run one request per alternative where Scryfall would take an OR.
Step 2
Switch the identifier you key on
A card record here is one printing, like a Scryfall card object, and its id is ours, not Scryfall's. To map your stored rows, join on tcgplayerId or cardmarketId, which Scryfall also publishes and every record carries in externalIds. There is no oracle_id equivalent: group printings by name, which Magic keeps unique per rules object.
Step 3
Move price reads off the card object
Scryfall attaches a small price object to each card. Every card here carries prices[], one quote per marketplace, finish and list type, and the daily history is one call away at /v1/prices/{id}/history. There is nothing to opt into and no blended number.
Step 4
Keep Scryfall where it is better
Plenty of teams run both: Scryfall for its search syntax on a Magic-only screen, us for everything cross-game. They are not mutually exclusive, and we would rather tell you that than pretend otherwise.
Field mapping
What each field becomes
The part that takes the longest is discovering that Scryfall spells the same concept differently. Here it is, written down.
| Scryfall | TCGGraph | Notes |
|---|---|---|
| oracle_id | — (not carried) | Group printings by name instead. |
| tcgplayer_id | externalIds.tcgplayerId | The join key for a migration, with cardmarket_id. |
| cmc | gameData.manaValue | Renamed by Wizards in 2021; we follow the current term. |
| type_line | gameData.typeLine | Same string, em dash included. |
| color_identity | gameData.colorIdentity | Array of single-letter codes in both. |
| card_faces | name, text, gameData.typeLine | One record; the faces joined with " // ", layout says how. |
| legalities.commander | legalities.commander | Same keys, same four values. |
| prices.usd | prices[].market | Ours is an array by source and finish, not one field. |
| image_uris.normal | images.normal | Unmetered on both. No credit cost here either. |
FAQ
Common questions
Anything else, email hello@tcggraph.com. We will tell you if the answer is that you should stay where you are.
More comparisons