← Blog

Whatnot

Whatnot Price Tracker: Track Sold Prices and Auctions

Build a Whatnot price tracker with scheduled scrapes: capture asking prices, current bids and last-sale prices, store snapshots and get alerts on changes.

Epic Scrapers

If you buy or sell on Whatnot, you want to know what a card, sneaker or sealed box is going for this week, not three months ago. Whatnot has no price history page and no public API, so the practical approach is to snapshot search results on a schedule and compare them yourself.

This tutorial sets up that tracker with the Whatnot Search Scraper: a fixed list of queries, a daily schedule and a short Python script that saves each snapshot and flags price moves. If you also want seller or category data in the same runs, the all-in-one Whatnot Scraper accepts the same search input in search mode.

Which prices you can capture

A Whatnot search returns several record types. Two of them matter for pricing:

Record type Price fields What it tells you
listing price, currentBid, currentBidCount, transactionType, quantity Live offers: buy-it-now asking prices and auction bids right now
product listingPrice, lastSalePrice, numListings Catalog view of one product: current lowest listing, most recent sale, and supply

lastSalePrice on product records is the field to use for “Whatnot sold prices”. It’s the most recent sale Whatnot reports for that catalog product, not a full transaction history, which is why snapshots matter. Run daily and the lastSalePrice values build your own sold-price series. The rest of this guide is about making that happen.

Prices come as { "amount": ..., "currency": ... }. In the README samples the amounts look like minor units (499 USD = $4.99), so check one record against the live site on your first run and divide by 100 if that holds.

Step 1: Choose your queries

Pick specific search terms. “pokemon” returns noise, while “pokemon 151 booster bundle” returns comparable items. Keep auctions and buy-it-now listings in separate series, since auction prices mid-show behave differently.

{
  "searchQueries": [
    "pokemon 151 booster bundle",
    "one piece op-07 booster box",
    "jordan 4 military black"
  ],
  "vertical": "PRODUCT",
  "maxResultsPerQuery": 100
}

If you’ve built a filtered or sorted search on whatnot.com, paste the URL into searchUrls instead. The URL’s own vertical and sort settings are kept.

Run it once from the Apify Console and look at the output to confirm the results match what you expect.

Step 2: Save it as a task and schedule it

  1. In Apify Console, click Save as task on the input above.
  2. Open Schedules, create a schedule and attach the task.
  3. Daily is enough for most sealed products and sneakers. Run every few hours for hot releases.

Each run writes a fresh dataset, and every record carries searchQuery and scrapedAt, so the timestamps line up across runs.

Step 3: Store snapshots and compare

The script below runs the actor, appends every priced record to a CSV, and prints queries where the median asking price moved more than 10% since the previous snapshot. Run it from cron, GitHub Actions or anywhere that has Python.

import csv, os, statistics
from datetime import datetime, timezone
from pathlib import Path
from apify_client import ApifyClient

QUERIES = ["pokemon 151 booster bundle", "one piece op-07 booster box"]
HISTORY = Path("whatnot_prices.csv")
THRESHOLD = 0.10  # alert on a 10% move

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("epicscrapers/whatnot-search-scraper").call(run_input={
    "searchQueries": QUERIES,
    "vertical": "PRODUCT",
    "maxResultsPerQuery": 100,
})

def amount(p):
    return p.get("amount") if isinstance(p, dict) else p

rows = []
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["type"] == "listing" and item.get("transactionType") == "BUY_IT_NOW":
        rows.append([item["scrapedAt"], item["searchQuery"], "ask",
                     amount(item.get("price")), (item.get("price") or {}).get("currency"),
                     item.get("title")])
    elif item["type"] == "listing" and item.get("currentBid"):
        rows.append([item["scrapedAt"], item["searchQuery"], "bid",
                     amount(item["currentBid"]), None, item.get("title")])
    elif item["type"] == "product" and item.get("lastSalePrice"):
        rows.append([item["scrapedAt"], item["searchQuery"], "last_sale",
                     amount(item["lastSalePrice"]), item["lastSalePrice"].get("currency"),
                     item.get("name")])

# Load the previous snapshot's medians before appending
previous = {}
if HISTORY.exists():
    with HISTORY.open() as f:
        hist = [r for r in csv.reader(f) if r[2] == "ask" and r[3]]
    if hist:
        last_run = max(r[0][:13] for r in hist)  # group by hour
        for q in QUERIES:
            vals = [float(r[3]) for r in hist if r[1] == q and r[0][:13] == last_run]
            if vals:
                previous[q] = statistics.median(vals)

with HISTORY.open("a", newline="") as f:
    csv.writer(f).writerows(rows)

for q in QUERIES:
    now = [float(r[3]) for r in rows if r[1] == q and r[2] == "ask" and r[3]]
    if now and q in previous:
        change = (statistics.median(now) - previous[q]) / previous[q]
        if abs(change) >= THRESHOLD:
            print(f"{q}: median ask moved {change:+.0%}")

print(f"Saved {len(rows)} price points at {datetime.now(timezone.utc).isoformat()}")

Notes on the script:

  • It tracks three series separately (ask, bid, last_sale), so bids and sales don’t get mixed in with asking prices.
  • The median is used rather than the minimum. One mispriced listing won’t trigger an alert, but a real shift in the market will.
  • For a no-code version, connect the scheduled task to Google Sheets through Apify integrations and calculate the change in a sheet.

Step 4: Turn changes into alerts

Useful rules to start with:

  • Median ask drops more than 10%: possible buying window, or a reprint or restock is landing.
  • lastSalePrice rises across three consecutive runs: demand is building.
  • numListings on a product jumps: supply is increasing and prices usually soften soon after.
  • A buy-it-now listing appears below your target price: buy it now. Filter by title keywords to avoid lots and bundles.

Send the printed alerts to Slack, email or Telegram from the same script, or use an Apify webhook that fires when the scheduled run succeeds.

Tracking auctions during live shows

Auction listings in search results show currentBid and currentBidCount at the moment of the scrape, with isLive telling you whether the item is in a live show. To watch a niche’s live auctions, run a LIVESTREAM search in the Whatnot Scraper to see which shows are running and how many activeViewers each has. The Whatnot scraper guide covers livestream and category deep-dive inputs.

Who uses this

  • Card breakers and resellers price sealed product before buying a case.
  • Sneaker sellers set buy-it-now prices from the market median instead of guessing.
  • Collectors wait for a target price without refreshing the app all day.

The same snapshot approach works on other platforms. See Vinted price tracking and eBay sold listings to compare prices across platforms.

FAQ

Is there a Whatnot price history tool?

Whatnot doesn’t publish price history. A scheduled scraper is the simplest way to build one, and your history starts from the first snapshot.

Can I see Whatnot sold prices?

You can see the most recent sale per catalog product through lastSalePrice. Collect it daily and you’ll have a sold-price trend.

How often should I run the tracker?

Daily for most products. For new releases or hyped items, every few hours. Costs scale with results, so check the actor’s Pricing tab and keep maxResultsPerQuery tight.

Do I need a Whatnot login?

No. Public search results are available without an account.

Start tracking

Save your queries as a task, schedule it daily and let the snapshots build up. Open the Whatnot Search Scraper to run your first snapshot.