# Poshmark Scraper: New Listing & Price Drop Alerts (`accountable_eel/poshmark-listing-lookup`) Actor

Poshmark scraper for new listings, price drops, poshmark sold comps by brand, sell-through rate and days to sell, on poshmark.com and poshmark.ca. Price, euro price, size, condition, link. No login. Pay per listing.

- **URL**: https://apify.com/accountable\_eel/poshmark-listing-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 listing returneds

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 Scraper: New Listing & Price Drop Alerts

**Watch a search, get only what's new.** New listings and price drops since your last run, charged
per new row, free on quiet days. Schedule it hourly and send it to Discord, Slack, Google Sheets or
n8n.

This actor reads Poshmark the way you browse it: name a brand ("Coach"), a brand plus keywords
("Louis Vuitton: neverfull"), or paste a brand or category page with your own filters, pick
poshmark.com and/or poshmark.ca, and get one clean row per listing with the title,
price, a euro conversion, the seller's stated retail price, the price it was first listed at, brand,
size, condition, category, likes, the main photo and the link. Switch to sold listings for price
comps, or turn on monitoring and each run returns only the listings that appeared, or got cheaper,
since the previous run. No login.

### Who it's for

- **Resellers and luxury flippers** sourcing Coach, Louis Vuitton, Gucci or Lululemon before anyone
  else messages the seller. A watchlist on "Coach: tabby" under $150, run every hour, puts new
  listings in your Discord or Telegram without keeping the app open.
- **Sourcing agents and personal shoppers** watching a list of brands for clients in one run, in
  the US and Canada, with prices converted to euros for comparison.
- **Pricing a flip or a buy.** Sold listings (`listingType: sold`) show what a bag actually sold for
  and when, next to what it was first listed at: the comps you need before you bid or relist.
- **Alert-bot and n8n builders** who want a stable JSON row per listing instead of maintaining their
  own Poshmark parser.

### Why this one

- **Monitoring built in, not bolted on.** `deltaMode` remembers what each watchlist has seen per
  country. New listings and price drops (with your own minimum drop %) come back; everything else is
  removed before billing. A quiet run returns one summary row and costs only the start fee.
- **Poshmark's own price history in every row.** `firstListedPrice` is the price the listing was
  published at and `priceCutPct` the cut since then, so a one-off run already shows which sellers are
  dropping, even before monitoring has history.
- **US and Canada in one run.** One brand line runs on poshmark.com and poshmark.ca. Rows carry the country, the local currency and `priceEur` at the European Central
  Bank's daily reference rate.
- **Sold comps and live listings from one actor.** Available, sold or both, with `soldAt` on sold
  rows.
- **Seller privacy by default.** An anonymous seller hash lets you group listings by seller. No
  usernames, no names, no profile links, no contact details; descriptions have emails, phone numbers,
  @handles and chat links redacted.

### Countries

Brand lines run once per country you list in `countries`. A pasted Poshmark link always runs on its
own site.

| Code | Site | Currency |
|---|---|---|
| `us` | poshmark.com | USD |
| `ca` | poshmark.ca | CAD |

Minimum and maximum price apply in each site's own currency. `priceEur` converts every row at the
ECB rate of the day, so a cross-border comparison is one sort. poshmark.com.au is not offered yet:
it did not serve listings in testing, so `au` is ignored with a warning.

### What you get

By default each listing is its own row. Every row also repeats the search it came from.

