1. 2scraper
  2. E-commerce & retail
  3. StockX
Open source · MITFree to run · paid add-ons optional

StockX Scraper

Search results, category listings and product pages — lowest ask, highest bid and last sale from StockX's own payload.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
stockx-scraper
# Category listing
$ python3 playwright_scraper.py --category sneakers --pages 3 --format json --out stockx_sneakers.json
✓ 6 sample rows · 21 columns in sample_output.json
3page kinds: search, category, product
21output columns
41products from one category run via the Scraping Browser API
0keys needed in the Sep 2026 headless captures
Available StockX scrapers

What the StockX scraper collects

Scrapes StockX search results, category/browse listings and single product pages. Listing rows carry live market data — lowest ask, highest bid, last sale, annual average price and sales count — read from the site's embedded Next.js payload; product pages add style ID, colorway, retail price and per-size offers. Output is JSON or CSV with a run-metadata sidecar.

Category listing

Input: A category slug such as sneakers

One row per product with brand, lowest ask, highest bid, last sale, release date, annual average price and sales count, paginated with ?page=N.

Search results

Input: A stockx.com/search URL

The same market-data rows for every product matching a search query.

Single product

Input: A product page URL

One product with style ID, colorway, retail price in USD and per-size offers from the page's JSON-LD.

Quick start

From zero to StockX data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/stockx-scraper.git && cd stockx-scraper
    $ python3 -m venv .venv && . .venv/bin/activate
    $ pip install -r requirements-playwright.txt && playwright install chromium
    $ cp .env.example .env
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --category sneakers --pages 3 --format json --out stockx_sneakers.json
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

StockX data fields

21 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
skuThe product's StockX URL slug
titleProduct name
brandBrand, e.g. Jordan
priceLowest ask — the price a buyer could act on now
currencyCurrency of the page, localized by exit country
lowest_askLowest ask
highest_bidHighest bid (listing rows)
last_saleLast sale price (listing rows)
annual_avg_priceAverage sale price over the year
annual_sales_countNumber of sales over the year
release_dateRelease date
style_idManufacturer style ID (product pages only)
colorwayColorway (product pages)
retail_price_usdRetail price, always in USD
genderTarget gender/demographic
price_sourceembedded_json (listings) or jsonld (product pages)
[
  {
    "sku": "air-jordan-4-retro-toro-bravo-2026",
    "source": "stockx.com",
    "category": "search:jordan 4",
    "title": "Jordan 4 Retro Toro Bravo (2026)",
    "brand": "Jordan",
    "price": 123,
    "currency": "EUR",
    "price_source": "embedded_json",
    "product_url": "https://stockx.com/air-jordan-4-retro-toro-bravo-2026",
    "image_url": "https://images.stockx.com/images/Air-Jordan-4-Retro-Toro-Bravo-2026-Product.jpg?fit=fil…",
    "scraped_at": "2026-09-10T13:36:18Z",
    "style_id": null,
    "colorway": null,
    "lowest_ask": 123,
    "highest_bid": 214,
    "last_sale": 147,
    "retail_price_usd": null,
    "release_date": "2026-05-30",
    "annual_avg_price": 158,
    "annual_sales_count": 33540,
    "gender": "men"
  },
  {
    "sku": "air-jordan-4-retro-rare-air-tour-yellow",
    "source": "stockx.com",
    "category": "search:jordan 4",
    "title": "Jordan 4 Retro Rare Air Tour Yellow",
    "brand": "Jordan",
    "price": 149,
    "currency": "EUR",
    "price_source": "embedded_json",
    "product_url": "https://stockx.com/air-jordan-4-retro-rare-air-tour-yellow",
    "image_url": "https://images.stockx.com/images/air-jordan-4-retro-rare-air-tour-yellow.jpg?fit=fill&b…",
    "scraped_at": "2026-09-10T13:36:18Z",
    "style_id": null,
    "colorway": null,
    "lowest_ask": 149,
    "highest_bid": 135,
    "last_sale": 152,
    "retail_price_usd": null,
    "release_date": "2026-09-05",
    "annual_avg_price": 160,
    "annual_sales_count": 2580,
    "gender": "men"
  }
]

First 2 of 6 rows from a real run — sample_output.json. Long values shortened here.

Built for StockX

Handles what breaks naive StockX scrapers

Market data from the embedded payload

Listing pages carry no product JSON-LD; the scraper reads the getDiscoveryData entry of StockX's __NEXT_DATA__ cache, which holds asks, bids, last sale and annual stats with no DOM read.

Both listing-node shapes handled

Some listing rows arrive as Variant-typed edges with catalogue fields nested one level down; the parser handles both shapes, verified against a real capture.

No false block from Cloudflare's precursor script

Cloudflare's challenge-platform script is present on fully successful pages too, so it is deliberately excluded from the block markers.

Detected is not paying

A captcha widget on a page whose products are already rendered is never solved — the log on a real Scraping Browser API run shows exactly that decision.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete StockX snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with StockX data

Sneaker resale pricing

Track lowest ask, highest bid and last sale across a category to spot spread and momentum.

Release performance

Compare annual average price and sales count against retail price to see which releases trade above retail.

Inventory and arbitrage research

Monitor bids and asks for a watchlist of models and diff runs over time.

Product catalogue enrichment

Pull style IDs, colorways and release dates from product pages to enrich your own catalogue.

Access & pricing

Free to run. Pay only for what the site requires.

Free to run · paid add-ons optional

In live captures on 2026-09-10 an ordinary headless Chromium with no proxy, key or account cleared StockX's Cloudflare checks on every page requested. Results vary by path and exit: in later runs, automated sessions also met fast 403s and a Cloudflare block page carrying no captcha, while a category run through the Scraping Browser API came back complete with 41 products. The paid products buy volume from many addresses, a specific exit country (prices localize to it) and a consistent device identity.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • Captcha token injection on a locally launched browser is not implemented; over --cdp-endpoint the Scraping Browser API handles solving itself.
  • highest_bid and last_sale are only populated on listing rows.
  • Automated sessions have been refused with HTTP 403 on some runs; results vary by path and exit.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

StockX scraper FAQ

Do I need a proxy or a 2Captcha key?

Not necessarily: the September 2026 captures were taken with plain headless Chromium and no key. Results vary by exit and session, so proxies and the Scraping Browser API are there for volume, geography and consistency.

Why is style_id empty on listing rows?

StockX publishes style ID only on product pages. Scrape a product's own URL if you need it.

Why are highest_bid and last_sale empty on product rows?

The product page's server-rendered payload does not carry them; they appear on listing rows, so scrape the category or search listing for those.

What currency are prices in?

Prices are localized to the exit country — a Netherlands exit returned EUR throughout — except retail_price_usd, which StockX always states in USD.

How does pagination work?

StockX uses a real ?page=N parameter, and requesting a page directly server-renders that page's own data.

Is scraping StockX legal?

It reads public pages without an account. Follow StockX's terms and the law where you operate.