Tcgplayer Scraper
Pricing
from $9.80 / 1,000 results
Tcgplayer Scraper
Get TCGplayer card and product data for Pokemon, Magic, Yu-Gi-Oh, and every game on the platform — no API key needed. Real per-seller listings with condition and price, server-side filters by set/rarity/price, and full historical price charts. Search, lookup by ID, or track price history.
Pricing
from $9.80 / 1,000 results
Rating
0.0
(0)
Developer
Norm Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share

TCGplayer Scraper
Get TCGplayer card and product data for Pokemon, Magic: The Gathering, Yu-Gi-Oh, and every other trading card game on the platform with no API key and no login: market price, every seller listing with condition and reputation, and full historical price and sales-volume charts. Filter by set, rarity, condition, and price, or look up specific products by ID.
Here is one real row:
{"product_id": 106999,"product_name": "Charizard - Base Set (Shadowless)","product_url": "https://www.tcgplayer.com/product/106999/Charizard-Base-Set-Shadowless","image_url": "https://product-images.tcgplayer.com/fit-in/400x400/106999.jpg","game": "Pokemon","set_name": "Base Set","set_code": "BS","rarity": "Holo Rare","market_price": 892.5,"median_price": 850,"lowest_price": 599.99,"lowest_price_with_shipping": 610.98,"total_listings": 14,"listings": [{"seller_name": "CardShopPro","seller_rating": 99.8,"seller_sales": 15234,"verified_seller": true,"condition": "Near Mint","printing": "Unlimited","price": 599.99,"shipping_price": 10.99,"total_price": 610.98,"quantity": 1}],"scraped_at": "2026-09-12T00:00:00.000Z"}
What it does
Reads TCGplayer's own public search and pricing endpoints directly and normalizes every card or product into a flat row.
- Search filters the whole TCGplayer catalog: by name, game, set, rarity, listing condition, and price range.
- Look up resolves exact product IDs, one row per ID, with the same full detail as search. A
product that doesn't resolve comes back as an
errorrow. - Price history returns a real daily price and sales-volume chart for each product ID, broken out by every condition/printing/edition combination TCGplayer tracks separately.
Missing source values are returned as null, never invented.
Why this scraper
- Real seller listings, not just an aggregate price. Every listing's condition, printing, language, seller name, rating, sales count, and price plus shipping - not just a market-price number.
- Server-side filters that actually narrow the search. Set, rarity, listing condition, and price range all filter at the source, so you never pay for a page of results you then have to filter yourself.
- Real historical price charts. Daily market price, sale price range, and quantity sold, per condition/printing/edition, going back a full quarter - not a short list of recent sales.
- Works with every TCGplayer game, not just Pokemon: verified live across Magic: The Gathering, Yu-Gi-Oh, Cardfight!! Vanguard, Dragon Ball Super, and more in the same run.
- A normal
maxItemscap, not manual page-and-count math. - No API key, no login, no browser. Reads only what TCGplayer's own site reads.
How it compares
Checked directly against both other TCGplayer scrapers on Apify (their own declared input/output, not a guess):
| Capability | This actor | parseforge/tcgplayer-scraper | devcake/tcgplayer-data-scraper |
|---|---|---|---|
| Every TCGplayer game | yes | Pokemon only | yes |
| Per-seller listings (condition, rating, price + shipping) | yes | no | yes |
| Filter by set | yes | yes | no |
| Filter by rarity | yes | yes | no |
| Filter by listing condition | yes | no | no |
| Filter by price range | yes | no | no |
| Historical price / volume chart | yes | no | recent sales list only |
maxItems cap | yes | yes | no (manual page math) |
| Direct lookup by product ID | yes | no | no |
| Declared dataset schema | yes | yes | no |
Use cases
- Arbitrage and reselling. Find the cheapest real listing for a card, by condition, across every seller, not just an aggregate low price.
- Collection valuation. Price a whole collection by looking up each product ID.
- Price tracking. Pull the daily price and volume chart for cards you're watching.
- Deck-building and budget planning. Filter competitive staples by price range and set.
- Market research. Track price trends by set, rarity, or game over time.
- Inventory pricing for a card shop. Keep listings priced against real current market data.
Quickstart
Search: Pokemon cards from Base Set with Holo Rare rarity, priced $10-500, Near Mint listings only.
{ "mode": "search", "game": "Pokemon", "setName": "Base Set", "rarityName": "Holo Rare", "condition": "Near Mint", "priceMin": 10, "priceMax": 500, "maxItems": 100 }
Search: Magic: The Gathering cards matching a name, cheapest first.
{ "mode": "search", "query": "black lotus", "game": "Magic: The Gathering", "sortField": "market-price", "sortOrder": "asc", "maxItems": 50 }
Look up specific products:
{ "mode": "lookup", "productIds": [106999, 654213] }
Price history for the last quarter:
{ "mode": "priceHistory", "productIds": [106999], "priceHistoryRange": "quarter" }
Input reference
| Field | Applies to | Description |
|---|---|---|
maxItems | all | Ceiling on rows written. |
mode | all | search, lookup, or priceHistory. |
query | search | Card or product name contains this text. |
game | search | TCGplayer's own game name, e.g. Pokemon, Magic: The Gathering, YuGiOh. |
setName | search | Exact TCGplayer set name. |
rarityName | search | Exact TCGplayer rarity name; varies by game. |
condition | search | Only return seller listings in this condition, e.g. Near Mint. |
priceMin / priceMax | search | Market price range, USD. |
foilOnly | search | Only foil-only prints. |
sortField / sortOrder | search | Sort by market price (verified), best-selling, or product name. |
productIds | lookup, priceHistory | TCGplayer product IDs (the number in a product's URL). |
priceHistoryRange | priceHistory | month or quarter - the only two ranges TCGplayer's own endpoint supports. |
Output reference (selected)
| Field | Description |
|---|---|
product_id / product_name / product_url / image_url | Identity. |
game / set_name / set_code / rarity | Classification. |
market_price / median_price / lowest_price / lowest_price_with_shipping | Pricing. |
total_listings | Total active seller listings for this product. |
listings | { seller_name, seller_rating, seller_sales, verified_seller, gold_seller, condition, printing, language, price, shipping_price, total_price, quantity, listed_date }[]. |
custom_attributes | Game-specific card attributes (HP, energy type, stage, attack text, etc.), when TCGplayer has them. Cleaned of the display markup (<strong>, <br>, etc.) TCGplayer's own API embeds directly in the text. |
range / skus | Price-history mode: the requested range, and one entry per condition/printing/edition with a dated buckets[] series. |
query / error | Set on an unresolved look-up row. |
scraped_at | ISO 8601 collection timestamp. |
Run via API and CLI
curl -X POST "https://api.apify.com/v2/acts/USERNAME~tcgplayer-scraper/run-sync-get-dataset-items?token=<TOKEN>" \-H "Content-Type: application/json" \-d '{"mode":"lookup","productIds":[106999]}'
$apify call USERNAME/tcgplayer-scraper --input '{"mode":"search","game":"Pokemon","rarityName":"Holo Rare","maxItems":500}'
Fetch results
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=json"curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
Billing and limits
- Pay per result. Billed per row written (one row per product, or one row per product ID in price-history mode).
- No charge on failure. A run that produces zero rows fails with a message and is not billed.
- An unresolved look-up or price-history product ID still writes one
error: "not found"row and is billed as a base row. - Free Apify plans run the built-in 10-row sample only.
FAQ and troubleshooting
Do I need a TCGplayer API key? No. TCGplayer's own public search and pricing endpoints are read directly, with no key and no login.
Why did my search return zero rows? No product matched the filters. Loosen them, check the
exact spelling of setName/rarityName (TCGplayer's own values, case-sensitive), or widen the
price range.
Why is market_price null for some products? TCGplayer only computes a market price when it
has enough recent sales data. An obscure or rarely-traded product can genuinely have none. This
Actor reports null rather than guessing.
Why is median_price null much more often than market_price? Verified directly against
TCGplayer's own raw response (about 1 in 4 products carry it, checked at scale): TCGplayer
computes a median far less often than a market price, most often skipping it for lower-volume
single cards. When it's missing, TCGplayer's own response doesn't include the field at all - not
a gap in how this Actor reads it.
Why is product_type usually empty? TCGplayer's own search endpoint doesn't return this
field for the large majority of products (confirmed at scale, not a parsing gap). It's kept in
the output for the products where it is present.
Where does the product image come from? TCGplayer's own search results carry no product
image field at all. image_url is built directly from product_id against TCGplayer's own
image CDN (product-images.tcgplayer.com), verified to return a real image for every product ID
tested.
Why do listings and custom_attributes show up as raw text in CSV or Excel? Those formats
have no way to represent a nested list or object inside one cell, so they're serialized to a JSON
string there - the same as every nested field on any Apify Actor. In the Apify Console's dataset
table, and in the JSON export, they render as proper structured data.
Can I get a price history longer than a quarter? No. TCGplayer's own history endpoint only
supports month and quarter ranges.
Why can a large search run take longer than the result count suggests? TCGplayer's own
relevance search doesn't paginate against a perfectly stable view of the catalog, so the same
product can appear on more than one page. This Actor drops repeats and keeps fetching until it
has enough distinct rows, not just enough raw pages - a large maxItems can take a little
longer as a result. The alternative (not de-duplicating) would be faster but wrong.
How current is the data? Read live from TCGplayer's own endpoints on every run. It is not cached.
Is this an official TCGplayer tool? No. Independent, not affiliated with TCGplayer. It reads only publicly available data.
Local development
bun installbun test # offline: normalisation, filter-building, input logic (real fixtures)bun run src/main.ts # reads storage/key_value_stores/default/INPUT.json