datagrit

datagrit › Data › TCGplayer Price Trends & Sales Velocity Tracker

Data

TCGplayer Price Trends & Sales Velocity Tracker

TCGplayer card and sealed product prices with 30 and 90 day price change, sales velocity and days of supply per printing.

Run it on Apify StoreUse the APIfrom $7.00 per 1,000 results + $10 per run · no code needed
from $7.00 per 1,000 results + $10 per runpay only for price trend rows you get
JSON · CSV · Excelexport or call via API
Scheduled runsdaily or weekly feeds with Apify schedules
v0.2updated 2026-09-30

TCGplayer Price Trends & Sales Velocity Tracker reads the public TCGplayer catalogue and returns, for every printing and language of a card or sealed product, the current market price, the 30-day and 90-day price change, the units sold in 30 and 90 days, sales per day and days of supply. Results are clean records you can export as JSON, CSV or Excel, call through the Apify API, or connect to n8n, Make and AI agents through MCP.

It is built for card resellers, collectors, investors and price-tracking tools that need to know which cards are moving, not only what they cost today. Choose a game, add search terms, set your filters and run.

Why track TCGplayer prices and sales velocity?

What data can you extract from TCGplayer?

Each row is one printing and language of one product, for example the Holofoil English copy of a card. The figures refer to the main condition: Near Mint for cards and Unopened for sealed products.