| Field | What it is |
|---|---|
| `listingId`, `url`, `title` | Poshmark's listing ID, the listing link and its title |
| `price`, `currency` | The current price in the site's currency |
| `priceEur` | `price` in euros at the ECB daily reference rate |
| `originalPrice` | The retail price the seller entered (empty when they left it blank, on about 60% of listings) |
| `firstListedPrice`, `priceCutPct` | The price when the listing was first published, and the cut since then in % |
| `brand`, `size`, `condition`, `category`, `colors` | As shown on Poshmark; `condition` is New With Tags, Boutique, Like New, Good or Fair, and empty when the seller left it blank |
| `likeCount` | Likes so far |
| `availability`, `isSold`, `soldAt` | `available`, `sold_out` and so on; `soldAt` on sold rows |
| `soldPrice`, `daysToSell` | **Sold rows only.** The last asking price at the moment it sold (Poshmark never reveals a negotiated final price), and days from `postedAt` to `soldAt` |
| `postedAt`, `publishedAt` | When the listing was created, and when it was published (Poshmark's "Just In" order) |
| `sellerHash` | An anonymous 16-character seller hash |
| `imageUrl` | Link to the main photo (links only, nothing is downloaded) |
| `description` | The seller's description, contacts redacted (turn off with `includeDescription: false`) |
| `country` | Which Poshmark site the listing is on |
| `isNew`, `changeType`, `firstSeenAt` | Monitoring: `new`, `price-drop` or `seen`, and when this watchlist first saw it |
| `previousPrice`, `priceDropPct` | Monitoring: the price last seen and the drop in %, on price-drop rows |
| `searchQuery`, `searchCountries`, `listingCount`, `totalAvailable`, `truncated` | The search summary |
| `newCount`, `priceDropCount`, `monitorStatus` | Monitoring summary: `NEW_ROWS`, `NO_NEW_ROWS` or `SEEDED` |
| `activeCount`, `soldCount`, `sellThroughRate`, `compsWindowDays` | **Sold comps only.** How many active/sold listings this run fetched, the sell-through rate, and the day span the sold comps cover |
| `activeMedianPrice`, `soldMedianPrice`, `activeMedianPriceEur`, `soldMedianPriceEur`, `askVsSoldGapPct` | **Sold comps only.** Median asking/sold price, in the site's own currency and in EUR, and the gap between them |
| `medianDaysToSell` | **Sold comps only.** Median `daysToSell` across the sold comps fetched |

Three dataset views are ready in the Console: **Overview**, **Monitoring** (change type, previous
price and drop % next to each listing) and **Sold comps** (extended with the sell-through summary
columns and `soldPrice`/`daysToSell` — see below).

### Sold comps and sell-through

Turn on **"Include sold comps and sell-through stats"** and every search also fetches Poshmark's own
`sold_out` listings for the same brand/keywords and filters — up to "Max sold comps to fetch" (50 by
default, 200 max), per country. This runs regardless of what "Listings to include" is set to, so you
can keep searching "For sale" and still get comps alongside it. Each sold comp comes back as an
ordinary row: `isSold: true`, `soldAt`, `soldPrice`, and `daysToSell` (days from `postedAt` to
`soldAt`, when both are present). **Sold comps are listings too** — they're billed as ordinary
`listing` rows, at the same per-listing price as an available listing, not a separate event.

Every row of a search with sold comps on also carries sell-through summary columns, computed from
everything the run actually fetched (not just what's returned after any monitoring filter):
`activeCount` and `soldCount`, `sellThroughRate` (`soldCount / (soldCount + activeCount)`, 0-1, over
the window described by `compsWindowDays` — the span between the oldest and newest sold comp's
`soldAt`), `activeMedianPrice`/`soldMedianPrice` (the site's own currency) plus
`activeMedianPriceEur`/`soldMedianPriceEur`, the gap between the EUR pair as `askVsSoldGapPct`, and
`medianDaysToSell`. All ten are `null` when sold comps are off.

**Honesty notes.**

- **Poshmark shows the last asking price, not a negotiated final price.** `soldPrice` is whatever the
  listing's price was at the moment its status changed to `sold_out` — Poshmark's own data has no
  separate "amount actually paid" field, so a private offer accepted below (or a bundle discount
  applied at) checkout isn't reflected here.
- **Currency mix on a two-country search.** If "Poshmark countries to search" includes both `us` and
  `ca`, `activeMedianPrice`/`soldMedianPrice` mix USD and CAD amounts — use the
  `activeMedianPriceEur`/`soldMedianPriceEur` columns (and `askVsSoldGapPct`, which is always computed
  off the EUR pair) for a currency-safe comparison across countries.
- **Poshmark has no "recently sold" sort.** Unlike a dedicated sold-price index, the sold comps fetch
  uses whatever sort your search already uses (Just In / newest by default). Poshmark sellers commonly
  relist an item shortly before or after it sells, so some sold comps can show a `daysToSell` of 0 or
  close to it — that's a relisting artifact, not evidence every sale happens instantly. For a cleaner
  sample, run a broader brand/keyword search so more genuinely distinct sold items are captured.

Example: `{"searches": ["Coach"], "countries": ["us"], "includeSoldComps": true, "maxSoldComps": 100}`
returns available Coach listings plus up to 100 recent sold comps in the same run, with sell-through
and median-price-gap columns on every row.

**Related actors.** [`grailed-listing-lookup`](https://apify.com/accountable_eel/grailed-listing-lookup)
has the same sold-comps shape for Grailed, reading a real sold-price index (`sold_at desc`) rather than
a status filter on a keyword browse, so its comps window is not subject to Poshmark's relisting
caveat above.

### Monitoring: new listings and price drops

The recipe most buyers use:

1. Put your searches in `searches` ("Coach: tabby", "Louis Vuitton: speedy", or a pasted brand page
   with your size and condition filters), pick `countries`, and turn on **Only return listings that
   are new, or cheaper, since the last run** (`deltaMode`).
2. Optionally turn on **Seed silently** so the first run remembers today's listings without sending
   them all to your webhook.
3. Save it as a Task and add an hourly **Schedule** in Apify.
4. Add a webhook or integration on the Task for **Run succeeded**: Discord or Slack webhook,
   Telegram bot via n8n or Make, a Google Sheets append, or an HTTP call to your own bot. Each run's
   dataset holds only the new and price-drop rows.

```json
{
  "searches": ["Coach: tabby", "Louis Vuitton: neverfull"],
  "countries": ["us", "ca"],
  "category": "Women-Bags",
  "maxPrice": 400,
  "deltaMode": true,
  "skipFirstRun": true,
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 10
}
```

How it decides:

- **New** means this watchlist has never returned that listing ID before, on that country site.
- **Price drop** means the price is at least `minPriceDropPct` below the price last seen, on a
  listing that is still available. The remembered price updates every run, so a second cut is
  measured from the latest price.
- Unchanged listings are removed before you are billed. A run with nothing new returns one summary
  row with `monitorStatus: NO_NEW_ROWS`, `listingCount: 0`, and costs only the start fee.
- Each watchlist remembers up to 5,000 listings per country and search, oldest forgotten first.
- The watchlist name is derived from your price, category, condition and keyword filters, so two
  schedules with different filters never share a memory. Set `deltaName` to choose your own.

**The window limitation.** A run only sees the newest `maxListingsPerSearch` listings (48 by
default, one Poshmark page). A listing that drops in price after it has slid out of that window is
not seen again, so its price drop is missed. For price-drop alerts keep searches narrow (brand plus
model, a category, a price cap) or raise `maxListingsPerSearch`. For a busy brand on an hourly
schedule, 96 or more keeps new-listing alerts complete.

### Searches you can write

- `Coach`: every Coach listing, newest first.
- `Coach: tabby shoulder bag`: Coach listings matching those words (Poshmark's own keyword filter on
  the brand page).
- `Louis Vuitton: neverfull` with `category: Women-Bags`: narrowed to women's bags.
- A pasted link such as `https://poshmark.com/brand/Coach-Women-Bags?sort_by=added_desc&size[]=OS`
  or a `/category/...` page: every filter in the link is kept.

Write brands the way Poshmark does ("Louis Vuitton", "Michael Kors", "Tory Burch"). Poshmark asks
crawlers not to use its `/search` pages, so this actor reads brand and category pages only; a
pasted `/search` link that names exactly one brand is rewritten to that brand's page, and any other
`/search` link is reported as a free `BAD_FORMAT` row with this explanation.

### Price

- **Listing returned**: $3 per 1,000 listings

Plus a $0.00005 start fee per run. Each event above is billed independently, only when it actually returns data — misses (`found:false`) are never charged.

- **Listings:** $3 per 1,000 listings returned, plus a $0.00005 start fee per run.
- A monitoring run with nothing new costs the start fee only. A search that returns nothing, or a
  country that fails, is never billed.

An hourly watchlist on one search that finds 5 new listings an hour costs about 5 x 24 x 30 = 3,600
listings, **about $11 a month**.

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `searches` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~poshmark-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"searches":["Coach: tabby"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

Tips:

- Paste a link from Poshmark when you need filters the input doesn't list (size, colour, a
  sub-category, shipping discounts). Everything in the link is kept; monitoring only forces the Just
  In order.
- `conditions` keeps only the codes you list (`nwt`, `ret`, `uln`, `ug`, `uf`), applied while paging,
  so the actor reads further pages until it has enough matches.
- `includeKeywords` and `excludeKeywords` match the title, brand, size, category and description
  before billing, so "replica" or "dust bag only" in `excludeKeywords` never costs you a row.

### Input

```json
{
  "searches": [
    "Coach: tabby"
  ]
}
```

One search per line: a brand such as "Coach", a brand plus keywords such as "Louis Vuitton: neverfull", or a brand or category page link copied from poshmark.com or poshmark.ca (its own filters such as size, condition and price are kept). Brand lines run once in every country you pick below; a pasted link runs on its own site. No login required. Accepted formats: Coach: tabby, Louis Vuitton: neverfull, https://poshmark.com/brand/Coach-Women-Bags?sort\_by=added\_desc.

### Sample output

| query | found | status | searchQuery | searchCountries | listingCount | totalAvailable | truncated | newCount | priceDropCount | monitorStatus | activeCount | soldCount | sellThroughRate | compsWindowDays | activeMedianPrice | soldMedianPrice | activeMedianPriceEur | soldMedianPriceEur | askVsSoldGapPct | medianDaysToSell | listings | listingId | title | price | currency | priceEur | originalPrice | firstListedPrice | priceCutPct | brand | size | condition | category | colors | likeCount | availability | isSold | country | postedAt | publishedAt | sellerHash | imageUrl | url | isNew | changeType | firstSeenAt | description | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Coach: tabby | true | OK | <search> | <countries searched> | <listings returned> | \<matching on poshmark (5000 = 5,000 or more per country)> | \<more listings were available (or a country failed)> | <new since last run> | <price drops since last run> | <monitoring status> | \<active listings fetched this run (sold comps only)> | \<sold comps fetched this run (sold comps only)> | \<sell-through rate: sold / (sold + active) (sold comps only)> | \<span of the fetched sold comps, oldest to newest sale (sold comps only)> | \<median asking price, local currency (sold comps only)> | \<median sold price, local currency (sold comps only)> | \<median asking price, eur (sold comps only)> | \<median sold price, eur (sold comps only)> | \<asking vs. sold median price gap %, computed in eur (sold comps only)> | \<median days from posted to sold (sold comps only)> | \<all listings found (full list)> | <poshmark listing id> | <title> | \<price (local currency)> | <currency> | \<price in eur (ecb daily rate)> | \<original retail price (as the seller states it)> | <price when first listed> | \<cut since first listed (%)> | <brand> | <size> | <condition> | <category> | <colours> | <likes> | \<availability (available / sold\_out / ...)> | <sold> | <poshmark country> | <created at> | \<published at (just in order)> | <anonymous seller id> | <main photo> | <listing link> | \<is this listing new?> | \<change (new / price-drop / seen)> | <first seen on a run> | \<description (contacts redacted)> | 1970-01-01T00:00:00.000Z |

A real row from a `Coach` brand page on poshmark.com (2026-09-22), trimmed:

```json
{
  "searchQuery": "Coach",
  "searchCountries": "us",
  "listingId": "6ab28124d48e7e00053f7924",
  "url": "https://poshmark.com/listing/Vintage-Coach-Slim-Legacy-Duffle-Leather-03-Bag-In-Blue-9328-6ab28124d48e7e00053f7924",
  "title": "Vintage Coach Slim Legacy Duffle Leather 03  Bag In Blue #9328",
  "price": 180,
  "currency": "USD",
  "priceEur": 156.66,
  "originalPrice": 212,
  "firstListedPrice": 180,
  "brand": "Coach",
  "size": "OS",
  "category": "Women > Bags > Shoulder Bags",
  "availability": "available",
  "isSold": false,
  "publishedAt": "2026-09-22T13:22:52.000Z",
  "sellerHash": "7aa4f97c321985cb",
  "country": "us"
}
```

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~poshmark-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"searches":["Coach: tabby"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~poshmark-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"searches":["Coach: tabby"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~poshmark-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"searches":["{{search}}"]}`, mapping the row's search into the `searches` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Poshmark Scraper: New Listing and Price Drop Alerts" — the agent will find and run this actor.

**Discord or Slack alerts without code.** Schedule the monitoring Task hourly, then add an
integration on the Task: in n8n or Make, trigger on "Apify: run succeeded", read the run's dataset,
skip rows where `listingCount` is 0, and post `title`, `price`, `currency`, `size` and `url` to a
Discord or Slack webhook (or a Telegram bot node). Google Sheets users can append the same rows to a
sheet for a running price log.

### vs. alternatives

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** | $3 per 1,000 listings, quiet monitoring runs free | US and Canada in one run, euro prices, first-listed price and cut %, sold comps, built-in new-listing and price-drop monitoring | Brand and category pages only (Poshmark's robots.txt excludes /search) |
| Other Poshmark scrapers on the Apify Store | Pay per result | Search results or sold listings, usually one site per run | The most used has 14 users a month; none combines monitoring with sold comps and two countries, so you rebuild "what's new" yourself |
| Poshmark's own saved searches | Free | Push notifications in the app | Only on your phone, no export, no Sheets, no bot, no price history |

Store figures as of September 2026.

### Data & privacy

**Data & privacy.** This actor reads public search results that anyone can see without logging in. It
doesn't log in, solve CAPTCHAs or reveal hidden contact details. Seller identity is off by default: you
get an anonymous seller hash so you can group listings by seller without names. Turning on seller info
makes you responsible for having a lawful reason to process it. Not affiliated with Poshmark.

Poshmark shows every seller's username and name on each listing; this actor never reads either.
Descriptions have emails, phone numbers, @handles and chat links replaced with `[redacted]`, and only
the main photo link is returned. Nothing is downloaded.

### FAQ

**Is this allowed?**
It collects the same public listing data your browser shows, for the searches you
choose. It's built for monitoring a search, not for copying the marketplace. Check that your use fits
Poshmark's terms and your local law.

**Why did my monitoring run return nothing?**
Nothing new or cheaper appeared since the last run. You get one row with `monitorStatus:
NO_NEW_ROWS` and are charged only the start fee. On the very first run with "Seed silently" on, the
status is `SEEDED`.

**Why can't I type free keywords without a brand?**
Poshmark's robots.txt asks crawlers not to use its `/search` pages, and this actor respects that. Its
brand and category pages carry the same listings and accept keywords, so start the line with a brand
("Coach: tabby"), or paste a category page link.

**What does `totalAvailable` mean?**
Poshmark's own count for the page. It reads 5,000 on broad pages, meaning 5,000 or more.

**Why is `truncated` true?**
More listings were available than `maxListingsPerSearch`, or a country site refused the run partway
(the listings collected up to then are delivered and billed; nothing else is).

**Can I get the seller's username?**
No. Usernames and names are deliberately never returned. Turn on "Include the raw Poshmark seller ID"
only if you have a lawful reason to process it.

**What do I need to set up?**
Nothing. No Poshmark account, no cookies, no proxy settings.

**Can an AI agent call this?**
Yes, through the Apify MCP server or the API call shown above. Ask for "Poshmark Scraper: New
Listing and Price Drop Alerts".

**Is `soldPrice` the actual amount the buyer paid?**
No — see "Sold comps and sell-through" above. Poshmark only exposes the listing's last asking price
at the moment it sold, never a negotiated final amount.

### Related actors

- [Vinted Scraper: New Listing & Price Drop Alerts](https://apify.com/accountable_eel/vinted-listing-lookup):
  the same watchlist shape across 22 European Vinted sites.
- [Grailed Scraper: Sold Prices & New Listings](https://apify.com/accountable_eel/grailed-listing-lookup):
  menswear and streetwear, with sold-price comps.
- [Mercari Japan Scraper](https://apify.com/accountable_eel/mercari-jp-listing-lookup): Japan's
  largest flea market, with sold prices.
- Coming in the same resale series: 1stDibs, Selency, Pamono and Chairish scrapers for design and
  vintage furniture.

# Actor input Schema

## `searches` (type: `array`):

One search per line: a brand such as "Coach", a brand plus keywords such as "Louis Vuitton: neverfull", or a brand or category page link copied from poshmark.com or poshmark.ca (its own filters such as size, condition and price are kept). Brand lines run once in every country you pick below; a pasted link runs on its own site. No login required. Accepted formats: Coach: tabby, Louis Vuitton: neverfull, https://poshmark.com/brand/Coach-Women-Bags?sort\_by=added\_desc. You're only charged for the ones we actually find — a miss costs nothing.

## `countries` (type: `array`):

One country code per line: us (poshmark.com, USD) or ca (poshmark.ca, CAD). Brand lines run once in each; prices come back in each site's own currency plus a euro conversion. Ignored for pasted links, which use their own site. Leave empty for us.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `category` (type: `string`):

Optional. A Poshmark department and category as it appears in brand page links, for example Women-Bags, Women-Shoes, Men-Jackets\_&\_Coats or Women. "Coach" then reads poshmark.com/brand/Coach-Women-Bags. Ignored for pasted links.

## `sort` (type: `string`):

Poshmark's own sort options. Forced to Just In whenever monitoring is on, so every run compares the same ordering. A pasted link keeps its own sort unless monitoring is on.

## `listingType` (type: `string`):

Sold listings show what an item actually sold for: useful for pricing a flip or a buy. A pasted link keeps its own availability filter.

## `maxListingsPerSearch` (type: `integer`):

Poshmark shows 48 listings per page; the actor follows its next-page cursor up to 1,000 per search per country. You pay per listing returned, so this is also your budget control.

## `includeSoldComps` (type: `boolean`):

Off by default. When on, this search also fetches Poshmark's own sold\_out listings for the same brand/keywords and filters, returns each sold comp as an ordinary listing row (isSold, soldAt, soldPrice, daysToSell), and adds sell-through summary columns (activeCount, soldCount, sellThroughRate, activeMedianPrice/Eur, soldMedianPrice/Eur, askVsSoldGapPct, medianDaysToSell) to every row of this search. Sold comps are billed as ordinary listings — see "Sold comps and sell-through" in the README.

## `maxSoldComps` (type: `integer`):

Only used when "Include sold comps" is on. Caps how many sold listings this search fetches for comps, per country. Max 200.

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

Optional. Sent to Poshmark as its own price filter and re-checked on every row, in each site's currency (dollars on poshmark.com, Canadian dollars on poshmark.ca).

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

Optional. Sent to Poshmark as its own price filter and re-checked on every row. Leave empty for no maximum.

## `conditions` (type: `array`):

Optional. One code per line: nwt (New With Tags), ret (Boutique), uln (Like New), ug (Good), uf (Fair), wlsl (Wholesale). Listings whose seller left the condition blank are dropped when this is set. Applied while paging, so the actor reads further pages until it has enough matches.

## `deltaMode` (type: `boolean`):

Turns a search into a watchlist. A listing is new when its Poshmark listing ID was not returned by a previous run of the same watchlist, and a price drop when its price fell by at least the percentage below since it was last seen. Unchanged listings are removed before you are billed, so a quiet run only costs the start fee and returns one summary row. Schedule it hourly and send the results to Discord, Slack, Telegram, Google Sheets or n8n.

## `deltaName` (type: `string`):

Leave empty and one is derived from this run's filters, so two schedules with different filters keep separate memories. Type your own name to keep one memory across a filter change. Naming a watchlist with the checkbox above off returns every listing but still marks each one new / price-drop / seen.

## `alertOnNew` (type: `boolean`):

With monitoring on, return listings this watchlist has never seen before.

## `alertOnPriceDrop` (type: `boolean`):

With monitoring on, return listings already seen whose price has dropped since the last sighting. Sold listings never count as a price drop.

## `minPriceDropPct` (type: `integer`):

A listing must be at least this much cheaper than when it was last seen to count as a price drop.

## `skipFirstRun` (type: `boolean`):

The first run of a watchlist has nothing to compare with. Turn this on to remember everything it finds without returning or billing it, so a webhook does not get a hundred messages on day one. Alerts start from the second run.

## `includeDescription` (type: `boolean`):

On by default: the seller's description as shown on the listing, with emails, phone numbers, @handles and chat links replaced by \[redacted]. Turn off for smaller rows.

## `includeSellerInfo` (type: `boolean`):

Off by default. Every row already carries an anonymous seller hash, so you can group listings by seller without knowing who they are. Turning this on adds Poshmark's internal seller ID (sellerId); you then need a lawful reason to process it. Usernames and names are never returned.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each listing found gets its own row instead of being grouped under its search. You're still only charged once per search, no matter how many rows it produces.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

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

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "searches": [
    "Coach: tabby"
  ],
  "countries": [
    "us"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "category": "",
  "sort": "newest",
  "listingType": "available",
  "maxListingsPerSearch": 48,
  "includeSoldComps": false,
  "maxSoldComps": 50,
  "conditions": [],
  "deltaMode": false,
  "deltaName": "",
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 5,
  "skipFirstRun": false,
  "includeDescription": true,
  "includeSellerInfo": false,
  "columns": [
    "searchQuery",
    "searchCountries",
    "listingCount",
    "totalAvailable",
    "truncated",
    "newCount",
    "priceDropCount",
    "monitorStatus",
    "activeCount",
    "soldCount",
    "sellThroughRate",
    "compsWindowDays",
    "activeMedianPrice",
    "soldMedianPrice",
    "activeMedianPriceEur",
    "soldMedianPriceEur",
    "askVsSoldGapPct",
    "medianDaysToSell",
    "listings",
    "listingId",
    "title",
    "price",
    "currency",
    "priceEur",
    "originalPrice",
    "firstListedPrice",
    "priceCutPct",
    "brand",
    "size",
    "condition",
    "category",
    "colors",
    "likeCount",
    "availability",
    "isSold",
    "country",
    "postedAt",
    "publishedAt",
    "sellerHash",
    "imageUrl",
    "url",
    "isNew",
    "changeType",
    "firstSeenAt",
    "description"
  ],
  "expandRows": true,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "searches": [
        "Coach: tabby"
    ],
    "countries": [
        "us"
    ],
    "includeKeywords": [],
    "excludeKeywords": [],
    "conditions": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/poshmark-listing-lookup").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 = {
    "searches": ["Coach: tabby"],
    "countries": ["us"],
    "includeKeywords": [],
    "excludeKeywords": [],
    "conditions": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/poshmark-listing-lookup").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 '{
  "searches": [
    "Coach: tabby"
  ],
  "countries": [
    "us"
  ],
  "includeKeywords": [],
  "excludeKeywords": [],
  "conditions": []
}' |
apify call accountable_eel/poshmark-listing-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/poshmark-listing-lookup"
        }
    }
}
```

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/GzkfCVTArflp5ge2J/builds/0gWMTejO7DuF9Dd7i/openapi.json
