# Poshmark Sold Listings Scraper (`solidcode/poshmark-scraper`) Actor

\[💰 $2.00 / 1K] Extract Poshmark sold listings and active listings — final sold price, sold date, days-to-sell, brand, size, condition, and seller username. The sold-comps data Poshmark hides, with brand, department, price, and condition filters.

- **URL**: https://apify.com/solidcode/poshmark-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** E-commerce, Automation, Other
- **Features:** Limited permissions
- **Stats:** 6 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 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?

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

## Poshmark Sold Listings Scraper

Pull real sold-comp data from Poshmark at scale — final sold prices, exact sold dates, and days-to-sell that Poshmark never shows you, plus brand, size, condition, colors, and seller handle on every row. Search many keywords in one run and get one clean row per listing, ready for a spreadsheet or your pricing model. Built for resellers, sourcing pros, and brand analysts who need accurate Poshmark sold comps without manually scrolling through closed listings one page at a time.

### Why This Scraper?

- **Real sold comps Poshmark hides** — every sold row carries the final sold price, the exact sold date, and a computed days-to-sell, the three numbers Poshmark removes from its public UI the moment an item sells.
- **Sold or active in one toggle** — flip `listingStatus` between sold comps (what items actually fetched) and live listings (what the current market is asking), instead of being locked to sold-only.
- **Multi-keyword batch search** — feed a whole product list into `searchQueries` and run every search in a single job; no one-keyword-per-run limit.
- **7 departments** — scope to Women, Men, Kids, Home, Pets, Electronics, or leave on All departments.
- **4 sort modes that hold across every keyword** — Most recent first, Price: low to high, Price: high to low, or Most liked, applied to the finished result set end to end rather than restarting at each keyword, so a 10-keyword job is one sorted list and not 10 stacked ones. Most recent first means the exact date each item changed hands on a sold run, so the top of your sheet is what the market paid this week, and the newest listings on an active run.
- **Brand-family filtering** — pass a single brand name (e.g. Nike, Coach) to scope results to that brand and its sub-labels, so "Nike" also pulls in Nike Air Jordan listings.
- **New-With-Tags-only filter** — narrow to brand-new, tagged inventory for deadstock and retail-arbitrage research.
- **Price-band filtering in USD** — set a `minPrice`, a `maxPrice`, or both to focus on a single price tier.
- **Live-show flyers, giveaways and bulk pallet lots filtered out** — Poshmark sellers post "listings" that are show flyers, giveaway notices, "unlisted inventory" placeholders priced up to the $50,000 ceiling, and pallet batches numbered 001 to 053 at one flat price that a seller creates and marks sold within seconds. On a designer-handbag search these can be 96% of what the site returns, and a single pallet burst took 18% of a dresses search. All of them are dropped automatically and replaced with real sales, so you never pay for a row you cannot price against — while genuine mystery boxes, clothing lots and items sold live during a show stay in.
- **Repeat copies of one item collapsed to a single comp** — Poshmark gives sellers a "copy listing" button, and one physical item comes back as several separate paid rows; measured across 15 sold searches it is 6% of rows and reaches 29% on watches. Matching copies are recognised by seller, photo, price and size together, then removed and replaced with genuinely different items, so your median is not dragged toward whatever one seller duplicated. Different sizes of the same style stay as the separate sales they are.
- **Fabricated retail prices removed** — sellers with no retail price to enter type filler into the box (999, 88888, 123456), and those land in the original-price column where they inflate every discount and resale-margin figure computed from it. Filler is detected by pattern and by how far it sits from the actual sold price, so a $19 dress no longer claims a $22,222 retail while a genuine $55,296 Birkin keeps its real number.
- **Full listing detail on every row, no extra step** — each result already carries the complete seller description, every listed color, style tags, Poshmark category, the like, comment, and share counts, the original retail price for sell-through math, the condition in Poshmark's own words (New With Tags, Boutique, Like New, Good, Fair, Pre-owned) so you can price a Good tee against a Like New one, and **every photo on the listing at full size — 7 per item on average, up to 16** — front, back, tags, flaws and all, not just the cover shot. No second lookup needed.

### Use Cases

**Reseller Pricing & Sourcing**

- Build a fresh sold-comp set for any item before you list, so you price to what actually sells.
- Measure days-to-sell across brands and price bands to find the fastest-moving inventory.
- Spot underpriced active listings to flip by comparing live asks against recent sold prices.

