# Spyhe Whatnot Scraper — Listings, Sellers, Reviews & Live Chat (`spyhe/whatnot-scraper`) Actor

Scrape public Whatnot listings, seller shops, profiles, reviews, shows and category rankings. Capture live chat and auction bid observations, track listing changes, and export JSON/CSV with clear coverage limits.

- **URL**: https://apify.com/spyhe/whatnot-scraper.md
- **Developed by:** [Corey Brain](https://apify.com/spyhe) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Whatnot Scraper — Listings, Sellers, Reviews & Live Chat

Collect public Whatnot listings, seller profiles, reviews, shows, category feeds and seller rankings. Observe active auction bids and live chat within a chosen time window. Use results for product research, seller comparisons and listing change tracking.

No Whatnot login, cookies or API key is required. Results include source references and coverage information, so you can distinguish a complete requested scope from a capped or interrupted collection.

### Quick start

For a small product search, use:

```json
{
  "modes": ["search"],
  "keywords": ["pokemon cards"],
  "searchVertical": "PRODUCT",
  "maxPages": 1,
  "maxItems": 24,
  "maxRequests": 10,
  "maxRunSeconds": 60
}
```

The default input collects one category's public activity totals. Start with a small limit, inspect the Dataset and SUMMARY, then increase the scope. Several modules can be combined in one run.

### Available data

| Module | Targets | Results |
|---|---|---|
| `search` | `keywords` or `searchUrls` | Listings, shows, sellers or categories, depending on `searchVertical` |
| `shop` | `sellerUsernames`, optional `shopQuery` | Seller shop listings |
| `listings` | `listingUrls` | Direct public listing details |
| `seller` | `sellerUsernames` | Followers, following, lifetime sold count, ratings and available profile details |
| `reviews` | `sellerUsernames` | Written reviews, dates, rating dimensions and seller responses; reviewer identities are excluded |
| `shows` | `sellerUsernames` | Accessible shows, status, scheduled time, viewers, watchlists, images and categories |
| `category` | `categorySlugs` | Exact category/tag activity totals |
| `categories` | No target required | Public category catalog IDs, labels and types |
| `categoryShows` | `categorySlugs` | Public category show feeds |
| `categoryRankings` | `categorySlugs`, `rankingInterval` | Source seller leaderboard for the category and selected period |
| `auctionSnapshot` | `liveUrls` | At most one observed active auction per show: bid, currency, bid count and end time |
| `chat` | `liveUrls` | Public live comments, message IDs, available public author details and role flags |

Listing fields include IDs, title, description, price/currency, quantity, availability, sale format, images, seller and category. Source-provided extras include catalog price ranges, creation/update times, offer availability and current bids. Optional fields stay null when unavailable.

### Search and filters

`searchVertical` accepts `PRODUCT`, `LIVESTREAM`, `USER`, `CATEGORY` or `UNIVERSAL`. UNIVERSAL combines four separate bounded searches; its order does not reproduce the website's blended Top results.

`searchUrls` accepts public Whatnot `/search` links with `query`, `searchVertical` and supported native JSON `sort` values. Unsupported filtering parameters are rejected; tracking parameters are removed.

`listingOrder` supports `bestMatch`, `priceAsc`, `priceDesc` and `newest`. Product filters include `saleFormats`, `categoryIds`, `liveOnly`, `minPrice`, `maxPrice` and `priceCurrency`. Filters apply locally after fetching pages, so a page cap can leave matches undiscovered. There is no currency conversion. Product filters apply only to product rows in UNIVERSAL searches.

### Reviews, rankings and live data

Reviews default to the last 30 days. `reviewDays=0` requests the accessible connection without a date cutoff, still bounded by limits. Written reviews do not necessarily equal the profile's rating count, which can include star-only ratings. Complete review history is not guaranteed.

Rankings use Whatnot's public seller leaderboard and its returned order. `rankingInterval` is `CURRENT_DAY`, `CURRENT_WEEK` or `LIVE`. Lifetime sold counts beside ranks are not sales during that period. A live leaderboard may be empty.

For auctions or chat, supply current public live-show URLs: `https://www.whatnot.com/live/<show-uuid>`. Up to three distinct shows are supported. `auctionWaitSeconds` is 5–30 seconds. Zero auction rows mean no eligible event was observed in that window. Observed bids and asking prices are not finalized sale prices or paid orders.

`chatDurationSeconds` is 5–600 seconds. `includeRecentMessages` controls the initial recent batch. Reconnect recovery batches are marked and deduplicated within the run. Chat is best effort: no complete historical transcript, guaranteed lossless recovery or deduplication across independent runs. Increase both the platform timeout and `maxRunSeconds` for longer captures; the platform deadline takes precedence.

### Listing change monitoring

Set `monitorChanges=true` for PRODUCT search, shop or direct listings. The first scan emits `listingChange` initial snapshots. Later scans emit newly observed listings and changes to the established business fields. Unchanged observations produce no rows. Missing items in partial scans are never labeled sold or removed. Catalog, offer and bid enrichment fields are snapshots rather than additional change triggers.

Keep the same `monitorNamespace` for a baseline; choose another for an independent baseline. State is stored in your account and bounded to 10,000 listing IDs and 8 MiB per scope. Concurrent runs of the same scope report `MONITOR_SCOPE_BUSY`; interrupted locks expire within 15 minutes.

For an unresolved write from an older run, select its Dataset in `recoveryDatasetId` to permit read-only reconciliation, or resurrect the original run. Without access, recovery stops with `MONITOR_RECOVERY_DATASET_READ_REQUIRED` rather than replaying uncertain results.

### Output and coverage

Dataset rows contain `recordType`, `recordKey`, `target`, `data`, `completeness`, `coverage`, `provenance`, `retrievedAt` and `schemaVersion`. `data` holds the business fields. Record keys deduplicate within a run. Receipt times are distinguished from source-provided dates; missing source values remain null.

The Output tab links to:

- **Dataset:** primary JSON records with standard Apify exports.
- **SUMMARY:** actual saved count, target outcomes, pagination, limits and errors.
- **EXPORTS:** CSV files grouped by record type, with common business fields flattened. These copies are not charged again. Oversized or timed-out exports report an error while retaining the Dataset.

`fullCoverage=true` means the requested accessible scope passed its checks, not all Whatnot data or all history. Page caps, source restrictions, dynamic pagination, item limits and spending limits can produce partial results. Consult SUMMARY for the final outcome. A valid empty source connection may succeed with zero rows.

### Sample output

Shortened category result observed on 2026-10-13. Counts change over time; complete records also include keys, coverage and provenance.

```json
{
  "recordType": "categoryInsight",
  "target": "fragrances",
  "data": {
    "category_id": "TGl2ZXN0cmVhbVRhZ05vZGU6NTQz",
    "slug": "fragrances",
    "name": "Perfume & Cologne",
    "viewer_count": 773,
    "livestream_count": 19,
    "metric_scope": "category_total",
    "observed_at": "2026-10-13T10:18:34.763952+00:00"
  },
  "completeness": "complete",
  "retrievedAt": "2026-10-13T10:18:34.763952+00:00"
}
```

### Pricing

The configured price is **$1.50 per 1,000 saved result rows** ($0.0015 per row), plus the Actor Start event at **$0.00005 per start up to 1 GB of allocated memory**. The Store pricing panel is authoritative for current prices and any discounts.

One saved row is one result, including a listing change, ranking entry or live comment. Errors and coverage reports in SUMMARY, and CSV copies, do not create additional result charges. Empty or unchanged scans can still incur the start event. Use the platform's maximum cost per run and `maxItems` to control spending. Collection stops at the result spending limit.

### Limits and troubleshooting

Limits are 100 targets of each kind, 100 pages per connection, 10,000 saved items, 1,000 source requests/connection attempts, and 600 processing seconds. The default platform timeout is 120 seconds. There is no unlimited mode.

- **Partial output:** inspect SUMMARY and increase only the relevant page, item, request or time limit.
- **No auction/chat output:** check that the show is live and public and that the observation window has enough activity.
- **Restricted source:** HTTP 401, 403 and 429 stop that access path. The Actor does not bypass challenges or replay logged-in credentials.
- **Temporary failures:** network errors and selected server errors receive at most two bounded retries within the request budget.
- **Unknown fields:** null means the public source did not provide a verified value.

This Python Actor uses the Apify SDK, public Whatnot pages and read-only public query/live interfaces. Upstream interfaces can change. It does not retrieve private orders, payment details, shipping credentials or buyer identities from reviews. It is independent and not affiliated with Whatnot.

For help, open an issue in this Actor's **Issues** tab with the run ID, input and expected outcome. Do not include credentials or private account data.

# Actor input Schema

## `modes` (type: `array`):

Choose public data modules. Marketplace modules are bounded and report partial pagination explicitly.

## `categorySlugs` (type: `array`):

Exact public /tag/ slug, not a display label or aggregate parent.

## `sellerUsernames` (type: `array`):

Required for seller, shows and reviews. Public IDs are resolved live; no fixed 14-seller restriction.

## `saveEvidence` (type: `boolean`):

Save necessary metadata and GraphQL responses to the run key-value store. No buyer identities, cookies, token headers or HTML scripts.

## `maxPages` (type: `integer`):

Hard bounded limit; a page cap is partial coverage. Review date boundaries are partial unless the source connection is exhausted.

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

Hard bounded limit; a page cap is partial coverage. Review date boundaries are partial unless the source connection is exhausted.

## `maxRequests` (type: `integer`):

Combined HTTP requests and WebSocket connection attempts. Retries and anonymous session requests consume this budget.

## `reviewDays` (type: `integer`):

Hard bounded limit; a page cap is partial coverage. Review date boundaries are partial unless the source connection is exhausted.

## `timeoutSeconds` (type: `integer`):

Hard bounded limit; a page cap is partial coverage. Review date boundaries are partial unless the source connection is exhausted.

## `keywords` (type: `array`):

Bounded to 100 values. Use the relevant marketplace mode.

## `listingUrls` (type: `array`):

Bounded to 100 values. Use the relevant marketplace mode.

## `categoryIds` (type: `array`):

Bounded to 100 values. Use the relevant marketplace mode.

## `shopQuery` (type: `string`):

Optional keyword for shop mode.

## `listingOrder` (type: `string`):

Ordering sent to the public search/shop source.

## `saleFormats` (type: `array`):

Local filtering of fetched records; empty accepts all.

## `minPrice` (type: `number`):

Optional local filter in priceCurrency. No currency conversion.

## `maxPrice` (type: `number`):

Optional local filter in priceCurrency. No currency conversion.

## `priceCurrency` (type: `string`):

Local price filters apply only to this currency; no exchange conversion.

## `liveOnly` (type: `boolean`):

Local filter; unknown live state is not treated as live.

## `searchVertical` (type: `string`):

UNIVERSAL merges four bounded searches. Product filters affect PRODUCT rows only; each vertical has its own coverage in SUMMARY.

## `monitorChanges` (type: `boolean`):

Persistent state across runs; same scope is exclusive. Unchanged scans still consume platform resources.

## `monitorNamespace` (type: `string`):

Use a different namespace for an independent baseline. Lowercase letters, digits and hyphens, up to 48 characters.

## `maxRunSeconds` (type: `integer`):

Bounds source processing and output; platform timeout can be lower.

## `maxRetries` (type: `integer`):

Only bounded network failures and selected 5xx; all attempts count toward maxRequests. No 401/403/429 retries.

## `recoveryDatasetId` (type: `string`):

Only needed when unresolved events belong to an older run. Select that run's primary Dataset to grant read-only reconciliation; normal monitoring needs no selection.

## `searchUrls` (type: `array`):

Public /search URLs with query, searchVertical and native JSON sort. Other filtering parameters are rejected rather than silently ignored.

## `liveUrls` (type: `array`):

Required for auctionSnapshot or chat; at most three distinct shows. Only fixed Whatnot HTTPS live URLs are accepted.

## `chatDurationSeconds` (type: `integer`):

Finite best-effort window, subject to maxRunSeconds and the platform timeout. Messages save as they arrive.

## `includeRecentMessages` (type: `boolean`):

Keep the recent batch on join. After reconnect the recovery batch is retained and marked separately; this is not full history.

## `auctionWaitSeconds` (type: `integer`):

Wait for a public active-auction observation. Zero rows mean none was observed during this window, not proof no auction exists.

## `rankingInterval` (type: `string`):

Whatnot source leaderboard for the exact tag and period. Rank follows the returned connection order, not local follower or sold-count sorting.

## Actor input object example

```json
{
  "modes": [
    "category"
  ],
  "categorySlugs": [
    "fragrances"
  ],
  "sellerUsernames": [],
  "saveEvidence": false,
  "maxPages": 3,
  "maxItems": 1000,
  "maxRequests": 100,
  "reviewDays": 30,
  "timeoutSeconds": 30,
  "keywords": [],
  "listingUrls": [],
  "categoryIds": [],
  "shopQuery": "",
  "listingOrder": "bestMatch",
  "saleFormats": [],
  "priceCurrency": "USD",
  "liveOnly": false,
  "searchVertical": "PRODUCT",
  "monitorChanges": false,
  "monitorNamespace": "default",
  "maxRunSeconds": 300,
  "maxRetries": 2,
  "searchUrls": [],
  "liveUrls": [],
  "chatDurationSeconds": 30,
  "includeRecentMessages": true,
  "auctionWaitSeconds": 10,
  "rankingInterval": "CURRENT_DAY"
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `exports` (type: `string`):

No description

# 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 = {
    "modes": [
        "category"
    ],
    "categorySlugs": [
        "fragrances"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("spyhe/whatnot-scraper").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 = {
    "modes": ["category"],
    "categorySlugs": ["fragrances"],
}

# Run the Actor and wait for it to finish
run = client.actor("spyhe/whatnot-scraper").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 '{
  "modes": [
    "category"
  ],
  "categorySlugs": [
    "fragrances"
  ]
}' |
apify call spyhe/whatnot-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spyhe/whatnot-scraper"
        }
    }
}
```

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/qyP1cj41FgJsrBd6Q/builds/t7FY1j1aNCnUXjc09/openapi.json
