# GOAT Scraper - Sneaker Asks, Last Sale, Sizes & Prices (`abotapi/goat-sneaker-scraper`) Actor

Scrape GOAT (goat.com), the sneaker and streetwear resale marketplace. Search or paste product, brand, collection and category URLs. 45+ fields per product: lowest ask, Instant Ship price, last sale and stock status for every size, retail, SKU, colorway, release date, images and story.

- **URL**: https://apify.com/abotapi/goat-sneaker-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## GOAT Sneaker Marketplace Scraper

Scrape [GOAT](https://www.goat.com), the sneaker and streetwear resale marketplace, at product level.
Search by keyword, browse the catalogue with filters alone, or paste GOAT product, search, brand,
collection and category URLs.

Every product comes back with its full identity and, with **Fetch full market data** on, the live
**per size market table**: lowest ask, Instant Ship price, **last sold price** and stock status for
every single size, in the market you choose.

### What you get

#### Always

| Field | What it is |
|---|---|
| `productId`, `slug`, `url` | GOAT's product id, URL slug and product page link |
| `name`, `nickname` | Full product name and its short nickname |
| `brand`, `sku`, `colorway`, `color` | Brand, style code, colorway text and base colour |
| `designer`, `silhouette`, `midsole`, `upperMaterial` | Design attributes |
| `productCategory`, `productType`, `activities` | Shoes / clothing / accessories, type, and activity tags |
| `gender`, `genders` | Primary audience and every audience it is cut for |
| `sizeRange`, `sizeUnit`, `sizeBrand` | Every size the product exists in, and the sizing system |
| `releaseDate`, `releaseYear`, `releaseMonth`, `season` | Release data |
| `retailPrice` | Original retail price, USD |
| `lowestAsk`, `instantShipLowestAsk` | Lowest ask and Instant Ship price, USD |
| `lowestAskSource` | `all_sizes` (true minimum across every size) or `search_match` (the one variant GOAT's search matched) |
| `matchedSize`, `matchedCondition`, `matchedBoxCondition` | The variant GOAT's search matched |
| `isUnderRetail`, `hasStock`, `status` | Whether it sits under retail, whether there is stock, listing status |
| `minimumOffer`, `maximumOffer` | The offer bounds GOAT enforces |
| `story`, `storyHtml` | The product write-up, plain and as HTML |
| `imageUrl`, `gridImageUrl`, `originalImageUrl` | Product images |
| `collectionSlugs` | GOAT collections the product is featured in |
| `market`, `currency`, `localPricing` | The market you asked for, and the retail/ask in that market's own currency |
| `siteName`, `scrapedAt` | Provenance |

#### With `fetchDetails` on

| Field | What it is |
|---|---|
| `sizes[]` | One row per size: `size`, `shoeCondition`, `boxCondition`, `lowestAsk`, `instantShipLowestAsk`, **`lastSale`**, `stockStatus` |
| `lowestAsk`, `lowestAskSize`, `highestAsk` | True lowest ask across every size, the size it is on, and the highest |
| `lastSale`, `lastSaleLow`, `lastSaleHigh`, `lastSaleSizeCount` | Median, cheapest and dearest most-recent sale price across sizes |
| `totalSizeCount`, `sizesWithAskCount`, `inStockSizeCount`, `instantShipSizeCount` | Depth of the market on this product |
| `imageUrls[]` | The full image gallery, not just the hero shot |
| `sizeOptions[]` | Every size option GOAT lists for the product |
| `taxonomy`, `isOfferable`, `isResellable` | Classification and trade flags |
| `usedForSaleCount`, `withDefectForSaleCount`, `sellingCount` | How many listings exist per condition |
| `detailCarriedForward` | Present and `true` only when a market fetch failed and the row was repaired from the previous run |

#### In incremental mode

`changeType` (`NEW` / `UPDATED` / `REAPPEARED` / `UNCHANGED` / `EXPIRED`), `changedFields`,
`firstSeenAt`, `lastSeenAt`.

### Modes

#### Search

Give one or more search terms. Each is scraped independently.

```json
{ "mode": "search", "searchTerms": ["air jordan 1", "nike dunk low"], "maxItems": 50 }
```

Leave `searchTerms` empty and set filters instead to browse the catalogue itself, for example every
Nike basketball shoe under $150 released since 2024:

```json
{
  "mode": "search",
  "searchTerms": [],
  "brands": ["Nike"],
  "activity": "basketball",
  "maxPriceUsd": 150,
  "releaseYearFrom": 2024,
  "maxItems": 200
}
```

#### URL

Paste any of these and the actor works out what to do with it:

| URL | What happens |
|---|---|
| `https://www.goat.com/sneakers/<slug>` | That one product, in full |
| `https://www.goat.com/search?query=travis+scott` | Paged like a keyword search |
| `https://www.goat.com/brands/new-balance` | The brand, resolved to GOAT's own brand name |
| `https://www.goat.com/collections/<slug>` | That collection |
| `https://www.goat.com/sneakers` (or `/apparel`, `/accessories`) | That category |
| any browse URL with `?page=3` | Starts the walk at page 3 |

The filters apply to every pasted browse URL as well. A pasted product URL is the one exception: it
always returns that single product in full.

### Filters

All of them are sent to GOAT's own search, so a filtered run reads fewer pages instead of throwing
rows away afterwards.

`brands`, `productCategory`, `activity`, `gender`, `condition`, `sizeUs`, `minPriceUsd`,
`maxPriceUsd`, `releaseYearFrom`, `releaseYearTo`, `inStockOnly`, `instantShipOnly`,
`underRetailOnly`.

`condition` also narrows the per size market table, so the lowest ask and last sale you get back are
for that condition only.

### Ship-to market

`market` (US, GB, CA, AU, DE, JP) is a real narrowing, not a currency label. GOAT offers different
sizes at different prices per country, so switching markets changes the asks, the last sale prices
and which sizes come back. Top level money fields stay in USD so rows remain comparable; the
market's own currency is carried in `localPricing`.

### Recurring monitoring

Turn on **Incremental changes for scheduled runs** and schedule the actor. The first run returns
everything as `NEW`; later runs return only what changed. Price, ask and stock moves are reported as
`UPDATED` with the exact fields listed in `changedFields`, because on a resale marketplace those are
the signal rather than noise.

- State is kept per search, URL, filter and market setup, so two different searches never mix.
- `emitUnchanged` and `emitExpired` are off by default. Both return, and bill, extra rows.
- `EXPIRED` is only produced after a run has fully scanned the tracked search. A run that was capped
  by Max items, resumed, blocked, or truncated by GOAT's own 1000-product search limit never marks
  anything expired.

To continue one specific interrupted crawl instead, paste its run id into **Resume from a previous
run**. Products that run already collected are skipped, and not charged again.

### Limits worth knowing

- GOAT's search returns at most **1000 products per query**. A very broad scope is truncated there,
  and the run says so in the log. Narrow it with the brand, category, size, price or release year
  filters to reach the rest.
- GOAT does not publish highest bid, bid counts or a historical sales chart on its public surfaces.
  The deepest sales signal it does publish is the **most recent sale price per size**, which this
  actor returns in `sizes[].lastSale` plus the `lastSale` / `lastSaleLow` / `lastSaleHigh` roll-up.

### Costs

You are charged once when the run starts, once for every product returned, and once more per product
when **Fetch full market data** is on. A catalogue-only run never triggers the third charge. The Store
page shows the current rates.

### Connection

The default proxy setting works on every plan. Apify Residential is available
in the Proxy setting as a fallback if you start seeing refusals.

### Output example

```json
{
  "productId": 651566,
  "slug": "air-jordan-1-mid-chicago-554724-173",
  "url": "https://www.goat.com/sneakers/air-jordan-1-mid-chicago-554724-173",
  "name": "Air Jordan 1 Mid 'Chicago'",
  "brand": "Air Jordan",
  "sku": "554724 173",
  "colorway": "White/Gym Red/Black",
  "productCategory": "shoes",
  "gender": "men",
  "retailPrice": 115.0,
  "lowestAsk": 52.0,
  "lowestAskSize": "8",
  "highestAsk": 334.0,
  "lowestAskSource": "all_sizes",
  "instantShipLowestAsk": 75.0,
  "lastSale": 145.0,
  "lastSaleLow": 44.0,
  "lastSaleHigh": 307.0,
  "lastSaleSizeCount": 111,
  "totalSizeCount": 123,
  "sizesWithAskCount": 64,
  "inStockSizeCount": 64,
  "instantShipSizeCount": 14,
  "hasStock": true,
  "releaseDate": "2020-09-09T23:59:59.999Z",
  "market": "US",
  "currency": "USD",
  "localPricing": {
    "currency": "USD",
    "retailPrice": 115.0,
    "lowestAsk": 52.0
  },
  "sizes": [
    {
      "size": "7",
      "sizeValue": 7,
      "shoeCondition": "new_no_defects",
      "boxCondition": "good_condition",
      "lowestAsk": 188.0,
      "instantShipLowestAsk": 202.0,
      "lastSale": 120.0,
      "stockStatus": "single_in_stock"
    }
  ],
  "siteName": "GOAT"
}
```

### Verification

2026-09-01: audit re-derived the live catalogue counts from the search index the actor queries.
Narrowing is monotone: 609,262 products unfiltered, 2,383 for the keyword "air jordan 1", 39 with
the brand facet, 25 with the gender facet, 12 with a size facet, 6 inside a price band. Every
documented filter maps to a live facet or numeric field. All five URL shapes verified: a product
page returns one full record, a search URL paginates (1,351 matches), a brand page resolves to the
index's own brand name (23,788), a collection page filters on its slug (83 for a live collection),
and a category page maps to its product category (149,011).

# Actor input Schema

## `mode` (type: `string`):

How to start the scrape. 'search' runs GOAT keyword searches. 'url' processes the GOAT URLs you paste: a product URL is fetched as a single product, and a search, brand, collection or category URL is paged like a search. Only where the scope comes from differs: the filters below apply in BOTH modes.

## `searchTerms` (type: `array`):

One or more things to search GOAT for, for example 'air jordan 1', 'nike dunk low', 'yeezy 350'. Each term is scraped independently. Search mode only: in URL mode the scope is read out of each pasted GOAT URL instead. If you leave this empty and set at least one filter, the actor browses the whole catalogue narrowed by those filters.

## `urls` (type: `array`):

Paste GOAT product URLs (https://www.goat.com/sneakers/<slug>), search URLs (https://www.goat.com/search?query=...), brand pages (https://www.goat.com/brands/nike), collection pages (https://www.goat.com/collections/<slug>) or category pages (https://www.goat.com/sneakers). Add ?page=3 to any browse URL to start walking from that page instead of the first. The filters below are NOT ignored here: every pasted search, brand, collection or category URL is re-run through GOAT's search with them applied. A pasted product URL is the one exception, since it returns that single product in full.

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

Only return products from these brands, for example 'Nike', 'Air Jordan', 'adidas', 'New Balance'. Several brands are combined with OR. Leave empty for every brand. Applies in BOTH search mode and URL mode. A pasted brand page URL overrides this filter for that URL only.

## `productCategory` (type: `string`):

Only return products in this category. Applies in BOTH search mode and URL mode. A pasted category page URL overrides this filter for that URL only.

## `activity` (type: `string`):

Only return products GOAT files under this activity. Applies in BOTH search mode and URL mode.

## `gender` (type: `string`):

Only return products cut for this audience. Applies in BOTH search mode and URL mode.

## `condition` (type: `string`):

Only return listings in this condition. This also narrows the per size market table when Fetch full market data is on, so the lowest ask and last sale you get back are for this condition only. Applies in BOTH search mode and URL mode.

## `sizeUs` (type: `string`):

Only return products listed in this US size, for example '10' or '9.5'. Leave empty for every size. Applies in BOTH search mode and URL mode.

## `minPriceUsd` (type: `integer`):

Only return products whose lowest ask is at least this many US dollars. Applies in BOTH search mode and URL mode.

## `maxPriceUsd` (type: `integer`):

Only return products whose lowest ask is at most this many US dollars. Applies in BOTH search mode and URL mode.

## `releaseYearFrom` (type: `integer`):

Only return products released in this year or later. Applies in BOTH search mode and URL mode.

## `releaseYearTo` (type: `integer`):

Only return products released in this year or earlier. Applies in BOTH search mode and URL mode.

## `inStockOnly` (type: `boolean`):

Only return products that currently have stock on GOAT. Applies in BOTH search mode and URL mode.

## `instantShipOnly` (type: `boolean`):

Only return products with an Instant Ship price, meaning stock GOAT already holds and can send immediately. Applies in BOTH search mode and URL mode.

## `underRetailOnly` (type: `boolean`):

Only return products whose lowest ask is below the original retail price. Applies in BOTH search mode and URL mode.

## `market` (type: `string`):

The market the prices apply to. GOAT offers different sizes at different prices per country, so this genuinely changes the asks, the last sale prices and which sizes come back. Top level money fields are always USD so rows stay comparable; the market's own currency is carried in localPricing. Applies in BOTH search mode and URL mode.

## `sortResultsBy` (type: `string`):

Order of the rows this run returns. GOAT's public search does not offer server side ordering, so this orders the products this run collected, not the whole catalogue. To target the cheapest or most expensive listings across the catalogue, use the price filters above instead. Applies in BOTH search mode and URL mode.

## `fetchDetails` (type: `boolean`):

Fetch each product's live per size market table: lowest ask, Instant Ship price, LAST SOLD price and stock status for every size, plus the full image gallery, the offer bounds and the for sale counts. This also replaces the single sampled ask with the true lowest ask across all sizes (the row then reports lowestAskSource = all\_sizes). Slower, and charged once per product. Leave off for a fast catalogue crawl: identity, retail price, release date, images, story and a sampled ask are included either way.

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

The single cap on this run: stop after collecting this many products across all search terms and URLs. Set 0 for unlimited.

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

Safety bound on how many result pages to walk per search term or URL. Leave empty (0) for no page limit: the run stops at Max items, not here. Does not impose a separate cap below Max items. GOAT itself returns at most 1000 products per search, so a very broad scope needs the filters above rather than more pages.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl without returning or charging for products already collected there. Use this after an interrupted or capped run. For recurring monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or weekly recurring monitoring of the same search. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED products. Price, ask and stock moves ARE reported as UPDATED: on a resale marketplace they are the signal, not noise. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately per search, URL, filter and market setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search terms, URLs, filters and market, so two different searches never mix state.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want a full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search: not when Max items capped it, not when Resume was used, not when the run was blocked, and not when GOAT's 1000 product search limit truncated the scope. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.

## `proxy` (type: `object`):

Leave the default for the cheapest run. Apify Residential is available as a fallback if the shared pool starts getting refused.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerms": [
    "air jordan 1"
  ],
  "urls": [
    "https://www.goat.com/sneakers/air-jordan-1-mid-chicago-554724-173"
  ],
  "productCategory": "",
  "activity": "",
  "gender": "",
  "condition": "",
  "inStockOnly": false,
  "instantShipOnly": false,
  "underRetailOnly": false,
  "market": "US",
  "sortResultsBy": "relevance",
  "fetchDetails": true,
  "maxItems": 20,
  "maxPages": 0,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "searchTerms": [
        "air jordan 1"
    ],
    "urls": [
        "https://www.goat.com/sneakers/air-jordan-1-mid-chicago-554724-173"
    ],
    "market": "US",
    "fetchDetails": true,
    "maxItems": 20,
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/goat-sneaker-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 = {
    "mode": "search",
    "searchTerms": ["air jordan 1"],
    "urls": ["https://www.goat.com/sneakers/air-jordan-1-mid-chicago-554724-173"],
    "market": "US",
    "fetchDetails": True,
    "maxItems": 20,
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/goat-sneaker-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 '{
  "mode": "search",
  "searchTerms": [
    "air jordan 1"
  ],
  "urls": [
    "https://www.goat.com/sneakers/air-jordan-1-mid-chicago-554724-173"
  ],
  "market": "US",
  "fetchDetails": true,
  "maxItems": 20,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/goat-sneaker-scraper --silent --output-dataset

```

## MCP server setup

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