# Poshmark Listings Scraper (`axiomworks/poshmark-listings-scraper`) Actor

Scrape public Poshmark listings using search phrases or supported search, brand, and category URLs. Results include titles, brands, sizes, asking prices, seller names, likes, comments, and image URLs. Embedded page data provides listing records without a separate request for every item.

- **URL**: https://apify.com/axiomworks/poshmark-listings-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (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.79 / 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 Listings Scraper

**Returns:** one row per Poshmark listing with id, sourceUrl, title, price, currency, status, seller, and daysToSell.
**Input:** `{"searchQueries":["nike hoodie"],"maxItems":20}`
**Best for:** resale price comparisons, sold listing research, and public inventory datasets.

```json
{
  "id": "6abd5b1fadedd1ae8fbbdf56",
  "sourceUrl": "https://poshmark.com/listing/6abd5b1fadedd1ae8fbbdf56",
  "title": "Nike hoodie",
  "price": 8,
  "currency": "USD",
  "status": "sold_out",
  "seller": "dannielleweyer",
  "daysToSell": 3.9
}
```

This Poshmark scraper provides public listing data for Poshmark API workflows. The record above came from a local run of the input shown above.

### What does Poshmark Listings Scraper do?

Poshmark Listings Scraper collects public listing information from Poshmark search, brand, and category pages. Give it a search phrase such as `nike hoodie`, a public Poshmark search URL, or a brand or category URL. It reads the listing data included in the page, follows Poshmark's search cursor when more pages exist, and saves one dataset item for each unique listing. You can request sold listings, active listings, or both. The Actor does not require a Poshmark login.

The output is useful when comparing asking prices, examining a product category, or building a research dataset from publicly visible listings. For sold listings, the output includes the time when Poshmark's inventory status changed to sold out. The `daysToSell` value is calculated from that timestamp and the first publication timestamp. This is an estimate based on public page data. It is not a transaction record. In particular, `price` is the listing price visible in the search data; a private offer or negotiated final sale amount is not publicly established by this Actor.

The Actor runs as a batch job. It can traverse subsequent search pages until it reaches `maxItems`, runs out of pages, or finds no more eligible unique records. A single query may expose only a limited search depth, so narrower search phrases and filters can give more focused coverage. Search results and availability can change between runs as Poshmark updates its site.

### What data can you get?

Each dataset item represents one Poshmark listing. Empty optional values appear as `null` rather than invented values. The dataset schema permits nulls because sellers do not fill in every detail and search pages may omit some properties.

| Field | Meaning |
| --- | --- |
| `id` | Stable listing identifier used to remove duplicates within a run. |
| `sourceUrl` | Public listing URL associated with the item. |
| `title` | Listing title. |
| `price` | Listed price shown in search data. |
| `currency` | Currency code of that listed price. |
| `status` | Inventory status, such as `sold_out`. |
| `listedAt` | First publication timestamp from the listing object. |
| `createdAt` | Timestamp when the listing was created. |
| `comments` | Number of comments on the listing. |
| `soldAt` | Inventory status change timestamp when the item is sold out. |
| `daysToSell` | Difference between `soldAt` and `listedAt`, in days, rounded to one decimal. |
| `brand` | Brand text on the listing, when provided. |
| `size` | Size text on the listing, when provided. |
| `originalPrice` | Seller supplied original price, when available. |
| `condition` | Raw condition code supplied by Poshmark. |
| `department` | Catalog department display name. |
| `category` | Catalog category display name. |
| `seller` | Public seller username included in the search data. |
| `likes` | Listing like count. |
| `image` | Main listing picture URL. |

A zero original price is returned as null because the source does not provide a meaningful original price in that case. The condition field retains the site's short code rather than translating it into a potentially misleading description. Times include the UTC offset provided in the page data. `soldAt` and `daysToSell` are null for active listings.

### How to use

Open the Actor's input form in Apify Console. Enter one or more search phrases in Search queries. Choose `sold`, `active`, or `all` for availability, then set Maximum items to the number of unique listings you want to save. Run the Actor and open its dataset after the run finishes. The default input searches for sold Nike hoodies and asks for a small sample.

