# Stadium Goods Product Scraper & Sneaker Price Tracker (`superslowsloth/stadiumgoods-products`) Actor

Stadium Goods scraper: sneakers, streetwear and accessories newest first, filtered by brand (NIKE, JORDAN, NEW BALANCE...) and publish time. One row per product with USD price range, per-size stock and SKU, type, tags, photo and timestamps. For sneaker resale price and new-drop watch.

- **URL**: https://apify.com/superslowsloth/stadiumgoods-products.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 product scrapeds

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

## Stadium Goods Product Scraper & Sneaker Price Tracker

A **Stadium Goods scraper** and **sneaker resale price tracker** for
[www.stadiumgoods.com](https://www.stadiumgoods.com). It reads the catalogue
newest-published first and returns one flat row per product: title, brand
(`NIKE`, `JORDAN`, `NEW BALANCE`, `SUPREME`, `CHROME HEARTS`), the price range
in **USD**, whether it can be bought, and every size with its own SKU, price and
stock flag. Filter by brand and by **publish time** (`24 hours`, `3 days`) and
schedule it to get a **new-drop alert**, or run it daily on a brand and compare
rows by `handle` to watch how the **resale price** of each pair moves.

No account, no API key, no login, no browser. One request returns 250 products.
Stadium Goods published about 360 products in the 24 hours to 2026-10-20, so a
24-hour window is two requests.

### Input

| Field | Notes |
|---|---|
| `brands` | Return only products by these brands, spelled as Stadium Goods spells them in `vendor`: `NIKE`, `JORDAN` (not Air Jordan), `ADIDAS`, `NEW BALANCE`, `SUPREME`, `CHROME HEARTS`, `THE NORTH FACE`. Case and extra spaces are ignored; otherwise the match is exact. Leave empty for every brand. |
| `publishedAfter` | Return only products that went live after this moment: a span back from now (`24 hours`, `3 days`, `90 minutes`, `1 week`), a date (`2026-10-16`, midnight UTC) or a date-time (`2026-10-16T12:00:00Z`, no offset means UTC). This is the product's **publish time** (`published_at`), not the record's creation time (`created_at`). On the whole catalogue the run stops at the first older product, since the feed is newest-published first. Leave empty for no cut-off. |
| `collections` | Stadium Goods collections to read instead of the whole catalogue, one per line: the name from the address bar (`new-balance`, `kith`, `asics`, `sale`, `new-arrivals`) or the link (`https://www.stadiumgoods.com/collections/new-balance`). A collection is in the shop's own order, **not** newest first, so `publishedAfter` filters it but cannot stop early. A collection is also the only way past the newest 25,000 products (see below). Leave empty to read the whole catalogue, newest first. |
| `maxItems` | Products to return per collection, or for the whole catalogue (default 250, up to 25,000). 250 per page. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

Filtered products are read but not returned and not charged, and do not count
toward `maxItems`.

Example input, new Nike and Jordan products from the last day:

```json
{
  "brands": ["NIKE", "JORDAN"],
  "publishedAfter": "24 hours",
  "maxItems": 1000
}
```

Example input, a daily snapshot of one brand to compare prices over time:

```json
{
  "brands": ["NEW BALANCE"],
  "maxItems": 5000
}
```

### Output

Prices are numbers in US dollars; `currency` is `USD`. The shop's own
`/meta.json` says USD, but its feed is priced for the visitor's country (from a
Japanese address it returned yen), so every request carries `localization=US`
and the prices are dollars whatever address the run exits from. A field the shop
did not send is `null`, never `0` or `""`.