**Brand & Market Research**

- Track real resale values for a single brand across departments over time.
- Compare New-With-Tags sell-through against used-condition listings for the same product.
- Benchmark a brand's secondary-market pricing against its retail price using the original-price field.

**Inventory Valuation**

- Value a closet or consignment lot by pulling sold comps for each item and summing realistic exit prices.
- Audit which size and color combinations command a premium within a brand.

**Trend Analysis**

- Watch which styles, colors, and tags are selling fastest in a category.
- Quantify demand by sorting on Most liked and cross-referencing likes against sold dates.

### Getting Started

#### Simple — one keyword, sold comps

```json
{
  "searchQueries": ["Lululemon leggings"]
}
```

#### Filtered — one brand, New With Tags, price band

```json
{
  "searchQueries": ["Coach handbag"],
  "listingStatus": "sold",
  "brand": "Coach",
  "condition": "nwt",
  "minPrice": 50,
  "maxPrice": 300,
  "sortBy": "sold_recently",
  "maxResults": 500
}
```

#### Advanced — multi-keyword batch, full filters

```json
{
  "searchQueries": ["Nike Air Jordan 1", "Adidas Samba", "New Balance 990"],
  "listingStatus": "sold",
  "department": "men",
  "condition": "all",
  "minPrice": 80,
  "maxPrice": 600,
  "sortBy": "price_desc",
  "maxResults": 2000
}
```

### Input Reference

#### What to Search

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQueries` | array of strings | `["Lululemon leggings"]` | Keywords, brands, or phrases to look for. Add several entries to run multiple searches in one job. |
| `listingStatus` | string (select) | `sold` | `sold` for items that already sold (sold comps) or `available` for items still for sale. |

#### Filters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `department` | string (select) | `all` | One of All departments, Women, Men, Kids, Home, Pets, Electronics. |
| `brand` | string | *(empty)* | Return only items from this brand and its sub-labels (e.g. "Nike" also returns Nike Air Jordan). Leave empty to include every brand. |
| `condition` | string (select) | `all` | `all` for any condition or `nwt` for New With Tags only. |
| `minPrice` | integer | *(none)* | Only return items at or above this price in USD. |
| `maxPrice` | integer | *(none)* | Only return items at or below this price in USD. |
| `sortBy` | string (select) | `sold_recently` | Most recent first (newest sales on a sold search, newest listings on an active one), Price: low to high, Price: high to low, or Most liked. |

#### Options

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResults` | integer | `100` | Maximum listings to collect across all searches. With several keywords the limit is shared evenly between them, so every keyword contributes. Set to `0` for no limit. |
| `includePlaceholderListings` | boolean | `false` | Keep Live show flyers, giveaway notices, and bulk pallet or "unlisted inventory" placeholders in the results. Off by default so every row is a real item. |

### Output

Each listing is one flat row. Example sold-comp result:

```json
{
  "listingId": "65f1a2b3c4d5e6f7a8b9c0d1",
  "title": "Lululemon Align High-Rise Leggings 25\" Black Size 6",
  "brand": "lululemon athletica",
  "size": "6",
  "department": "Women",
  "category": "Pants & Jumpsuits",
  "colors": ["Black"],
  "description": "Excellent used condition, no pilling. Inseam 25\".",
  "condition": "not_nwt",
  "conditionLabel": "Pre-owned",
  "nwt": false,
  "soldPrice": 58.0,
  "originalPrice": 98.0,
  "status": "sold",
  "soldAt": "2026-05-28T14:21:09Z",
  "listedAt": "2026-05-10T09:03:44Z",
  "daysToSell": 18,
  "styleTags": ["align", "leggings"],
  "likesCount": 42,
  "commentsCount": 3,
  "shareCount": 7,
  "sellerUsername": "closetdeals22",
  "sellerName": "Jamie R.",
  "thumbnailUrl": "https://di2ponv0v5otw.cloudfront.net/posts/.../s_cover.jpg",
  "imageUrls": [
    "https://di2ponv0v5otw.cloudfront.net/posts/.../l_cover.jpg",
    "https://di2ponv0v5otw.cloudfront.net/posts/.../l_photo2.jpg",
    "https://di2ponv0v5otw.cloudfront.net/posts/.../l_photo3.jpg",
    "https://di2ponv0v5otw.cloudfront.net/posts/.../l_photo4.jpg",
    "https://di2ponv0v5otw.cloudfront.net/posts/.../l_photo5.jpg"
  ],
  "url": "https://poshmark.com/listing/65f1a2b3c4d5e6f7a8b9c0d1",
  "isPlaceholderListing": false,
  "scrapedAt": "2026-06-02T17:45:00Z"
}
```

