Pokemon Card Arbitrage - Cardmarket vs TCGplayer
Pricing
from $4.50 / 1,000 results
Pokemon Card Arbitrage - Cardmarket vs TCGplayer
EU vs US card prices in one run: Cardmarket trend (EUR) against TCGplayer market (USD), matched card-by-card via collector number, converted at the daily ECB rate. Spread percent, cheaper side and both product links per row. Aggregate prices only - no listings, no sellers.
Pricing
from $4.50 / 1,000 results
Rating
0.0
(0)
Developer
Lowland Data
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
4 days ago
Last modified
Categories
Share
Compares the price of the same Pokémon card on Cardmarket (EU) and TCGplayer (US) and reports every spread worth acting on, converted at the day's official ECB rate, matched by card number so a Base Set Charizard never gets compared to a promo. One row per card with both market prices, the spread percent, and which side is cheaper.
Live health record: lowlanddata.com/status/tcg-price-arbitrage - 30-day success rate and daily canary results, failures included. Full input/output reference: tool page.
Quick start (30 seconds)
- Type the cards to compare: "umbreon gx", "charizard ex", "mew".
- Set the minimum spread (default 20%).
- Hit Start. Each row is one card priced on both markets:
{"name": "Umbreon GX (SM36)","game": "Pokémon","cardNumber": "SM36","setNameUs": "SM Black Star Promos","rarity": "Promo","trendEurCardmarket": 24.5,"marketUsdTcgplayer": 41.2,"marketUsdInEur": 35.4,"spreadPct": 44.5,"cheaperSide": "EU","eurPerUsd": 0.86,"urlCardmarket": "https://www.cardmarket.com/en/Pokemon/Products/Singles/SM-Promos/Umbreon-GX-SM36?language=1","urlTcgplayer": "https://www.tcgplayer.com/product/153552","priceGuideDate": "2026-09-03"}
cheaperSide: "EU" with a 44% spread reads: buy on Cardmarket, the US market values it 44% higher. urlCardmarket lands pre-filtered to English copies - the US side of every spread is TCGplayer's English-printing market price, so a cheap Italian copy is not the arbitrage you are looking at.
Who uses this
- Cross-market resellers run their staples list daily and act when a spread crosses their shipping-plus-fees threshold.
- EU buyers check whether a US import is actually cheaper once the ECB rate is applied, before ordering.
- Collectors selling out pick the market that values their cards higher, card by card instead of by gut feel.
How it works
- EU side: Cardmarket's official daily price guide, the trend price of every product, from openly published files. That trend is what the card has been selling for, which is not the same as the cheapest copy listed right now; on a thinly traded card the two can differ by a factor. A spread is therefore a signal to go and check both markets, not a quote you can fill at.
- US side: TCGplayer's market price, from its own public storefront search.
- Matching: cards pair by name and collector number: the reason this is Pokémon-only for now, since that numbering discipline is what makes the join trustworthy.
- Conversion: the day's ECB reference rate, fetched automatically (override with
eurPerUsdif you hedge at your own rate).
Rows come back sorted by spread, steepest first. Cards that only exist on one market are skipped, not guessed.
How much does it cost?
$0.005 per spread row plus $0.005 per run, on the standard tier. You pay per actionable spread, not per card checked: a run where the markets agree costs half a cent. A daily watch on a 10-card staples list: a few cents a day. Platform usage (the EU side uses Apify's Site Unblocker proxy) is billed by Apify alongside, a few cents per run.
Not technical? Let your AI assistant set it up
Paste this to Claude, ChatGPT or Cursor:
I want EU-vs-US card price spreads from the Apify actorlowlanddata/tcg-price-arbitrage. Build me the input JSON.Fields:- searchQuery: cards to compare, e.g. "umbreon gx" (required)- minSpreadPct: only report spreads at least this big (default 20)- priceMinEur: skip cards under this EU trend price - bulk spreads are noise (default 5)- eurPerUsd: leave empty for the daily ECB rate- maxItems: cap on delivered rows- game: pokemon (the only game for now - matching is verified on Pokémon numbering)- keep proxyConfiguration exactly as prefilledHere is my list: <cards>Give me the JSON only, then tell me how to run it daily on a schedule.
Input
| Field | What it does |
|---|---|
searchQuery | Cards to compare across the two markets. |
minSpreadPct | Only report spreads at least this big (default 20). |
priceMinEur | Skip cards under this EU trend price (default 5), bulk is noise. |
eurPerUsd | Empty = the daily ECB reference rate. |
maxItems | Cap on delivered rows. |
game | pokemon, the cross-market match is verified on Pokémon numbering. |
proxyConfiguration | Keep the prefill: Cardmarket requires the Site Unblocker proxy. |
Use it from your code
curl -X POST \"https://api.apify.com/v2/acts/lowlanddata~tcg-price-arbitrage/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"searchQuery":"charizard ex","minSpreadPct":25}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('lowlanddata/tcg-price-arbitrage').call({searchQuery: 'umbreon gx',minSpreadPct: 15,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(token=os.environ["APIFY_TOKEN"])run = client.actor("lowlanddata/tcg-price-arbitrage").call(run_input={"searchQuery": "mew ex","minSpreadPct": 20,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["name"], row["spreadPct"], row["cheaperSide"])
Use it with AI agents (MCP)
$claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/tcg-price-arbitrage"
Cursor or Claude Desktop: add a custom connector with https://mcp.apify.com?actors=lowlanddata/tcg-price-arbitrage. Sign in with your Apify account when prompted. Runs are billed to it. Details: Apify MCP docs.
Prompts that work once connected:
- "Where is Umbreon GX cheaper right now, EU or US, and by how much?"
- "Check my staples list for EU-US spreads over 25%."
Is it legal?
Yes. The EU prices come from files Cardmarket publishes openly; the US prices from TCGplayer's own public storefront search; the exchange rate from the ECB. All of it is aggregate market data, no sellers, no listings text, no personal data of any kind in the source or the output.
FAQ
Why Pokémon only? The match joins cards by name and collector number, and that convention is verified to line up between the two markets for Pokémon. A wrong match here would produce confident nonsense: other games ship when their numbering proves out, not before.
Do the prices include shipping and fees? No. These are the markets' own reference prices. Your actionable threshold should include your shipping, fees and grading risk; that is what minSpreadPct is for.
Why did a card from my query not appear? Either it exists on only one of the two markets (skipped, not guessed), its EU trend is under priceMinEur, or the spread is below your bar.
How fresh are the numbers? The EU guide refreshes daily (see priceGuideDate); the US market price and the ECB rate are read live at run time.
Related actors
- Cardmarket Price Guide: the full EU price guide, 19 games.
- Cardmarket Deal Finder: live EU offers under trend, the buy side of the trade.
Troubleshooting
- "... matched 0 Cardmarket and N TCGplayer products - broaden the query": the query found nothing on one side; use the card's common English name.
- "Cardmarket did not answer after N attempts on fresh routes": temporary outage or block streak on their side; the run says so honestly rather than returning empty rows. Retry in a few minutes.
- A spread looks too good. Check
cardNumberandsetNameUson the row: if a promo reprint exists, the two markets may price different printings. The number match prevents most of this; the columns are there so you can verify before wiring money.
Something else off? Open an issue on the Issues tab. It is read daily.