# Sneaker Price Tracker: Sales, Price Drops & Restocks EU/UK/US (`apizilla/sneaker-price-tracker`) Actor

Track sneaker prices, sales and restocks in 13 shops (Kith, SNS, END., Footpatrol, Patta, Slam Jam...). Per-size stock, style-code match across shops, alerts for drops, sales and restocks.

- **URL**: https://apify.com/apizilla/sneaker-price-tracker.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (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 $1.80 / 1,000 sneakers

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

## Sneaker Price Tracker: Sales, Price Drops & Restocks (EU, UK, US)

Track sneaker prices, sales and restocks in **13 sneaker shops** at once: Kith, Sneakersnstuff (SNS), END., Footpatrol, Asphaltgold, Overkill, Patta, Slam Jam, Footdistrict, Concepts and more. Search by model ("Dunk", "Samba", "New Balance 990") or by exact style code ("DD1391-100"), get **per-size stock**, the **old price and discount**, the **same shoe matched across shops** with the cheapest shop, and, when you run it on a schedule, **alerts for new releases, price drops, sales, restocks and sold-out sizes**.

### What it does

- **One run, many shops.** Reads each shop's public product feed (no browser, fast and cheap).
- **Per-size stock.** Every size with in stock true/false, as the shop writes it (US 9, EU 42 2/3, UK 8...).
- **Sales.** Current price, old price (`compareAtPrice`), `discountPercent` and `onSale`.
- **Style codes.** The manufacturer code (Nike `DD1391-100`, adidas `IE3437`, New Balance `U9060BLK`, ASICS `1201A789-020`...) is found in the SKU, tags or description and normalized, so the same shoe has the same code in every shop.
- **Cross-shop comparison.** Offers grouped by style code: cheapest shop (in stock first), price range in EUR, sizes in stock per shop.
- **Change tracking (the part other scrapers do not have).** The Actor remembers every sneaker between runs and reports:

| Change | When |
| --- | --- |
| `new_release` | A new product appeared in the shop |
| `price_drop` / `price_increase` | The price changed (with old price, change and %) |
| `sale_started` / `sale_ended` | The shop started or stopped showing an old price |
| `restock` | One or more sizes came back in stock (the sizes are listed) |
| `sold_out` | The last size (of your sizes) sold out |
| `removed` | The product page is gone |

Turn on **Only changes** and schedule the Actor (for example every 30 minutes) to get a clean alert feed. Connect it to Slack, email, Telegram or a webhook with Apify integrations.

### Shops

| Shop ID | Shop | Country | Currency |
| --- | --- | --- | --- |
| `kith-eu` | Kith Europe (eu.kith.com) | France / EU | EUR |
| `kith-us` | Kith (kith.com) | United States | USD |
| `sneakersnstuff` | Sneakersnstuff / SNS | Sweden / EU | EUR |
| `footpatrol` | Footpatrol | United Kingdom | GBP |
| `endclothing` | END. Clothing | United Kingdom | GBP |
| `urbanindustry` | Urban Industry | United Kingdom | GBP |
| `overkill` | Overkill | Germany | EUR |
| `asphaltgold` | Asphaltgold | Germany | EUR |
| `footdistrict` | Footdistrict | Spain | EUR |
| `patta` | Patta | Netherlands | EUR |
| `slamjam` | Slam Jam | Italy | EUR |
| `oneblockdown` | One Block Down | Italy | EUR |
| `concepts` | Concepts (CNCPTS) | United States | USD |

You can also type a shop by its website, for example `"www.patta.nl"`.

### Examples

**Find Dunks and Sambas in four EU shops**

```json
{
    "shops": ["kith-eu", "sneakersnstuff", "asphaltgold", "footdistrict"],
    "keywords": ["Dunk", "adidas Samba"],
    "maxItems": 100
}
```

**Restock and price-drop alerts for my size, every 30 minutes**

```json
{
    "shops": ["kith-eu", "sneakersnstuff", "footpatrol", "endclothing", "patta", "slamjam"],
    "keywords": ["New Balance 990", "Jordan 4"],
    "sizes": ["US 9", "EU 42.5", "UK 8"],
    "trackerName": "my-grails",
    "onlyChanges": true
}
```