productNamesetNamevariantlanguagemarketPricepriceChange30dPctsold30dsold90dsoldPerDaydaysOfSupply
Charizard GX - 9/68 (#60 Charizard Stamped)Battle AcademyHolofoilEnglish14.578.8351381.5354.2
Charizard - 3/70 (#39 Charizard Stamped)Battle AcademyNormalEnglish7.37-0.3731321.4746.3

{
  "found": true,
  "productId": 219059,
  "productName": "Charizard GX - 9/68 (#60 Charizard Stamped)",
  "productLine": "Pokemon",
  "setName": "Battle Academy",
  "variant": "Holofoil",
  "language": "English",
  "condition": "Near Mint",
  "sealed": false,
  "marketPrice": 14.57,
  "priceChange30dPct": 8.8,
  "priceChange90dPct": 12.1,
  "lowSalePrice90d": 10.2,
  "highSalePrice90d": 20,
  "sold30d": 35,
  "sold90d": 138,
  "soldPerDay": 1.53,
  "marketPriceLightlyPlayed": 10.67,
  "daysOfSupply": 54.2,
  "productUrl": "https://www.tcgplayer.com/product/219059"
}

The record also holds set code, card number, rarity, release date, the last sales window, sales across all conditions, listing count, lowest and median listing price, image URL and scrapedAt.

How to use the TCGplayer Price Trends Tracker

  1. Pick a game in Game and add Search terms, for example charizard, booster box or lightning bolt. Leave the terms empty and pick a game, a set or both to read a whole game or set; this also works when you call the Actor through the API.
  2. Set the number of products to read in Maximum products to scan and the row limit in Maximum results.
  3. Add filters, for example a minimum number of units sold or a minimum 30-day price change.
  4. Run the Actor and download the dataset.

How the numbers are calculated

The market price is TCGplayer's own market price for the main condition in the latest 3-day window. It is an average of recent sales and carries over when nothing sold, so a price change is reported only when the printing had at least one sale in that window; otherwise the field is empty. Units sold are summed over the 3-day windows of the last 30 or 90 days, for the main condition. The 90-day change needs at least 84 days of history, so new releases have an empty 90-day change. Days of supply divides the active listings of the whole product by its average daily sales across all printings and conditions.

TCGplayer reports sales per 3-day window, so figures are estimates of real sales volume rather than an audited count.

Is it legal to scrape TCGplayer?

The Actor reads only publicly available catalogue and sales information and does not log in or bypass access controls. You are responsible for using the data in line with applicable laws and the terms of the source. If you find an issue, open it in the Issues tab; problems are answered within one business day.

Output fields

Every result is one flat record, so it drops straight into a spreadsheet, a database or a CRM.

FieldTypeDescriptionExample
foundbooleanFalse only on the single status row emitted when nothing matched; every other field of that row is empty.true
productIdintegerTCGplayer product id. One product can produce several rows, one per printing and language.219059
productNamestringName of the card or sealed product as listed on TCGplayer.Charizard GX - 9/68 (#60 Charizard Stamped)
productLinestringTrading card game (product line) the product belongs to.Pokemon
setNamestringSet or expansion name.Battle Academy
setCodestringShort set code used by TCGplayer, when it has one.BTA
cardNumberstringCollector number printed on the card. Empty for sealed products and for cards without a number.009/068
raritystringRarity as named by TCGplayer. Empty for some sealed products.Promo
releaseDatestringRelease date of the card or product in YYYY-MM-DD form, when TCGplayer has it.2020-07-31
variantstringPrinting of the product, for example Normal, Foil, Holofoil or Reverse Holofoil. Each printing has its own price and sales.Holofoil
languagestringLanguage of the printing.English
conditionstringCondition the price and sales figures refer to: Near Mint for cards, Unopened for sealed products. If a printing has no Near Mint sales series, the condition with the most sales is used.Near Mint
sealedbooleanTrue when the price series is for an unopened sealed product such as a booster box.false
marketPricenumberTCGplayer market price of the main condition in the most recent 3-day window. It is an average of recent sales, so it carries over when nothing sold.14.57
priceChange30dPctnumberChange of the market price between the window about 30 days ago and the latest window. Empty when a price is missing or when the printing had no sales in the last 30 days, because the market price then only carries over.8.8
priceChange90dPctnumberChange of the market price between the oldest window of the 90-day history (about 87 days ago) and the latest window. Empty when a price is missing, when the printing has less than 84 days of history, or when it had no sales in 90 days.12.1
lowSalePrice90dnumberLowest single sale price (without shipping) in the 90-day history, taken over windows that had sales.10.2
highSalePrice90dnumberHighest single sale price (without shipping) in the 90-day history, taken over windows that had sales.20
sold30dintegerUnits sold at the main condition in the last 30 days, summed from the 3-day windows.35
sold90dintegerUnits sold at the main condition in the 90-day history, summed from the 3-day windows.138
soldPerDaynumberAverage units sold per day at the main condition over the 90-day history (sold90d divided by the days covered).1.53
lastSaleWindowStartstringStart date (YYYY-MM-DD) of the most recent 3-day window in which this printing sold. The sale happened on or up to 2 days after this date.2026-09-28
allConditionsSold90dintegerUnits sold in the 90-day history across all conditions of this printing and language.275
marketPriceLightlyPlayednumberLatest market price of the Lightly Played condition. Empty when this condition has no price series.10.67
marketPriceModeratelyPlayednumberLatest market price of the Moderately Played condition. Empty when this condition has no price series.9.6
marketPriceHeavilyPlayednumberLatest market price of the Heavily Played condition. Empty when this condition has no price series.7.4
marketPriceDamagednumberLatest market price of the Damaged condition. Empty when this condition has no price series.5.2
listingsCountintegerNumber of active seller listings for the whole product, across all printings, languages and conditions.114
lowestListingPricenumberLowest active listing price for the whole product, across all printings and conditions. Not specific to this printing.7.21
medianListingPricenumberMedian price of the active listings for the whole product, when TCGplayer reports it.13.9
daysOfSupplynumberActive listings of the whole product divided by its average daily sales across all printings and conditions. A low number means stock sells out fast; empty when nothing sold in 90 days.54.2
productUrlstringTCGplayer page of the product.https://www.tcgplayer.com/product/219059
imageUrlstringProduct image on the TCGplayer image server.https://product-images.tcgplayer.com/fit-in/437x437/219059.jpg
scrapedAtstringISO 8601 timestamp of extraction.2026-09-30T08:00:00.000Z

Sample record

{
  "found": true,
  "productId": 219059,
  "productName": "Charizard GX - 9/68 (#60 Charizard Stamped)",
  "productLine": "Pokemon",
  "setName": "Battle Academy",
  "setCode": "BTA",
  "cardNumber": "009/068",
  "rarity": "Promo",
  "releaseDate": "2020-07-31",
  "variant": "Holofoil",
  "language": "English",
  "condition": "Near Mint",
  "sealed": false,
  "marketPrice": 14.57,
  "priceChange30dPct": 8.8,
  "priceChange90dPct": 12.1,
  "lowSalePrice90d": 10.2,
  "highSalePrice90d": 20,
  "sold30d": 35,
  "sold90d": 138,
  "soldPerDay": 1.53,
  "lastSaleWindowStart": "2026-09-28",
  "allConditionsSold90d": 275,
  "marketPriceLightlyPlayed": 10.67,
  "marketPriceModeratelyPlayed": 9.6,
  "marketPriceHeavilyPlayed": 7.4,
  "marketPriceDamaged": 5.2,
  "listingsCount": 114,
  "lowestListingPrice": 7.21,
  "medianListingPrice": 13.9,
  "daysOfSupply": 54.2,
  "productUrl": "https://www.tcgplayer.com/product/219059",
  "imageUrl": "https://product-images.tcgplayer.com/fit-in/437x437/219059.jpg",
  "scrapedAt": "2026-09-30T08:00:00.000Z"
}

Input

FieldNameTypeWhat it does
searchQueriesSearch termsarrayCard or product names to search on TCGplayer, for example charizard or booster box. Every term is searched separately and a product found twice is returned once. Leave empty to read a whole product line or set.
productLineGame (product line)stringLimit the search to one trading card game. Choose All games to search every line, which works best together with a search term or a set.
setNamesSetsarrayOptional. Keep only products from these sets, for example Base Set or swsh-crown-zenith. Use the set name as shown on TCGplayer or the last part of the set URL. A set that does not exist in the chosen game stops the run with an error that lists similar names.
raritiesRaritiesarrayOptional. Keep only these rarities, for example Secret Rare or Special Illustration Rare. Names follow TCGplayer and differ by game.
productTypeCards or sealed productsstringSingle cards and sealed products (booster boxes, packs, decks) are both in the catalogue. Sealed products are the ones sold as Unopened.
printingsPrintingsarrayOptional. Keep only these printings, for example Normal, Foil, Holofoil or Reverse Holofoil. Every printing has its own price and sales history.
languagesLanguagesarrayOptional. Keep only these languages, for example English or Japanese. Leave empty for all languages.
minMarketPriceMinimum market price (USD)numberKeep only printings whose Near Mint market price (Unopened for sealed products) is at least this amount. 0 disables the filter.
maxMarketPriceMaximum market price (USD)numberKeep only printings whose market price is at most this amount. 0 disables the filter.
minSold30dMinimum units sold in 30 daysintegerKeep only printings that sold at least this many units in the last 30 days at the main condition. Use it to drop cards nobody buys. 0 disables the filter.
minSold90dMinimum units sold in 90 daysintegerKeep only printings that sold at least this many units in the last 90 days at the main condition. 0 disables the filter.
minPriceChange30dPctMinimum 30-day price change (%)numberOptional. Keep only printings whose market price rose at least this many percent over the last 30 days. Enter 20 to find risers. Negative values are allowed. Printings without a 30-day comparison are skipped.
maxPriceChange30dPctMaximum 30-day price change (%)numberOptional. Keep only printings whose market price changed at most this many percent over the last 30 days. Enter -15 to find fallers.
sortByOrder of products to scanstringOrder in which TCGplayer returns products before they are scanned. Relevance follows TCGplayer popularity. Highest price first is useful with a minimum price.
maxProductsToScanMaximum products to scanintegerHow many products to read the sales history of, per run across all search terms. One product gives one row per printing and language, so you often get more rows than products. TCGplayer search returns at most 9950 products per search.
maxItemsMaximum resultsintegerStop after this many rows in total. Each row is one billed result.
proxyConfigurationProxy configurationobjectOptional proxy. Leave disabled: the TCGplayer endpoints used here are public and need none.

Call it from your code

Run the Actor and get the results in one request. Replace YOUR_APIFY_TOKEN with the token from your Apify account settings.

curl -X POST "https://api.apify.com/v2/acts/datagrit~tcgplayer-price-trend-tracker/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries":["charizard"],"productLine":"pokemon","maxProductsToScan":30,"maxItems":50}'
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datagrit/tcgplayer-price-trend-tracker').call({
  "searchQueries": [
    "charizard"
  ],
  "productLine": "pokemon",
  "maxProductsToScan": 30,
  "maxItems": 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);

Install with npm i apify-client.

from apify_client import ApifyClient
import os

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("datagrit/tcgplayer-price-trend-tracker").call(run_input={
  "searchQueries": [
    "charizard"
  ],
  "productLine": "pokemon",
  "maxProductsToScan": 30,
  "maxItems": 50
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), items[0] if items else None)

Install with pip install apify-client.

Frequently asked questions

How fresh is the data?

Every run reads TCGplayer live. The market price is the value of the latest 3-day window of sales, so it can differ by a few cents from the price shown on the product page right now (for example 14.57 against 14.63 for the same foil card). Use it for trends and comparisons between runs, not as a live quote.

How many products and rows can one run read, and how long does it take?

One run reads up to 9950 products per search term, set by **Maximum products to scan**. Each product needs one extra request for its sales history, and the Actor keeps a short pause between batches, so expect roughly 6 seconds per 10 products and about a minute for the default 100 products. Rows are limited by **Maximum results**.

Why do I get more rows than products?

Each printing and language is its own row; a card with Normal and Foil copies in two languages gives up to four rows.

Why are the price change fields empty for some rows?

The printing had no sales in the window, or it is newer than 84 days for the 90-day change.

Can I schedule runs?

Yes, use Apify schedules or call the Actor from your own workflow and compare runs over time.

Something looks wrong.

Open an issue with the input you used; changes at the source are fixed quickly.

Try TCGplayer Price Trends & Sales Velocity Tracker on Apify

Related Actors

Company data

French Company Finder - Sirene Financials

French company lead lists from Sirene screened by net result and revenue, with net margin, size, matching establishment and optional directors.

from $5.60 / 1,000 results
Jobs & salaries

Career Site Jobs Aggregator - ATS Salary Data

Open jobs from Greenhouse, Lever, Ashby, Workday, Workable, SmartRecruiters, Recruitee and Personio in one schema with normalized salaries.

from $2.80 / 1,000 results