ThredUp Scraper - Resale Fashion, Prices & 35+ Fields avatar

ThredUp Scraper - Resale Fashion, Prices & 35+ Fields

Pricing

from $1.50 / 1,000 listing results

Go to Apify Store
ThredUp Scraper - Resale Fashion, Prices & 35+ Fields

ThredUp Scraper - Resale Fashion, Prices & 35+ Fields

Scrape ThredUp resale listings by keyword, department, brand, size, condition, price or URL. Extract 35+ fields including brand, price, original price, MSRP, size, colours, materials, condition, category and all photos. Supports filters and sorting.

Pricing

from $1.50 / 1,000 listing results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

2

Monthly active users

2 days ago

Last modified

Share

ThredUp Scraper: Secondhand Fashion Prices, Sizes & Photos

ThredUp Scraper turns ThredUp, one of the largest online resale and thrift marketplaces for secondhand clothing, shoes and accessories, into clean structured data. Give it keywords plus a department and filters, or paste ThredUp category and item URLs, and get brand, price, original price, MSRP, size, colors, materials, condition, category and every photo for each listing. Search and URL modes, three sort orders, and brand, category, material, condition and price filters are all built in, and you can export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • Returns 35+ named fields per item with no extra request: brand, price, original price, MSRP, size, condition, colors, materials, category, department and every photo URL.
  • Two ways to collect: keyword search with department, brand, material, style, condition and price filters, or paste ThredUp category and item URLs directly.
  • Three sort orders for search results: relevance, price low to high, price high to low.
  • Optional full item details on demand: description plus garment measurements (chest, waist, inseam, length).
  • Built for schedules: incremental mode returns only new, updated and reappeared items on recurring runs, and a refused run fails loudly instead of quietly returning an empty dataset.
  • Resume one interrupted crawl with resumeFromRunId so you never pay twice for items already collected.
  • Set Max items and Max pages to control run size and cost precisely.

Use Cases

  • Resale price tracking: monitor a brand or category's price and MSRP spread over time to spot underpriced or newly listed items.
  • Competitive analysis for resale sellers: compare your own listings' pricing and condition grading against similar items already on ThredUp.
  • Market research and trend analysis: build a dataset of brand, material, condition and price mix across departments to track secondhand demand.
  • Personal shopping bots and alerts: watch a saved search for new drops in your size, brand or price range.
  • Academic and sustainability research: study circular-fashion pricing, condition grading and turnover patterns.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
id200000000
itemNumber1500000000
url"https://www.thredup.com/product/1500000000"
title"Sample Item Title"
description"Short item description appears here."
brand"Sample Brand"
price24.99
originalPrice39.99
msrp89
condition"excellent"
sizeDisplay"Size M"
department"women"
category"dresses"
colorNames["Black"]
materials["Cotton"]
newWithTagsfalse
clearancefalse
imageUrl"https://tup-images.thredup.com/assets/000000000/xlarge.jpg"
imageUrls["https://tup-images.thredup.com/assets/000000000/xlarge.jpg"]
fullDescription"Full description appears when Fetch full details is on."
measurements{ "chest": "00", "length": "00" } (when Fetch full details is on)
changeType"NEW" (also "UPDATED", "UNCHANGED", "REAPPEARED", "EXPIRED", incremental mode only)
changedFields["price"] (incremental mode only, non-empty only for UPDATED)
firstSeenAt"2024-01-01T00:00:00Z" (incremental mode only)
lastSeenAt"2024-01-02T00:00:00Z" (incremental mode only)

Other output rows carry the same shape with extra catalog fields such as sku, brandId, categoryTags, departmentTags, styleTags, availability, state, favoriteCount, warehouseId, supplierId and the raw photoIds list; these fill in from the same listing or item-page fetch with no separate toggle.