| Field | Notes |
|---|---|
| `query`, `position` | The shop URL (whole catalogue) or collection URL that first found the product, and its place in that list (1 is newest on the catalogue, 250 per page). |
| `store` | `www.stadiumgoods.com`. |
| `product_id`, `handle`, `url` | Shopify's product id (a string), the URL handle (it ends in Stadium Goods' item number) and the product link. Use `handle` or `product_id` to follow one pair between runs. |
| `title`, `vendor`, `product_type` | `Plaid Western Shirt "Green" P348 PFFG224`, `PURPLE BRAND`, `Apparel`. `vendor` is the brand. `product_type` is `Shoes`, `Apparel` or `Accessories`. |
| `price`, `price_max` | The lowest and highest current size price. Sizes of one product can differ (1,771 of 25,000 products did). |
| `original_price`, `original_price_max`, `on_sale`, `discount_percent` | Stadium Goods sends a `compare_at_price` equal to the price on every size that has a price (350,930 of 350,930, the shop's `sale` collection included), so `on_sale` is false, `original_price` equals `price` and `discount_percent` is null. The columns are kept because they would show a real reduction if the shop starts sending one. To watch a price fall, compare `price` between runs. |
| `available`, `variant_count`, `available_variant_count` | Whether any size can be bought now, how many sizes there are, and how many can be bought. Only 14% of sizes were buyable on 2026-10-20 (55,658 of 391,842). |
| `option_names` | `["Size"]` on every product. |
| `variants` | One entry per size: `variant_id`, `title` (`XS`, `1C`, `2.5W`), `sku` (`124535|IC990PK6|1C`: item number, style code, size), `price`, `compare_at_price`, `available`, `options`. |
| `published_at` | When the product went live, ISO 8601 with the shop's offset. What the feed is ordered by and what `publishedAfter` compares against. |
| `created_at`, `updated_at` | When the record was created (months older than `published_at` for a relisted pair) and last changed (rewritten in bulk, so not a price-change time). |
| `tags` | The shop's own tags, as sent: one or two (`Mens`, `Womens`, `Kids`, `Unisex`, `Farfetch Photo Feed`). |
| `image_url`, `image_count` | The first photo on cdn.shopify.com, as sent (null when there is none, 11% of products), and how many photos there are. |

Example row (real values, 2026-10-20; `tags` and `variants` shortened here to
one entry each, the product has 19 sizes):

```json
{
  "query": "https://www.stadiumgoods.com",
  "position": 3,
  "store": "www.stadiumgoods.com",
  "product_id": "8208103899332",
  "title": "990v6 TD \"Pink Haze\" IC990PK6",
  "handle": "990v6-td-pink-haze-124535",
  "url": "https://www.stadiumgoods.com/products/990v6-td-pink-haze-124535",
  "vendor": "NEW BALANCE",
  "product_type": "Shoes",
  "tags": [
    "Kids"
  ],
  "created_at": "2025-03-13T04:39:40-04:00",
  "published_at": "2026-10-19T13:49:01-04:00",
  "updated_at": "2026-10-19T16:26:06-04:00",
  "image_url": "https://cdn.shopify.com/s/files/1/0659/1168/5316/files/giaxqk3s4xqqwb6lok5y0p6lwb58.png?v=1741855185",
  "image_count": 1,
  "currency": "USD",
  "price": 95.0,
  "price_max": 95.0,
  "original_price": 95.0,
  "original_price_max": 95.0,
  "on_sale": false,
  "discount_percent": null,
  "available": true,
  "variant_count": 19,
  "available_variant_count": 2,
  "option_names": [
    "Size"
  ],
  "variants": [
    {
      "variant_id": "44688068772036",
      "title": "1C",
      "sku": "124535|IC990PK6|1C",
      "price": 95.0,
      "compare_at_price": 95.0,
      "available": false,
      "options": [
        "1C"
      ]
    }
  ]
}
```

#### Honest nulls and what is not here

- **No markdowns.** See `on_sale` above: `discount_percent` is null, never 0.
- **No condition grade, no ask/bid spread.** The catalogue feed carries
  neither; this is the listed price, not market data.
- **Placeholder records are returned as sent.** 2,310 of the newest 25,000
  products (9.2%) are priced `0.00` on every size, none can be bought and 580
  have no photo: newly created records with no stock yet. Their `price` is 0.0
  and `available` is false; filter on `available` or `price > 0` if you only
  want live pairs.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.007** per product row written (`product-scraped`), i.e. $7.00 per
  1,000 products. A row that is not written is not charged: products filtered
  by `brands` or `publishedAfter`, and repeats another collection already
  returned, are free.

### How it fetches

It reads `/products.json`, the public catalogue feed every Shopify shop serves
(and `/collections/<name>/products.json` for a collection). Measured
2026-10-20: HTTP 200 JSON, about 1.7 MB per 250 products, no key or login
needed; the actor sends one cookie, `localization=US`, to fix the currency. A
refusal (403, 429, 430, 5xx), a 200 that is not the feed, or a dropped
connection is treated as the address being blocked, and the actor rotates to a
fresh one and retries.

Things worth knowing, all measured on 2026-10-20:

- **Newest-published first.** `published_at` never increased down all 100
  pages (25,000 distinct products, 2026-10-19 16:19 back to 2026-07-15 21:43).
  `created_at` is not in order, which is why the cut-off is on `published_at`.
- **At most 25,000 products per list.** Shopify refuses any page beyond
  `page * 250 = 25,000` with HTTP 400. Stadium Goods lists more than that
  (`/meta.json` says 25,001 and the `kids` collection alone reports 15,787), so
  the whole catalogue always ends at the window, about three months back. A
  run that reads to it without having returned `maxItems` rows (a brand filter,
  say) logs the list as capped. Older products are reachable only through
  collections (`new-balance` returned 2,750 New Balance rows in its first 11 pages,
  with more behind them, against 759 in the newest 25,000).
- **Filters on the feed are ignored.** `?vendor=`, `?product_type=`, `?q=`,
  `?order=` return the same page as sending nothing, so `brands` are matched on
  the rows. A rare brand on the whole catalogue therefore reads up to 100 pages
  (about 170 MB); a short `publishedAfter` window stops long before that.
- **Brand collections exist for some brands only.** `new-balance`, `kith`,
  `asics` do; `nike`, `jordan`, `adidas`, `supreme` are not collections (HTTP
  404 on `/collections/<name>.json`), so use `brands` for those.
- **An unknown collection looks empty.** The feed answers an unknown name with
  an empty list; the actor asks the collection's own record, and a name that
  does not exist fails instead of being reported as empty.

If Stadium Goods changes its feed, the run fails with a message instead of
returning empty rows.

# Actor input Schema

## `brands` (type: `array`):

Return only products by these brands, one per line, spelled as Stadium Goods spells them in the vendor field: NIKE, JORDAN (not Air Jordan), ADIDAS, NEW BALANCE, SUPREME, CHROME HEARTS, THE NORTH FACE, BRUNELLO CUCINELLI. Matching ignores case and extra spaces but is otherwise exact. Other products are read but not returned and not charged. The shop has no filter on its feed, so a brand is found by reading pages, up to 100 of them for a rare brand on the whole catalogue. Leave empty for every brand.

## `publishedAfter` (type: `string`):

Return only products that went live on Stadium Goods after this moment: a span back from now (24 hours, 3 days, 90 minutes, 1 week), a date (2026-10-16, midnight UTC) or a date-time (2026-10-16T12:00:00Z). This is the product's publish time (published_at), not the record's creation time (created_at), which can be months older. On the whole catalogue the run stops at the first older product, because the feed is newest-published first, so a short window is fast and cheap (about 360 products a day). Leave empty for no cut-off.

## `collections` (type: `array`):

Stadium Goods collections to read instead of the whole catalogue, one per line: the name from the shop's address bar (new-balance, kith, asics, sale, new-arrivals) or the whole link (https://www.stadiumgoods.com/collections/new-balance). A collection is in the shop's own order, not newest first, so Published after filters it without stopping early. Unlike the whole catalogue, which stops at the newest 25,000 products, a collection reaches older ones. Many brand names (nike, jordan, adidas) are not collections; use Brands for those. Leave empty to read the whole catalogue, newest first.

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

Return at most this many products for the catalogue or for each collection. The feed holds 250 per page. Up to 25,000 are accepted, which is the most Shopify serves for any one list; the whole catalogue is longer than that, so a full read is capped at its newest 25,000.

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

Use Apify's automatic datacenter proxy (the default). A refused request is retried from a fresh address.

## Actor input object example

```json
{
  "brands": [],
  "publishedAfter": "24 hours",
  "collections": [],
  "maxItems": 250,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "brands": [],
    "publishedAfter": "24 hours",
    "collections": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/stadiumgoods-products").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 = {
    "brands": [],
    "publishedAfter": "24 hours",
    "collections": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/stadiumgoods-products").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 '{
  "brands": [],
  "publishedAfter": "24 hours",
  "collections": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/stadiumgoods-products --silent --output-dataset

```

## MCP server setup

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

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/IxyAIovRhRaIpQasw/builds/EXgnlwgJQHbblhFke/openapi.json
