# TCGplayer Price Trends & Sales Velocity Tracker (`datagrit/tcgplayer-price-trend-tracker`) Actor

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

- **URL**: https://apify.com/datagrit/tcgplayer-price-trend-tracker.md
- **Developed by:** [datagrit](https://apify.com/datagrit) (community)
- **Categories:** E-commerce, Games
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does TCGplayer Price Trends & Sales Velocity Tracker do?

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?

- **Find risers and fallers.** Set a minimum 30-day price change to list cards that are climbing, or a maximum to list cards that are dropping, for any game TCGplayer carries.
- **Buy what sells.** Filter by units sold in 30 or 90 days, so you skip cards nobody buys and rank the rest by sales per day.
- **Judge sealed products.** Booster boxes and other sealed products carry the same metrics plus days of supply: active listings divided by average daily sales, a fast read on whether stock is tight.
- **Build a price feed.** Schedule the Actor and push rows into a sheet, a database or a repricing tool, with prices for Lightly Played, Moderately Played, Heavily Played and Damaged copies next to the Near Mint price.

### 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.

| productName | setName | variant | language | marketPrice | priceChange30dPct | sold30d | sold90d | soldPerDay | daysOfSupply |
|---|---|---|---|---|---|---|---|---|---|
| Charizard GX - 9/68 (#60 Charizard Stamped) | Battle Academy | Holofoil | English | 14.57 | 8.8 | 35 | 138 | 1.53 | 54.2 |
| Charizard - 3/70 (#39 Charizard Stamped) | Battle Academy | Normal | English | 7.37 | -0.3 | 73 | 132 | 1.47 | 46.3 |

```json
{
  "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 much does it cost to scrape TCGplayer?

You pay per result row. Set a maximum spend on the run and the Actor stops when it is reached. One product usually gives one or several rows, because every printing and language is its own row. Rows filtered out by your settings are never charged, and a run with no match returns one status row that is not charged.
The Actor uses plain HTTP requests and needs no proxy, so runs are light on platform resources.

### 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.

### Input

- **Search terms** – card or product names; each term is searched separately and a product found twice is returned once.
- **Game (product line)** – limits the search to one game such as Pokemon, Magic: The Gathering, Yu-Gi-Oh!, Disney Lorcana or One Piece, or searches all games.
- **Sets, Rarities, Printings, Languages** – optional lists that keep only matching rows. A set can be given by its name (`SV: Scarlet & Violet 151`) or by the last part of its TCGplayer URL (`sv-scarlet-and-violet-151`). A set that does not exist in the chosen game stops the run with an error and similar names, instead of returning another set's cards.
- **Cards or sealed products** – keep single cards only, sealed products only, or both. The choice is applied in the TCGplayer search, so the products you scan are already of that type.
- **Minimum and maximum market price** – price range in USD.
- **Minimum units sold in 30 days / 90 days** – drops cards that barely sell.
- **Minimum and maximum 30-day price change** – find risers or fallers.
- **Order of products to scan** – TCGplayer relevance, highest price first or lowest price first.
- **Maximum products to scan** – how many products are read per run; TCGplayer search exposes at most 9950 products per search.
- **Maximum results** – total row limit.
- **Proxy configuration** – optional and normally left off.

### 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.

### FAQ

**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.

### Related Actors

See other data Actors from the same publisher on the Store profile.

# Changelog

This Actor's version history is a separate document: https://apify.com/datagrit/tcgplayer-price-trend-tracker/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

Card 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.

## `productLine` (type: `string`):

Limit 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.

## `setNames` (type: `array`):

Optional. 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.

## `rarities` (type: `array`):

Optional. Keep only these rarities, for example Secret Rare or Special Illustration Rare. Names follow TCGplayer and differ by game.

## `productType` (type: `string`):

Single cards and sealed products (booster boxes, packs, decks) are both in the catalogue. Sealed products are the ones sold as Unopened.

## `printings` (type: `array`):

Optional. Keep only these printings, for example Normal, Foil, Holofoil or Reverse Holofoil. Every printing has its own price and sales history.

## `languages` (type: `array`):

Optional. Keep only these languages, for example English or Japanese. Leave empty for all languages.

## `minMarketPrice` (type: `number`):

Keep only printings whose Near Mint market price (Unopened for sealed products) is at least this amount. 0 disables the filter.

## `maxMarketPrice` (type: `number`):

Keep only printings whose market price is at most this amount. 0 disables the filter.

## `minSold30d` (type: `integer`):

Keep 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.

## `minSold90d` (type: `integer`):

Keep only printings that sold at least this many units in the last 90 days at the main condition. 0 disables the filter.

## `minPriceChange30dPct` (type: `number`):

Optional. 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.

## `maxPriceChange30dPct` (type: `number`):

Optional. Keep only printings whose market price changed at most this many percent over the last 30 days. Enter -15 to find fallers.

## `sortBy` (type: `string`):

Order in which TCGplayer returns products before they are scanned. Relevance follows TCGplayer popularity. Highest price first is useful with a minimum price.

## `maxProductsToScan` (type: `integer`):

How 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.

## `maxItems` (type: `integer`):

Stop after this many rows in total. Each row is one billed result.

## `proxyConfiguration` (type: `object`):

Optional proxy. Leave disabled: the TCGplayer endpoints used here are public and need none.

## Actor input object example

```json
{
  "searchQueries": [
    "charizard"
  ],
  "productLine": "pokemon",
  "setNames": [],
  "rarities": [],
  "productType": "all",
  "printings": [],
  "languages": [],
  "minMarketPrice": 0,
  "maxMarketPrice": 0,
  "minSold30d": 0,
  "minSold90d": 0,
  "sortBy": "relevance",
  "maxProductsToScan": 30,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All extracted records as a dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "charizard"
    ],
    "productLine": "pokemon",
    "maxProductsToScan": 30,
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagrit/tcgplayer-price-trend-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["charizard"],
    "productLine": "pokemon",
    "maxProductsToScan": 30,
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagrit/tcgplayer-price-trend-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "charizard"
  ],
  "productLine": "pokemon",
  "maxProductsToScan": 30,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagrit/tcgplayer-price-trend-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagrit/tcgplayer-price-trend-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7PXCeiNiFVCXgIsdP/builds/epqeT9jJefGcIaXJj/openapi.json