#### Core Fields

| Field | Type | Description |
|-------|------|-------------|
| `listingId` | string | Poshmark listing identifier. |
| `title` | string | Listing title. |
| `brand` | string | Brand name as listed. |
| `size` | string | Item size with its size system. |
| `department` | string | Department the item is listed in. |
| `category` | string | Poshmark category for the item. |
| `colors` | array of strings | Colors listed on the item. |
| `description` | string | Full listing description. |
| `conditionLabel` | string | Condition in plain words, exactly as Poshmark shows it on the listing: `New With Tags`, `Boutique`, `Like New`, `Good`, `Fair`, or `Pre-owned`. Empty when the seller left the condition unset. |
| `condition` | string | Poshmark's own short condition tag behind `conditionLabel` (`nwt`, `ret`, `uln`, `ug`, `uf`, `not_nwt`), kept for anyone already matching on it. |
| `nwt` | boolean | Whether the item is New With Tags. |
| `styleTags` | array of strings | Style tags applied by the seller. |
| `url` | string | Full listing URL. |
| `isPlaceholderListing` | boolean | `true` when the listing is a Live show flyer, giveaway notice, or a bulk pallet / "unlisted inventory" placeholder rather than a real item. Always `false` unless you turn on `includePlaceholderListings`. |
| `scrapedAt` | string (ISO 8601) | When the row was collected. |

#### Pricing & Status

| Field | Type | Description |
|-------|------|-------------|
| `soldPrice` | number | The sold price on sold listings, the current asking price on active ones. The results table heads this column **Sold / Asking Price** so an active-listing run never reads as a completed sale; check `status` to tell the two apart. |
| `originalPrice` | number | Original retail price, or null when the seller did not enter one. |
| `status` | string | `sold` or `available`. |

#### Dates & Velocity

| Field | Type | Description |
|-------|------|-------------|
| `soldAt` | string (ISO 8601) | Date the item sold (sold listings only). |
| `listedAt` | string (ISO 8601) | Date the item was first listed. |
| `daysToSell` | integer | Days between listed and sold. |

#### Seller & Engagement

| Field | Type | Description |
|-------|------|-------------|
| `sellerUsername` | string | Seller handle. |
| `sellerName` | string | Seller display name. |
| `likesCount` | integer | Number of likes on the listing. |
| `commentsCount` | integer | Number of comments. |
| `shareCount` | integer | Number of shares. |

#### Media

| Field | Type | Description |
|-------|------|-------------|
| `thumbnailUrl` | string | Cover photo, small size — the image Poshmark shows on the search grid. |
| `imageUrls` | array of strings | Every photo on the listing at full size, cover shot first, one entry per photo. Averages 7 per listing and goes up to 16. |

### Tips for Best Results

- For pricing research, combine `listingStatus: sold` with `sortBy: sold_recently` to build the freshest possible comp set: the run walks backwards from the most recent sale, so a few hundred rows on a busy keyword usually covers the last day or two of trading, while a niche keyword reaches back weeks.
- Sold results top out at 5,000 per keyword. To dig deeper into a popular product, split the keyword by a `brand` or a tight `minPrice`/`maxPrice` band and run several focused searches instead of one broad one.
- Every row already carries the full description, colors, style tags, category, and like/comment/share counts — no extra step or setting is needed to get the complete listing detail.
- `imageUrls` holds the listing's whole photo set, so you can grade condition from the flaw and tag close-ups instead of the cover shot alone. Around 3% of listings are posted with a single photo, so treat a one-entry list as "seller only uploaded one", not as missing data.
- Compare `originalPrice` against `soldPrice` to measure how much of retail value a brand holds on the secondary market.
- Sort on `daysToSell` after a run to find which styles, sizes, and colors sell fastest, then prioritize sourcing those.
- Searching luxury categories like designer handbags? Live-show flyers priced near Poshmark's $50,000 ceiling dominate a Price: high to low sort. The run already drops them, but pairing a `maxPrice` with Most recent first keeps your comp set in the real market range.
- Sorting by Most recent first puts whatever sold in the last few hours at the very top, which is exactly where a seller's pallet burst lands. Those numbered flat-price batches are removed for you, so the first screen of a sold-comps export is real garments rather than one seller's inventory counter.
- Start with a `maxResults` of 50–100 to preview the shape of the data, then raise it once you are happy with your filters.
- Set `listingStatus: available` to size up the live market — how many comparable items are currently listed and at what asking prices — before deciding what to buy.