**Deals: 30% off or more, in stock**

```json
{
    "shops": ["asphaltgold", "overkill", "footdistrict", "sneakersnstuff", "urbanindustry"],
    "brands": ["Nike", "adidas", "New Balance", "ASICS"],
    "minDiscountPercent": 30,
    "onlyInStock": true,
    "maxItems": 500
}
```

**Watch exact shoes by style code across all shops**

```json
{
    "shops": ["kith-eu", "kith-us", "sneakersnstuff", "footpatrol", "endclothing", "overkill", "asphaltgold", "urbanindustry", "footdistrict", "patta", "concepts", "slamjam", "oneblockdown"],
    "styleCodes": ["1203A537-026", "U9060BLK", "IE3437"],
    "trackerName": "style-watch"
}
```

### Output

One item per sneaker offer (shop + product). Example (shortened):

```json
{
    "id": "footdistrict:9123456789",
    "changeType": "price_drop",
    "changes": [{ "type": "price_drop", "price": 91, "previousPrice": 130, "priceChange": -39, "priceChangePercent": -30 }],
    "shop": "footdistrict",
    "shopName": "Footdistrict",
    "shopCountry": "ES",
    "title": "Nike x Kobe Bryant Dunk Low Protro",
    "brand": "Nike",
    "styleCode": "IQ3919-001",
    "currency": "EUR",
    "price": 91,
    "compareAtPrice": 130,
    "discountPercent": 30,
    "onSale": true,
    "priceEur": 91,
    "available": true,
    "sizesAvailable": ["40", "41", "42", "42.5", "44"],
    "sizes": [{ "size": "40", "available": true, "price": 91, "variantId": "...", "sku": "IQ3919-001-40" }],
    "restockedSizes": [],
    "crossShop": { "shopCount": 2, "cheapestShop": "footdistrict", "cheapestPriceEur": 91, "isCheapest": true, "otherShops": [{ "shop": "kith-eu", "priceEur": 125 }] },
    "priceHistory": [{ "date": "2026-10-20", "price": 130 }, { "date": "2026-10-23", "price": 91 }],
    "lowestPriceSeen": 91,
    "url": "https://www.footdistrict.com/products/...",
    "image": "https://cdn.shopify.com/...",
    "publishedAt": "2026-10-14T10:00:00+02:00"
}
```

The dataset has three views: **Overview**, **Changes (alerts)** and **Cross-shop prices**. The key-value store has:

- `COMPARISON`: every style code with its offers per shop, cheapest shop, EUR price range and sizes per shop.
- `OUTPUT`: run summary: status per shop (ok, partial, blocked, failed), counts, changes and charged events.

### How change tracking works

- Runs with the same **Tracker name** compare with each other. The baseline is saved per shop in a named key-value store `sneaker-tracker-<trackerName>` in your account.
- The **first run saves the baseline** (`changeType: "baseline"`); changes show from the second run.
- Every matching sneaker on the pages read is remembered, even if it is not saved because of **Max sneakers**. Changed sneakers are always saved first.
- Tracked sneakers that were not on the pages read this run are **re-checked one by one** (up to *Re-check tracked sneakers*, default 40 per shop), so their price drops and restocks are still caught, and a product whose page is gone becomes `removed`.
- `new_release` is only reported for shops that were already tracked, and only for products that are really new (published after the last run, or the shop was read to the end last time).
- If you change the keywords, brands or style codes, the tracker starts a new baseline for new releases (use a new tracker name for a different search).
- A change that could not be saved (max cost reached) is reported in the next run.

### Sizes

Shops write sizes differently. A bare number from 30 up is EU; a smaller bare number uses the shop's own system (US for Kith, SNS, Patta, Slam Jam, One Block Down, Concepts; UK for Footpatrol, END., Urban Industry). Write the system in the **Sizes** input: `"US 9"`, `"EU 42"`, `"EU 42 2/3"`, `"UK 8"`. Sizes are not converted between systems (the conversion depends on the brand), so add each system you care about, for example `["US 9", "EU 42.5", "UK 8"]`.

### Prices and currencies