You can also pass a public Poshmark search, brand, or category URL in Start URLs. Existing URL filters are retained unless an input filter explicitly overrides them. The Actor validates the URL host and path before requesting the page. It accepts only HTTPS Poshmark target pages for this input. A malformed or unsupported URL fails input validation with a message explaining the accepted URL forms. A valid dead or blocked target saves no records and the Actor continues to the next target. A search phrase with no matches yields a warning and no placeholder records.

For multiple queries, the Actor collects them in input order and deduplicates listings by `id`. The `maxItems` limit applies across the whole run, not separately to each phrase. Search pages have a cursor; the Actor passes that cursor to the next page and stops if the site reports that no next page exists. It keeps request concurrency low and waits between requests. If a page is blocked or rate limited, the Actor retries with backoff and a fresh proxy session.

### Input

| Input | Description | Example |
| --- | --- | --- |
| `searchQueries` | Search phrases to look up. Supply this or `startUrls`. | `["nike hoodie"]` |
| `startUrls` | Public Poshmark search, brand, or category URLs. | `[{"url":"https://poshmark.com/brand/Nike"}]` |
| `availability` | `sold`, `active`, or `all`; defaults to `sold`. | `"sold"` |
| `brand` | Optional search brand filter. | `"Nike"` |
| `size` | Optional search size filter. | `"L"` |
| `department` | Optional department filter: Women, Men, Kids, Home, Pets or Electronics. | `"Men"` |
| `minPrice` | Optional lower price bound; listings below it are dropped. | `20` |
| `maxPrice` | Optional upper price bound; listings above it are dropped. | `100` |
| `maxItems` | Maximum unique results across the run, from 1 to 5000. | `20` |
| `proxyConfiguration` | Apify Proxy configuration. Residential proxy is the default. | `{"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}` |

Example input:

```json
{
  "searchQueries": ["nike hoodie"],
  "availability": "sold",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

The required target is a search phrase or start URL. Optional brand and size inputs are passed as search filters. Poshmark controls the meaning and supported values of those filters. `maxItems` is a hard output and charging limit: if seven eligible unique listings are available and you set seven, exactly seven are saved. If fewer exist, only the listings found are saved. If no eligible listings exist, the dataset stays empty.

The hidden `__verifySnapshots` input can be set to `true` for source verification. It saves the raw listing JSON for the first ten records to the key value store as `SNAPSHOTS`, keyed by listing ID and output field. This diagnostic option does not add dataset items.

### Output

The following item is from a local run using the sample sold query. It shows the shape of a real dataset item; live results may differ because listings and search order change.

```json
{
  "id": "6ab054e156502b35e0bba744",
  "sourceUrl": "https://poshmark.com/listing/6ab054e156502b35e0bba744",
  "title": "Nike White Hoodie with Black and Gold Logo",
  "price": 10,
  "currency": "USD",
  "status": "sold_out",
  "listedAt": "2026-09-20T14:55:16-07:00",
  "soldAt": "2026-09-20T15:20:22-07:00",
  "daysToSell": 0,
  "brand": "Nike",
  "size": "3XL",
  "originalPrice": 40,
  "condition": "ug",
  "department": "Men",
  "category": "Shirts",
  "seller": "lsilbe",
  "likes": 1,
  "comments": 0,
  "createdAt": "2026-09-20T14:50:02-07:00",
  "image": "https://di2ponv0v5otw.cloudfront.net/posts/2026/09/20/6ab054e156502b35e0bba744/m_6ab05545f00c5594759926fb.jpg"
}
```

The Actor writes one item at a time with the `result` event. The listing ID is stable enough to identify the same public listing across search pages in a run. The main image URL is returned as text; the Actor does not download or store image files. If your downstream workflow needs the picture, it can use that URL separately under the target site's applicable conditions.

### How much does it cost?

This Actor is charged per saved result. Set `maxItems` to cap both the number of dataset records and the number of result events for a run. Open the Actor's Pricing tab for the current terms. A run with zero saved listings has no result events. Retries and duplicate listings do not create extra result events, because charging is attached to each successful dataset push.

Proxy traffic and platform usage depend on your Apify account and run settings. Search pages can be relatively large, so narrower queries and a modest item limit can reduce run time. The Actor does not publish fixed price figures in this documentation because the Pricing tab is the current source for billing details.

### Use with AI agents (MCP)

Apify's MCP server can expose the Actor as a tool to compatible AI agents. Configure an MCP server using `https://mcp.apify.com/?tools=axiomworks/poshmark-listings-scraper` and authorize it with your Apify account in the client. The tool's input schema tells the agent which search phrases and limits to send, while the output schema describes the listing fields it can read.