How to Use

  1. Pick a mode: search (keywords plus filters) or url (paste ThredUp category and item links).
  2. In search mode, set a department and any filters (brand, category, material, style, condition, price, sort). In url mode, paste the category or item links directly; filters and sort are read from each URL.
  3. Turn on Fetch full details if you also want the description and garment measurements.
  4. Set Max items (and optionally Max pages) to control run size and cost, then click Start.

Search a department with filters:

{
"mode": "search",
"searchQueries": ["nike dress"],
"department": "women",
"brands": ["Nike"],
"priceMin": 15,
"priceMax": 60,
"sortBy": "price_low_high",
"maxItems": 50,
"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}

Browse a whole category with full details:

{
"mode": "search",
"department": "juniors",
"categories": ["jeans"],
"fetchDetails": true,
"maxItems": 40
}

Paste ThredUp URLs (category pages and item pages):

{
"mode": "url",
"urls": [
"https://www.thredup.com/women?department_tags=women",
"https://www.thredup.com/product/1500000000"
]
}

Track new drops in a brand on a schedule:

{
"mode": "search",
"searchQueries": ["Madewell"],
"department": "women",
"incrementalMode": true,
"maxItems": 100
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/thredup-scraper").call(run_input={
"mode": "search",
"searchQueries": ["nike dress"],
"department": "women",
"maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item["brand"], item["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/thredup-scraper').call({
mode: 'search',
searchQueries: ['nike dress'],
department: 'women',
maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

How deep a search goes

There is no page limit by default: Max pages is empty (0), and the walk keeps going until ThredUp itself stops serving pages or Max items is reached.

ThredUp's own search backend, however, only serves the first block of about 10,000 matches for any one query or filter set, at 48 items per page. A broad search such as all of women reports a fixed total and stops after roughly 209 pages no matter how many items actually exist behind it. That is a limit of the site, not of this actor, and raising Max pages cannot get past it. To collect more from a large department, split the search into narrower slices (by brand, category, price band or condition) and run them separately; a slice whose real total is below that ceiling is served in full.

This also decides when EXPIRED rows can fire: they only make sense after a run has proven it saw the whole tracked result set, so a search that hit the site's own ceiling is skipped for EXPIRED detection rather than risk billing tombstones for items that are actually still listed.

Resume and recurring updates

There are two different things here, pick the one that matches what you are doing:

NeedUse
A crawl stopped and should continueresumeFromRunId
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous crawl: paste a run ID or dataset ID and this run skips items already collected there, returning only the remaining new items. Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW; later runs return only NEW, UPDATED and REAPPEARED items by default, and unchanged items are not billed unless you turn on Emit unchanged. State is isolated per search or URL and filter setup automatically; set stateKey to name or deliberately share a monitoring campaign, but only share it across configurations you actually want merged into one combined baseline (see the FAQ).

A few limits worth knowing before you rely on incremental mode for billing-sensitive scheduling:

  • EXPIRED detection is not capped by Max items. It runs once the normal walk finishes and pushes every tombstoned item it finds in one batch, so an EXPIRED-heavy run can return and bill more rows than Max items alone suggests. Turn Emit expired off if you need a hard, predictable cap on every run.
  • Combining resumeFromRunId with a first-time incrementalMode bootstrap (a search that has no prior incremental state yet) makes every resumed item read as UPDATED, with every field listed in changedFields, on the very next ordinary scheduled run. This is a one-time effect per resumed item, not a repeating one.
  • Each page of results is split against the remaining Max items share before anything is returned, and every item on that page, including the ones past the share, is counted as already handled for the rest of the run. Two things follow. With several search queries or URLs in one call, an item that an earlier query fetched but did not return is skipped by every later query too, so a tight Max items can return fewer items than were actually available. In incremental mode, unchanged items are dropped only after that split, so when the top of a page is unchanged, NEW items further down the same page can be skipped for this run (they show up as NEW on a later run). Give Max items generous headroom (or set it to 0) when running several queries together or when using incremental mode.
  • In url mode, if a pasted item link fails to load, that item is not returned, and the failure does not stop EXPIRED detection: if the item was tracked before and Emit expired is on, the run can wrongly mark it EXPIRED even though it may still be listed. Re-check any EXPIRED result on a pasted item link directly before acting on it.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use, through Model Context Protocol (MCP) connectors. Authorize a connector under Apify, Settings, API and Integrations, then select it in the mcpConnectors input. For Notion, also set notionParentPageUrl. Each item is written as a condensed, human-readable summary (title plus key fields), not the full JSON; the complete record always stays in the Apify dataset. Leave the field empty to skip; it never changes the dataset output.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (keywords plus filters) or url (paste ThredUp URLs).
searchQueriesarray(none)Keywords to search ThredUp for (search mode). Leave empty to browse a whole department or category by filters.
departmentstringwomenTop-level department: women, juniors, girls, boys, maternity, plus, petite, designer, handbags, shoes, accessories.
categoriesarray(none)Category tags to narrow to (e.g. dresses, jeans, sneakers).
brandsarray(none)Brand names to filter by (e.g. Nike, Madewell, Lululemon).
materialsarray(none)Material tags (e.g. Cotton, Leather, Silk).
stylesarray(none)Style tags (e.g. Casual, Y2K).
conditionarray(none)ThredUp condition tags to filter by (advanced; leave empty for any condition). The output condition field always shows the item's quality grade.
clearanceOnlybooleanfalseOnly return items ThredUp itself flags as clearance. Applies to search mode; in url mode the pasted link decides what is returned.
priceMininteger(none)Only return items priced at or above this amount, in USD.
priceMaxinteger(none)Only return items priced at or below this amount, in USD.
sortBystringrelevancerelevance, price_low_high, or price_high_low.
urlsarray(none)ThredUp category (PLP) or item URLs to paste (url mode). Multiple URLs supported; filters and sort are read from each one.
fetchDetailsbooleanfalseVisit each item page to add the full description and measurements. Adds a small per-item charge; leave off for fast listings, which already include brand, price, size, condition, colors, materials and all photos.
maxItemsinteger20Stop after collecting this many items across all queries or URLs. Set 0 for unlimited.
maxPagesinteger0Optional cap on result pages per query. Leave empty (or 0) for no page limit: the run then stops only when Max items is reached or ThredUp stops serving further pages. See "How deep a search goes" above for ThredUp's own depth limit.
proxyobjectResidential USProxy configuration. ThredUp only serves US connections, so Residential US is required for reliable results.
resumeFromRunIdstring(none)Continue one specific previous run or dataset: items already collected there are skipped and not re-billed. For recurring monitoring of the same search, use Incremental mode instead.
incrementalModebooleanfalseDaily or recurring monitoring of this same search. The first run returns everything as NEW; later runs return only NEW, UPDATED and REAPPEARED by default. See "Resume and recurring updates" above.
stateKeystring(none)Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Auto-derived from your search, URL and filter settings when left empty.
emitUnchangedbooleanfalseIncremental mode only. Also return items unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have.
emitExpiredbooleanfalseIncremental mode only. Also return items from a previous run no longer found, marked EXPIRED, once a run has fully scanned the search (not capped, not a resume, and narrow enough that ThredUp serves the whole result set). Adds and bills extra synthetic rows, not capped by Max items.
mcpConnectorsarray(none)Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API and Integrations, then select it here. Leave empty to skip; never changes the dataset output.
notionParentPageUrlstring(none)Notion connector only: URL (or id) of the page under which item pages are created. Ignored by other connectors.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"id": 200000000,
"itemNumber": "1500000000",
"sku": "SKU0000000",
"url": "https://www.thredup.com/product/1500000000",
"title": "Sample Item Title",
"description": "Short item description appears here.",
"brand": "Sample Brand",
"brandId": 1000,
"price": 24.99,
"originalPrice": 39.99,
"msrp": 89,
"clearance": false,
"newWithTags": false,
"condition": "excellent",
"sizeDisplay": "Size M",
"department": "women",
"category": "dresses",
"categoryTags": ["dresses"],
"colorNames": ["Black"],
"materials": ["Cotton"],
"availability": "available",
"favoriteCount": 0,
"warehouseId": 0,
"photoIds": ["000000000"],
"imageUrls": ["https://tup-images.thredup.com/assets/000000000/xlarge.jpg"],
"imageUrl": "https://tup-images.thredup.com/assets/000000000/xlarge.jpg",
"fullDescription": null,
"measurements": null
}

Plan Requirement

This actor requires Apify Residential proxy with country set to US, since ThredUp filters non-US and datacenter connections. Residential proxy access is included from the Starter plan and above. Pick Residential US under Connection; without it, runs will typically return zero items and a message explaining what to change.

FAQ

How much does it cost?

You pay per item returned, with the optional full-details fetch billed only when you switch it on. The Pricing tab shows the current rates. Use Max items to cap the cost of a run.

This actor collects only publicly available resale listings. You are responsible for how you use the data: follow ThredUp's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and listing details are generally facts, but photos may be subject to third-party rights.

Can I get only new or changed items on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW, UPDATED and REAPPEARED items by default, and unchanged items are not billed unless you also turn on Emit unchanged.

What's the difference between Resume and Incremental mode?

Resume (resumeFromRunId) continues one specific interrupted or previous run: paste its run or dataset ID and this run skips items already collected there. Incremental mode is for running the same search again and again, for example daily: the actor remembers the previous run of that search by itself, so you never paste an ID.

Why did my run fail instead of returning an empty dataset?

If a connection to ThredUp cannot be established at all, the run stops with a clear message so "no listings matched" is never confused with "the connection never worked". This is usually transient; try again, and confirm Apify Residential proxy with country US is set.

Why did a scheduled run bill more items than my Max items setting?

Max items caps the normal search or URL walk, but EXPIRED detection runs as a separate step afterward and is not capped by it: once a run has scanned a tracked search completely (not capped, not a resume), every previously tracked item no longer found is pushed as an EXPIRED row, however many that is. If your tracked backlog is large, an EXPIRED-heavy run can return and bill more rows than Max items alone would suggest. Turn off Emit expired if you need a hard, predictable cap on every run.

Why was an item marked UPDATED even though nothing about it seems to have changed?

This can happen once per item after you bootstrap Incremental mode from Resume, meaning resumeFromRunId combined with incrementalMode on a search that has no prior incremental state yet. Items pulled in through Resume are recorded without a comparable snapshot, so the very next ordinary scheduled run has nothing reliable to diff them against and reports them as UPDATED with every field listed in changedFields. It is a one-time effect for each resumed item, not a repeating one.

Can two searches share the same monitoring state?

Yes, by setting the same State key on both, which is useful when you deliberately want one combined "still listed" baseline for two related searches. Doing this across searches that track very different items is not recommended: once one of them scans to completion with Emit expired on, it will tombstone every tracked item it does not itself encounter, including ones that only the other search would find and that may still be live.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

πŸ”— Want more classifieds data?

Pair this actor with these related scrapers from the same team:

🏷️ Vinted.fr
Scrape Vinted.fr, France's C2C second-hand fashion marketplace: search with...
🏷️ Poshmark Scraper
Scrape Poshmark fashion-resale listings: keyword search, brand and category browse, sold...
πŸ‘— 24S Scraper
Scrape 24S luxury fashion by category, filters, or URL. Extract brand, name, price...
πŸ‘— Mango Scraper
Scrape Mango (shop.mango.com) fashion products: current price plus strike-through Rebajas...
🏷️ Daangn Scraper
From $1/1K. Scrape Daangn (λ‹Ήκ·Ό) marketplace listings by keyword and region. Returns 35+...
🏷️ Vinted Multi-Country Scraper
Scrape Vinted across 27 country marketplaces: keyword search with brand, price and...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • πŸ› οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.