Prices are in each shop's own currency (`currency`). `priceEur` converts with the European Central Bank reference rates of the day (frankfurter.app), or a fixed table if that service is down. This is approximate: shipping, duties and VAT differences between countries are not included.

### Pricing

Pay per event. You only pay for results:

| Event | Price |
| --- | --- |
| Sneaker (one saved sneaker offer with prices and per-size stock) | $1.80 per 1,000 |
| Change alert (new release, price drop or rise, sale started or ended, restock, sold out, removed) | $0.50 per 1,000 |
| Actor start | $0.003 per run (at the default 512 MB; one start event per GB of memory, minimum one) |

Examples:

- 1,000 sneakers from 13 shops: about $1.80.
- A tracker of 500 sneakers run every hour with **Only changes** on: you pay only for the changed sneakers (each $0.0018 + $0.0005 per change) plus $0.003 per run. A quiet hour costs $0.003 (about $2.20 for a month of hourly runs).
- Sneakers that are read but not saved (filtered out, not changed in *Only changes* mode) cost nothing. Blocked shops cost nothing.

Set a maximum cost per run in the Apify Console; the Actor stops cleanly when it is reached and never saves a result it cannot charge.

### StockX and Zalando (coming soon)

- **StockX resale prices (lowest ask, last sale) by style code: coming soon.** StockX blocks plain requests even through residential proxies in our tests. The switch is in the input but does nothing and costs nothing yet.
- **Zalando prices by style code: coming soon.** Zalando pages load fine, but its search results do not show style codes, and matching by name picked the wrong model too often. The switch does nothing and costs nothing yet.

Marketplace prices are coming soon. They are not in the price list yet and are never charged.

### FAQ

**Is a style code always found?** Almost always for Nike, Jordan, adidas, New Balance, ASICS, Puma, Vans, Converse, Hoka and Salomon: 94% of those products in our test of all 13 shops (82-100% per shop). Smaller brands often have no standard code, and some shops do not show it for every product. Those sneakers have `styleCode: null` and are not in the cross-shop comparison.

**Why fewer results than Max sneakers?** Rare keywords may not be in the first pages. Each page has 250 products of the shop's footwear collection, newest first in most shops. Raise **Max pages per shop**.

**How often can I run it?** As often as you like. Every 15 to 60 minutes is common for restock alerts.

**Does it buy or reserve shoes?** No. It only reads public product data.

**Which proxy?** Apify Proxy with no group (the default). Shops use datacenter proxies and switch to RESIDENTIAL automatically only if they block (Footpatrol sometimes shows a Cloudflare check).

**Can you add a shop?** Most sneaker shops on Shopify can be added quickly. Open an issue with the website.

### Limits

- Only public product data. No login, no raffles, no checkout.
- Shops change their catalogue layout from time to time; the run summary (`OUTPUT`) shows the status of every shop.
- Stock is what the shop shows at the time of the run.

# Actor input Schema

## `shops` (type: `array`):

Sneaker shops to read. All 13 are read with plain HTTP from their public product feed.

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

Model names to find, for example "Dunk", "New Balance 990", "adidas Samba", "Jordan 4". A sneaker matches when all words of one keyword are in its name, brand or style code. Empty: all sneakers.

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

Only these brands, for example "Nike", "adidas", "New Balance", "ASICS". Empty: all brands.

## `styleCodes` (type: `array`):

Track exact manufacturer style codes, for example "DD1391-100" (Nike), "IE3437" (adidas), "U9060BLK" (New Balance), "1201A789-020" (ASICS). Combined with keywords as OR.

## `excludeKeywords` (type: `array`):

Drop sneakers whose name has one of these, for example "kids", "slide", "GS".

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

Most sneakers to save in one run (all shops together). Changes are saved first.

## `maxItemsPerShop` (type: `integer`):

Most sneakers per shop. Empty: Max sneakers divided by the number of shops.

## `maxPagesPerShop` (type: `integer`):

Each page has 250 products of the shop's footwear collection, newest first in most shops. More pages find more matches for rare keywords but take longer.

## `sizes` (type: `array`):

Only sneakers available in these sizes, and restock / sold out alerts only for them. Write the system: "EU 42", "US 9", "UK 8", "EU 42 2/3". A bare number from 30 up is EU, else US. Sizes are not converted between systems (it depends on the brand): add each system you care about.