Example prompt: “Find up to twenty public sold Nike hoodie listings and show their listed prices, sold timestamps, and days to sell.” Another prompt: “Collect active listings for levis 501 jeans and compare the title, size, brand, and listed price.” Ask the agent to keep the `maxItems` limit small when exploring a broad category. An agent should treat missing optional fields as missing data rather than filling them from intuition.

The MCP tool returns data produced by the Actor run. The timestamps and numeric fields are calculated or copied by the Actor from public search JSON; there is no third party AI enrichment in this Actor. This helps the agent distinguish observed listing values from its own interpretation of those values.

### Integrations and API

The dataset can be consumed in Apify Console, via Apify API, or through common integrations supported by the Apify platform. The examples below start a run with a small input. Replace `YOUR_APIFY_TOKEN` in your own environment; do not place a token in a public repository. The snippets use the Store path for this Actor.

Python example:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("axiomworks/poshmark-listings-scraper").call(run_input={
    "searchQueries": ["nike hoodie"], "availability": "sold", "maxItems": 20
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
```

JavaScript example:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('axiomworks/poshmark-listings-scraper').call({
  searchQueries: ['nike hoodie'], availability: 'sold', maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

cURL example:

```bash
curl -X POST 'https://api.apify.com/v2/acts/axiomworks~poshmark-listings-scraper/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"searchQueries":["nike hoodie"],"availability":"sold","maxItems":20}'
```

The run response contains a run ID and dataset reference. Read the finished run's default dataset to retrieve the listing items. For repeat research, save the input JSON alongside the run ID so you know which search filters produced a dataset. Because site content changes, the same input can produce a different dataset at a later time.

### FAQ

**Is `price` the amount the buyer paid?** No. It is the listed price in the public search data. Poshmark does not expose any private negotiated payment in this output. Treat it as an asking price, including for sold listings.

**What does `soldAt` mean?** It is the public inventory status change time for a sold out listing. It is the best timestamp available in the search item for this purpose, but it is not an independently verified payment timestamp. `daysToSell` uses this time and the first publication time.

**Why is `daysToSell` zero sometimes?** The calculation rounds to one decimal day. A listing that changes to sold out shortly after publication can therefore appear as zero. The source timestamps remain in `listedAt` and `soldAt` for more precise calculations.

**Why are some values null?** A search item may not contain a brand, condition, size, seller, image, or other optional attribute. The Actor does not guess values. Active listings also have no sold timestamp or days to sell value.

**Can I collect more than one query?** Yes. Add multiple phrases to `searchQueries`. The Actor processes them in order, removes duplicate IDs, and stops at the run-wide `maxItems` limit. If you need balanced samples for separate phrases, use separate runs with their own limits.

**Can I use an existing filtered URL?** Yes, if it is a public HTTPS Poshmark search, brand, or category page. The Actor retains URL filters and adds the availability, brand, and size controls specified in the input. Other hosts and unsupported URL paths are rejected before a request.

**Why might a run return zero records?** The query may have no matching public listings, a filter combination may be too narrow, or the site may have changed its search output. Review the final status and Actor log. Broaden the search, relax brand, size, department or price filters, or replace a dead URL with a public search or brand URL. If the log reports a persistent block, check your proxy settings and retry later. Successful targets still contribute records when another target fails.

### Is it legal to scrape Poshmark?

Public listing information can be accessed without logging in, but rules for collecting and using it depend on your jurisdiction, purpose, and Poshmark's current terms. You are responsible for evaluating those conditions for your use. This Actor does not access private accounts or private sale details. It uses modest request pacing and retries temporary blocks with backoff. It is an independent tool and is not affiliated with, endorsed by, or operated by Poshmark.

### Feedback

If a field becomes empty or a search page stops parsing, include a safe example input, the approximate run time, and the relevant error text when reporting the issue through the Actor's Apify Store feedback channel. Do not share access tokens or private account information. A report with the target URL and expected public field helps distinguish an input problem from a site data change. For data interpretation questions, specify whether the listing was active or sold and which timestamps or prices you compared.

# Actor input Schema

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

Search phrases as a string array, e.g. \["nike hoodie"]. Supply searchQueries, startUrls, or both; there is no automatic target for API calls. Default availability is sold. Targets run in order and share maxItems. Empty or blocked targets save no error rows; try a broader phrase or another public URL.

## `startUrls` (type: `array`):

Public HTTPS Poshmark search, brand or category URLs, e.g. \[{"url":"https://poshmark.com/brand/Levis"}]. Use URL objects in schema-validated calls. Supply this or searchQueries. Listing-detail URLs and listing IDs are unsupported. Availability overrides the URL availability; non-empty input filters override matching URL filters.

## `availability` (type: `string`):

Choose "sold" (default) for sold_out listings, "active" for listings not marked sold_out, or "all" for both. With all, sold listings get the first half of the remaining maxItems budget before active listings. Example: "active" for current asking prices.

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

Brand text sent to Poshmark search, e.g. "Nike". Default "" adds no brand filter and retains an existing URL brand parameter. A non-empty value overrides it. Filtering depends on Poshmark support; check returned brand values.

## `size` (type: `string`):

Size text sent to Poshmark search, e.g. "L" or "8". Default "" adds no size filter and retains an existing URL size parameter. A non-empty value overrides it. Size labels vary by category; check returned size values.

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

Choose "Women", "Men", "Kids", "Home", "Pets", or "Electronics", e.g. "Men". Default "" adds no department filter and retains a URL department parameter. A non-empty choice overrides it. Department filtering depends on Poshmark search support.

## `minPrice` (type: `number`):

Optional non-negative minimum listed price in USD, e.g. 20. Omit for no additional lower bound. Inclusive: listings below this value are excluded. Must be no greater than maxPrice when both are supplied. This is the public listed price, not a verified sale payment.

## `maxPrice` (type: `number`):

Optional non-negative maximum listed price in USD, e.g. 100. Omit for no additional upper bound. Inclusive: listings above this value are excluded. Must be at least minPrice when both are supplied. Tight price bounds can return zero records.

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

Maximum unique listings saved across all searchQueries and startUrls combined, 1-5000, default 50; e.g. 20 for a small sample or 1 for one result. Fewer are returned if matching pages run out, targets remain blocked, or the run reaches its spending limit. Duplicate IDs do not use the budget.

## `proxyConfiguration` (type: `object`):

Proxy settings for Poshmark requests, e.g. {"useApifyProxy":true,"apifyProxyGroups":\["RESIDENTIAL"]} (the existing default). Blocked or rate-limited requests retry with backoff on fresh proxy sessions. For direct local testing use {"useApifyProxy":false}; persistent blocks save no error records.

## Actor input object example

```json
{
  "searchQueries": [
    "nike hoodie"
  ],
  "startUrls": [],
  "availability": "sold",
  "brand": "",
  "size": "",
  "department": "",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchQueries": [
        "nike hoodie"
    ],
    "availability": "sold",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/poshmark-listings-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": ["nike hoodie"],
    "availability": "sold",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/poshmark-listings-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": [
    "nike hoodie"
  ],
  "availability": "sold",
  "maxItems": 20
}' |
apify call axiomworks/poshmark-listings-scraper --silent --output-dataset

```

## MCP server setup

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