Poshmark Scraper - Listings, Sold Prices & Closets
Pricing
from $1.40 / 1,000 listing or seller records
Poshmark Scraper - Listings, Sold Prices & Closets
Scrape Poshmark fashion-resale listings: keyword search, brand and category browse, sold listings with sold dates, seller closet stats (followers, following). Filters for department, condition and availability. Incremental monitoring, resume, MCP export.
Pricing
from $1.40 / 1,000 listing or seller records
Rating
5.0
(1)
Developer
Abot API
Maintained by CommunityActor stats
3
Bookmarked
2
Total users
2
Monthly active users
11 days ago
Last modified
Categories
Share
Poshmark Scraper: Listings, Sold Prices & Seller Closets
Poshmark Scraper turns Poshmark into a clean secondhand-fashion data feed. Get listing details, sold prices with sold dates, seller closet profiles and social counts across every department and brand. Search by keyword, brand or seller closet, or paste specific listing, closet, brand, category or search links, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Two ways to find data. Search mode covers keywords, brands and seller closets with filters applied. URL mode reads any listing, closet, brand, category or search link exactly as pasted.
- Sold listings with sold dates. Switch Availability to Sold (or All) to pull sold-out listings alongside their sold date and quantity sold, the site's own price-history surface.
- Seller closet profiles. Add a seller username or closet link and get that seller's follower, following and listing counts, followed by every listing in the closet.
- Detail enrichment on demand. Turn it on to add the seller's full aggregate stats, the complete photo set and the shipping note to each listing, billed only for listings that were actually read.
- Filters that are honest. Availability, department, condition, price range and shipping are narrowed on the site's own servers. Filters the site would silently ignore, like size or color, are not offered.
- Built for monitoring. Incremental mode returns only new, updated and reappeared listings on repeat runs, and a refused run fails loudly instead of returning an empty dataset.
- Resume large pulls. Paste a previous run or dataset ID to continue an interrupted pull without paying to re-collect records it already has.
Use Cases
- Resale sourcing and arbitrage: scan brand and keyword listings for underpriced items worth reselling.
- Price and market research: collect sold listings with their sold dates and last asking prices to see which similar items sell, and when.
- Closet and competitor tracking: monitor specific sellers' closets for new listings and price changes.
- Fashion trend analysis: build datasets of styles, brands, colors and conditions across departments and categories.
- Deal alerting: run Incremental mode on a saved search or brand to get only newly listed or price-changed items.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
kind | "listing" (also "seller" on closet profile records) |
recordId | "e1111111111111111111111a" |
listingId | "e1111111111111111111111a" |
url | "https://poshmark.com/listing/Sample-Wool-Coat-e1111111111111111111111a" |
title | "Sample Brand Co Wool Coat" |
brand | "Sample Brand Co" |
size / sizeDisplay / condition / conditionLabel | "M" / "US M" / "nwt" / "New With Tags" |
price | 40.0 (the listing's asking price; on sold listings, the last asking price, not the private accepted-offer amount) |
originalPrice | 120.0 |
currency | "USD" |
availability | "available" (also "sold", "coming soon") |
soldAt / soldQuantity | "2026-01-05T10:00:00-07:00" / 1 (sold listings only) |
department / category / colors / styleTags | "Women" / "Coats & Jackets" / ["Tan"] / ["Vintage"] |
description | "Barely worn wool coat, smoke-free home." |
likeCount / commentCount / shareCount | 12 / 2 / 4 |
sellerUsername / sellerName | "sample_seller" / "Sample Seller" |
pictureUrls | ["https://images.example.invalid/sample.jpg"] |
shippingNote | "$6.49 Shipping" (detail enrichment only) |
comments | [{"commentId", "text", "createdAt", "authorUsername", "authorName", "authorId"}] (detail enrichment only; first maxComments visible buyer comments, default 20, maximum 500) |
sellerFollowers / sellerFollowing | 500 / 40 (detail enrichment only) |
soldPrice / status / daysToSell | 32 / "sold_out" / 9 (soldPrice and daysToSell on sold listings only) |
nwt / boutique / likesCount / commentsCount / thumbnailUrl / scrapedAt | true / false / same values as likeCount / commentCount, a small cover image, and the scrape time (nwt needs the condition, present on search results) |
shippingCost / sellerLocation / sellerSoldCount / sellerAvgShipTime | 6.49 / "Austin, TX" / 1594 / 1.08 days (detail enrichment only; location only when the seller shows one) |
_enrichmentFailed | false (set only when detail enrichment is on; true means the page could not be read and the row is card-only) |
changeType / changedFields | "NEW" / [] (incremental mode only) |
Seller records (kind: "seller", one per closet scraped) carry username, displayName, closetUrl, bio, city, state, joinedAt, lastActiveAt and the same followers / following / likes / shares counts instead of listing fields.
How to Use
- Pick a mode:
search(keywords, brands and seller closets) orurl(paste specific links). - In search mode, add any combination of keyword searches, brands or closets, and apply the availability, department and condition filters. In URL mode, paste listing, closet, brand, category or search links.
- URL mode with the links field untouched now scrapes one example per shape instead of nothing: the default is 12 real poshmark.com links (brand, brand pinned to a department, keyword search, filtered search, category leaf, category department root, category with condition filter, seller closet, filtered and sorted brand, paginated
max_idbrand, listing slug link, bare 24-hex listing id). Replace them with your own links before running.m.poshmark.comlinks are read as poshmark.com; short links (posh.mk) and non-Poshmark links are skipped with a per-link warning in the log. - Set Max items to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Keyword search:
{"mode": "search","searchQueries": ["wool coat"],"maxItems": 20}
Sold listings from one brand, one department:
{"mode": "search","brands": ["Madewell"],"availability": "sold_out","department": "Women","maxItems": 50}
Watch a seller's closet for new listings:
{"mode": "search","closets": ["sample_seller"],"incrementalMode": true,"stateKey": "seller-watch"}
Paste a link, with detail enrichment on:
{"mode": "url","listingInputs": ["https://poshmark.com/brand/Madewell"],"fetchDetails": true,"maxItems": 10}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/poshmark-scraper").call(run_input={"mode": "search", "searchQueries": ["wool coat"], "maxItems": 20})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], item["price"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/poshmark-scraper').call({ mode: 'search', searchQueries: ['wool coat'], maxItems: 20 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How Max items shapes a run
Every target (a keyword, brand or closet) gets an even share of Max items. A target's own walk stops when its share is spent, or when it reaches the site's own end (an empty page, or no further page cursor), whichever comes first. Shares round down and a share one target leaves unused is not handed to the next, so a run can return fewer records than Max items. With closets, the seller record takes one slot of that closet's share. Detail enrichment reads one extra page per listing that is actually pushed and carries its own small surcharge; leave it off unless you need the seller's full stats, the complete photo set or the shipping note.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips every record id already collected there, so you don't pay twice. - Incremental mode (
incrementalMode) is for running the same search, brand or closet again and again, for example daily. Each record is classifiedNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEARED, orEXPIRED(only withemitExpiredon, and only after a run whose every target finished cleanly). When you turn onemitExpired, set Max items to0so every target is scanned to its end: listings a capped run never reached can otherwise be reported asEXPIRED. A listing isUPDATEDwhen any returned field changes (price, availability, title, description, photos, likes, shares, comment countcommentCount, seller details). These fields are always left out of the change check andchangedFieldsbut stay in the output: the nestedcommentslist (new buyer comments alone do not make a listingUPDATED),scrapedAt,_enrichmentFailed, and the derived copiessoldPrice,status,nwt,likesCount,commentsCount,thumbnailUrl,daysToSellandshippingCost(each repeats a field that is already compared). Add field names toignoreFieldsForChangesto leave noisy ones (such aslikeCount) out of the comparison andchangedFieldswhile keeping them in the output. A run that starts from a pasted link in the middle of a walk (amax_idorpagecursor) never reportsEXPIRED, because it covers only part of the tracked listings.stateKeynames or shares a monitoring campaign; leave it empty and the actor derives one automatically from your targets and filters. With incremental mode off, output is exactly as before.
Resume and Incremental mode solve two different problems: Resume continues one specific run that got interrupted, while Incremental mode is for scheduling the same search repeatedly and getting only what changed.
Output views
The dataset has four tabs. Results shows every listing and seller field. Listing details shows the enrichment fields (seller stats, photos, shipping, buyer comments). Changes shows changeType, changedFields and first and last seen times for incremental runs. Sellers shows closet profiles. A run summary is saved under the OUTPUT key of the run's key-value store.
Send results into your apps (MCP connectors)
Send results into the apps you already use via MCP connectors (Model Context Protocol). Authorize a connector under Apify, Settings, API & Integrations, then select it here: Notion gets a rich page per item, other connectors get a best-effort write. The export writes a condensed, human-readable summary per record (a title plus key fields), not the full JSON; the complete record always stays in the Apify dataset. Leave mcpConnectors empty to skip this entirely.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search for keywords, brands and closets, or url for pasted links. |
searchQueries | array | ["tote bag"] | Search mode: keywords to search, one entry per search. |
brands | array | (none) | Search mode: brand names or brand-page paths. |
closets | array | (none) | Search mode: seller usernames or closet links. Each emits the seller's profile followed by that closet's listings. |
availability | string | available | available, sold_out, or all. All availability includes dropping-soon items. |
department | string | (none) | Keep listings from one department only. Leave empty for all departments. |
condition | string | (none) | Keep listings in one condition tier only: New With Tags, Like New, Good, or Fair. |
brand | string | (none) | Search mode: one brand, same as adding one entry to brands. |
minPrice | number | (none) | Keep listings priced at or above this USD amount (whole dollars). Applied by the site. |
maxPrice | number | (none) | Keep listings priced at or below this USD amount (whole dollars). Applied by the site. |
shippingFilter | string | all | all, free, or discounted_free (free or discounted shipping). |
sortBy | string | relevance | relevance, newest (most recently listed first; the site has no sort by sale date, and a saved sold_recently value is read as newest), price_asc, price_desc, likes. |
listingInputs | array | 12 sample links, one per URL shape | URL mode: listing links or bare listing ids, closet links, brand links, category links or search links. |
urls | array | same 12 sample links | Alias for listingInputs, accepted under the name other Apify actors use. |
fetchDetails | boolean | false | Read each listing's own page and merge seller stats, the full photo set and the shipping note. Adds a per-listing surcharge when on. |
maxComments | integer | 20 | With detail enrichment on, how many visible buyer comments to keep per listing (maximum 500). |
maxItems | integer | 20 | Stop after this many records (0 = no limit). Sellers count as records too when closets are scraped. |
resumeFromRunId | string | (none) | Paste a previous run ID or dataset ID to continue a large pull without returning items already collected there. |
incrementalMode | boolean | false | Turn this on for daily or recurring monitoring. Returns only new, updated and reappeared records on repeat runs. |
stateKey | string | (none) | Optional. Name a monitoring campaign to keep its state stable, or share state across differently configured runs. |
emitUnchanged | boolean | false | Also return (and bill) records that have not changed since the last run. |
emitExpired | boolean | false | Also return (and bill) records no longer found, once a run has fully scanned every tracked target. Use with Max items 0. |
ignoreFieldsForChanges | array | (none) | Field names that should not make a listing count as UPDATED (for example likeCount). They stay in the output; they are left out of the change check and changedFields. |
mcpConnectors | array | (none) | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
proxyConfiguration | object | Apify Proxy | Connection settings. The default standard pool works; no special proxy group is required. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"kind": "listing","recordId": "e1111111111111111111111a","listingId": "e1111111111111111111111a","url": "https://poshmark.com/listing/Sample-Wool-Coat-e1111111111111111111111a","title": "Sample Brand Co Wool Coat","brand": "Sample Brand Co","brandPath": "Sample-Brand-Co","size": "M","sizeDisplay": "US M","condition": "nwt","conditionLabel": "New With Tags","price": 40.0,"originalPrice": 120.0,"currency": "USD","availability": "sold","soldAt": "2026-01-05T10:00:00-07:00","soldQuantity": 1,"department": "Women","category": "Coats & Jackets","colors": ["Tan"],"description": "Barely worn wool coat, smoke-free home.","likeCount": 12,"commentCount": 2,"shareCount": 4,"sellerUsername": "sample_seller","sellerName": "Sample Seller","sellerUrl": "https://poshmark.com/closet/sample_seller","pictureUrls": ["https://images.example.invalid/sample.jpg"]}
Plan Requirement
An Apify plan with proxy access is required: the site refuses plain connections from datacenter and cloud addresses often enough that the default proxy setting, a standard rotating pool, is what the actor is built around. It was not confirmed that a datacenter-only setup works, so do not rely on one. The actor retries automatically with a different connection profile and exit when one is refused. Refusals also come in short windows: after a burst of rapid requests the site can refuse everything for about two minutes, and a run that hits one can return fewer records than Max items or, if every request is refused, stop with a clear message (see the FAQ). On a free Apify plan, which has no proxy access, the run stops with a message saying a paid plan or your own proxy URLs are needed. Detail enrichment reads one extra page per listing and carries its own small surcharge, shown on the Pricing tab; leave it off unless you need the seller's full stats, the complete photo set or the shipping note.
FAQ
How much does it cost?
You pay per record returned (listing, sold listing or seller record): $0.002 on the Free plan, falling to $0.0014 on the Gold plan and above, so about $2 per 1,000 records on Free. Detail enrichment adds $0.0008 per listing on Free ($0.0007 Bronze, lower on higher plans), charged only for listings whose detail page was actually read and pushed. Unchanged, suppressed and failed records are never billed. The Pricing tab always shows the current rates. Use Max items to cap the cost of any run.
Is it legal to scrape Poshmark?
This actor collects only publicly available marketplace data. You are responsible for how you use it: follow Poshmark's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing details are generally facts, but photos and seller-submitted text may be subject to third-party rights.
Can I get only new or changed listings 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 records, and unchanged ones are not billed unless you turn on Emit unchanged.
What is the difference between Resume and Incremental mode?
They solve two different problems. Resume continues ONE specific run that got interrupted, using its run or dataset ID so you don't pay to re-collect what it already has. Incremental mode is for running the same search, brand or closet again and again, for example daily, and getting only what changed.
Why did my run fail instead of returning an empty dataset?
If every request the run made was refused or unreadable, the run ends as failed with a clear message ("Could not load any results page ... This is a connection problem, not an empty search", or a proxy-access message on plans without proxy) so "no matching listings" is never confused with "nothing could be read". The site sometimes refuses all requests for about two minutes after rapid pulls; wait a few minutes and run again. If only some targets or pages could be read, you still get what was found, and the run still succeeds.
Is the sold price what the buyer paid?
No. On sold listings price and soldPrice are the last asking price. Poshmark does not show the accepted-offer amount, so the real sale price can be lower.
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:
| π·οΈ ThredUp Scraper Scrape ThredUp resale listings by keyword, department, brand, size, condition, price or... | π·οΈ Vinted Multi-Country Scraper Scrape Vinted across 27 country marketplaces: keyword search with brand, price and... |
| β½ Whatnot Scraper Scrape Whatnot live and upcoming shows, queued items and lots, and seller profiles... | π KLEKT Sneaker & Apparel Resale Scraper Scrape sneaker and streetwear listings from KLEKT (klekt.com). Browse the catalog with... |
| π·οΈ Daangn Scraper From $1/1K. Scrape Daangn (λΉκ·Ό) marketplace listings by keyword and region. Returns 35+... | π·οΈ Kleinanzeigen.de Scraper From $1/1K. Scrape Kleinanzeigen.de ads by keyword, category, location, price, seller... |
π 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.