### Pricing

**From $2.00 per 1,000 results** — simple per-result pricing, undercutting comparable Poshmark tools. No compute or time-based charges — you pay per result, plus a small fixed per-run start fee. Bronze, Silver, and Gold subscribers pay progressively less; the table below shows total cost at each discount tier.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.24 | $0.23 | $0.21 | $0.20 |
| 1,000 | $2.40 | $2.25 | $2.10 | $2.00 |
| 10,000 | $24.00 | $22.50 | $21.00 | $20.00 |
| 100,000 | $240.00 | $225.00 | $210.00 | $200.00 |

A "result" is one listing row in your dataset. Apify platform usage fees are billed separately.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Trigger custom APIs on run completion
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This scraper collects publicly available listing data for legitimate research, pricing, and analytics purposes. You are responsible for using the collected data in compliance with Poshmark's terms of service, applicable laws, and any relevant data-protection regulations. Do not use the data to harass sellers, infringe intellectual property, or process personal data unlawfully. Always review the target site's terms before running large jobs.

# Actor input Schema

## `searchQueries` (type: `array`):

What to search for on Poshmark — a product, brand, or phrase. For example 'Nike Air Jordan 1', 'Lululemon leggings', or 'Coach handbag'. Add several keywords to run multiple searches in one go.

## `listingStatus` (type: `string`):

Whether to collect items that have already sold (great for pricing research and sold comps) or items still available for sale.

## `department` (type: `string`):

Limit results to one department, or leave on 'All departments' to search everything.

## `brand` (type: `string`):

Only return items from this brand (e.g. 'Nike', 'Coach'). Matches the whole brand family, so 'Nike' also returns sub-labels like Nike Air Jordan. Leave empty to include every brand.

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

Limit to brand-new items still carrying their tags, or include items in any condition.

## `minPrice` (type: `integer`):

Only return items at or above this price. Leave empty for no lower limit.

## `maxPrice` (type: `integer`):

Only return items at or below this price. Leave empty for no upper limit.

## `sortBy` (type: `string`):

How to order results. "Most recent first" gives you the newest sales when you search sold listings — rows arrive newest sale first, and each one shows how long it took to sell. On active listings it gives you the newest listings instead.

## `maxResults` (type: `integer`):

Maximum number of listings to collect across all searches. When you enter several keywords the limit is shared evenly between them, so every keyword contributes results. Set to 0 for no limit. Tip: start with 50-100 to preview, then increase.

## `includePlaceholderListings` (type: `boolean`):

Some Poshmark sellers post listings that are not real items: flyers advertising a Live show, giveaway notices, and bulk pallet or 'unlisted inventory' placeholders that are numbered in sequence at one flat price and marked sold within seconds. These are left out by default so your results are real sales you can price against. Genuine mystery boxes, clothing lots and items sold live during a show are always kept. Tick this to keep the placeholders too; every row carries an 'isPlaceholderListing' flag either way.

## Actor input object example

```json
{
  "searchQueries": [
    "Lululemon leggings"
  ],
  "listingStatus": "sold",
  "department": "all",
  "condition": "all",
  "sortBy": "sold_recently",
  "maxResults": 100,
  "includePlaceholderListings": false
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of scraped Poshmark listings with key fields.

# 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 = {
    "searchQueries": [
        "Lululemon leggings"
    ],
    "listingStatus": "sold",
    "department": "all",
    "condition": "all",
    "sortBy": "sold_recently",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/poshmark-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 = {
    "searchQueries": ["Lululemon leggings"],
    "listingStatus": "sold",
    "department": "all",
    "condition": "all",
    "sortBy": "sold_recently",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/poshmark-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 '{
  "searchQueries": [
    "Lululemon leggings"
  ],
  "listingStatus": "sold",
  "department": "all",
  "condition": "all",
  "sortBy": "sold_recently",
  "maxResults": 100
}' |
apify call solidcode/poshmark-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,solidcode/poshmark-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/cgf20G1REXd6uzCr6/builds/cAC0JDm1KqaUf6SQn/openapi.json