## `onlyInStock` (type: `boolean`):

Only sneakers with at least one size in stock (in your sizes, if you set sizes).

## `onlyOnSale` (type: `boolean`):

Only sneakers with a reduced price (old price shown by the shop).

## `minDiscountPercent` (type: `integer`):

Only sneakers with at least this discount, for example 30.

## `minPriceEur` (type: `integer`):

Lowest price, converted to EUR for shops in GBP or USD.

## `maxPriceEur` (type: `integer`):

Highest price, converted to EUR for shops in GBP or USD.

## `trackChanges` (type: `boolean`):

Remember every sneaker between runs and report new releases, price drops and rises, sales starting and ending, restocks (with the sizes), sold out and removed. The first run saves the baseline. Schedule the Actor (for example every hour) to get alerts.

## `trackerName` (type: `string`):

Name of this tracker, for example "dunk-eu". Runs with the same name compare with each other. Empty: a name made from your keywords, brands and style codes. Letters, numbers and dashes.

## `onlyChanges` (type: `boolean`):

Save only sneakers that changed since the last run (new release, price drop, sale, restock, ...). Good for scheduled alerts.

## `maxRecheckPerShop` (type: `integer`):

Tracked sneakers that were not on the pages read this run are checked one by one, so their changes (and removals) are still caught. They are only saved when they changed.

## `compareAcrossShops` (type: `boolean`):

Group the same shoe (by style code) across shops: cheapest shop, price range in EUR, sizes in stock per shop. Saved in the COMPARISON record and as crossShop on each item.

## `includeStockX` (type: `boolean`):

Coming soon: StockX lowest ask and last sale for each style code. StockX blocks plain requests, so this switch does nothing yet and costs nothing. See the README.

## `includeZalando` (type: `boolean`):

Coming soon: the Zalando price for each style code. Zalando search results do not show style codes, so exact matching is not reliable yet; this switch does nothing yet and costs nothing. See the README.

## `zalandoCountry` (type: `string`):

Which Zalando site to check (for the coming-soon Zalando lookup).

## `maxResaleLookups` (type: `integer`):

Most style codes to look up on StockX / Zalando per run (coming soon).

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

Apify Proxy is recommended. With no group picked, shops use datacenter proxies and switch to RESIDENTIAL only if they block; StockX and Zalando use RESIDENTIAL.

## `debugTier2` (type: `boolean`):

Developer option: saves the first pages from StockX / Zalando in the key-value store.

## Actor input object example

```json
{
  "shops": [
    "kith-eu",
    "sneakersnstuff",
    "asphaltgold",
    "footdistrict"
  ],
  "keywords": [
    "Dunk"
  ],
  "maxItems": 50,
  "maxPagesPerShop": 8,
  "onlyInStock": false,
  "onlyOnSale": false,
  "trackChanges": true,
  "onlyChanges": false,
  "maxRecheckPerShop": 40,
  "compareAcrossShops": true,
  "includeStockX": false,
  "includeZalando": false,
  "zalandoCountry": "de",
  "maxResaleLookups": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "debugTier2": false
}
```

# Actor output Schema

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

One item per sneaker offer

## `comparison` (type: `string`):

Offers grouped by style code: cheapest shop, EUR price range, sizes per shop

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

Status per shop, counts, changes and charged events

# 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 = {
    "shops": [
        "kith-eu",
        "sneakersnstuff",
        "asphaltgold",
        "footdistrict"
    ],
    "keywords": [
        "Dunk"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/sneaker-price-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 = {
    "shops": [
        "kith-eu",
        "sneakersnstuff",
        "asphaltgold",
        "footdistrict",
    ],
    "keywords": ["Dunk"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apizilla/sneaker-price-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 '{
  "shops": [
    "kith-eu",
    "sneakersnstuff",
    "asphaltgold",
    "footdistrict"
  ],
  "keywords": [
    "Dunk"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apizilla/sneaker-price-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apizilla/sneaker-price-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/PzErLb4AJJg8AQ8eS/builds/akUaLEHgcsZLsxNoc/openapi.json
