# Rebag New Listings Scraper (Luxury Resale) (`superslowsloth/rebag-listings`) Actor

Rebag scraper: new pre-owned luxury listings from shop.rebag.com, newest first, filtered by brand (Louis Vuitton, Chanel, Hermes...) and publish time. One row per listing: USD price, availability, item number, type, tags, photo, timestamps. For luxury resale new-arrival alerts.

- **URL**: https://apify.com/superslowsloth/rebag-listings.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (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 $0.35 / 1,000 listing scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Rebag New Listings Scraper (Luxury Resale)

A **Rebag scraper** for new-arrival alerts on pre-owned luxury. It reads
[Rebag](https://shop.rebag.com)'s catalogue newest-published first and returns
one flat row per listing: title, brand (`Louis Vuitton`, `Chanel`, `Hermes`,
`Tiffany & Co.`), price in **USD**, whether it is still available, Rebag's item
number, product type, tags, photo and the minute it went live. Filter by brand
and by **publish time** (`24 hours`, `3 days`) and schedule it hourly to get a
**luxury resale new-listing alert** for the houses you collect.

No account, no API key, no login, no browser. One request returns 250 listings.
Rebag published 250 listings in about 12 hours at the head of its feed on
2026-10-17 (1,000 in about 53 hours), so a 24-hour window is roughly two
requests and an hourly run is one.

### Input

| Field | Notes |
|---|---|
| `brands` | Return only listings by these brands, spelled as Rebag spells them (`Louis Vuitton`, `Chanel`, `Hermes`, `Gucci`, `Tiffany & Co.`, `Cartier`, `Christian Dior`, `Saint Laurent`). Case and extra spaces are ignored; otherwise the match is exact. Leave empty for every brand. |
| `publishedAfter` | Return only listings that went live after this moment: a span back from now (`24 hours`, `3 days`, `90 minutes`, `1 week`), a date (`2026-10-17`, midnight UTC) or a date-time (`2026-10-17T12:00:00Z`, no offset means UTC). This is the listing's **publish time** (`published_at`), not the record's creation time (`created_at`), which is months older for a relisted item. On the whole catalogue the run stops at the first older listing. Leave empty for no cut-off. |
| `collections` | Rebag collections to read instead of the whole catalogue, one per line: the name from the address bar (`louis-vuitton`) or the link (`https://shop.rebag.com/collections/louis-vuitton`). A collection is in Rebag's own order, **not** newest first, so `publishedAfter` filters it but cannot stop early: the whole collection is read. For new listings by brand, prefer `brands` on the catalogue. A collection name that does not exist fails at no charge. |
| `maxItems` | Listings to return per collection, or for the whole catalogue (default 250, up to 25,000). 250 per page. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

Filtered listings are read but not returned and not charged, and do not count
toward `maxItems`.

Example input, new Hermes and Chanel listings from the last day:

```json
{
  "brands": ["Hermes", "Chanel"],
  "publishedAfter": "24 hours",
  "maxItems": 1000
}
```

Example input, everything listed since a date:

```json
{
  "publishedAfter": "2026-10-17",
  "maxItems": 5000
}
```

### Output

Prices are numbers in US dollars; `currency` is `USD` (the shop's own
`/meta.json` says so). A field the shop did not send is `null`, never `0` or `""`.

| Field | Notes |
|---|---|
| `query`, `position` | The shop URL (whole catalogue) or collection URL that first found the listing, and its place in that list (1 is newest on the catalogue, 250 per page). |
| `store` | `shop.rebag.com`. |
| `product_id`, `handle`, `url` | Shopify's product id (a string), the URL handle (it ends in Rebag's item number) and the listing link. |
| `title`, `vendor`, `product_type` | `Roman Stud Flap Bag Quilted Knit Medium`, `Valentino Garavani`, `Shoulder bags`. `vendor` is the luxury house. Null when empty. |
| `price` | The asking price. Each listing is one item, so `price_max` is the same number. |
| `original_price`, `original_price_max`, `on_sale`, `discount_percent` | Rebag sent no `compare_at_price` on any listing measured (25,000 of 25,000), so `on_sale` is false, `original_price` equals `price` and `discount_percent` is null. Rebag's tags `bc-filter-Up to 30% off` (3,599 listings) and `bc-filter-Clearance` (2,444) hint at markdowns but carry no price. The columns are kept because they would show a real reduction if Rebag starts sending one. |
| `available` | False when the feed marks the item not available (it can no longer be bought). About one in ten listings (2,446 of 25,000) was already unavailable when measured. |
| `variants` | One entry: `variant_id`, `title`, `sku` (Rebag's item number, `14490586` or `449971/1`), `price`, `compare_at_price` (null), `available`, `options`. `variant_count`, `available_variant_count` and `option_names` follow from it. |
| `published_at` | When the listing went live, ISO 8601 with the shop's offset (US Eastern). What the feed is ordered by and what `publishedAfter` compares against. |
| `created_at`, `updated_at` | When the record was created (older than `published_at` for a relisted item) and last changed (Rebag rewrites it in bulk, so it is not a price-change time). |
| `tags` | Rebag's own tags, as sent: 21 to 90 per listing (median 43), mostly storefront plumbing (`bc-filter-Excellent`, `new-arrivals`, `in-stock`, resale-channel names). |
| `image_url`, `image_count` | The first photo on cdn.shopify.com, as sent (null when there is none), and how many photos there are. |

Example row (real values, 2026-10-17, tags shortened):

```json
{
  "query": "https://shop.rebag.com",
  "position": 2,
  "store": "shop.rebag.com",
  "product_id": "9013474820273",
  "title": "Artsy Handbag Monogram Empreinte Leather MM",
  "handle": "handbag-louis-vuitton-artsy-handbag-monogram-empreinte-leather-mm-14490586",
  "url": "https://shop.rebag.com/products/handbag-louis-vuitton-artsy-handbag-monogram-empreinte-leather-mm-14490586",
  "vendor": "Louis Vuitton",
  "product_type": "All Bags",
  "tags": ["1000-to-2500", "bc-filter-Bags", "bc-filter-Hobos", "bc-filter-Very Good", "dust-bag"],
  "created_at": "2026-04-14T10:21:49-04:00",
  "published_at": "2026-10-17T15:05:09-04:00",
  "updated_at": "2026-10-17T15:56:59-04:00",
  "image_url": "https://cdn.shopify.com/s/files/1/0384/0161/files/AFG8859AKMHGGUJ5_1.jpg?v=1776176514",
  "image_count": 9,
  "currency": "USD",
  "price": 1865.0,
  "price_max": 1865.0,
  "original_price": 1865.0,
  "original_price_max": 1865.0,
  "on_sale": false,
  "discount_percent": null,
  "available": true,
  "variant_count": 1,
  "available_variant_count": 1,
  "option_names": ["Default Title", "Color"],
  "variants": [
    {
      "variant_id": "47209056469169",
      "title": "Very good | # 14490586 / pink",
      "sku": "14490586",
      "price": 1865.0,
      "compare_at_price": null,
      "available": true,
      "options": ["Very good | # 14490586", "pink"]
    }
  ]
}
```

(The tags are five of the 27 the listing carries, in the feed's order; the rest is as parsed
from the saved test fixture.)

#### Honest nulls and what is not here

- **Condition grade is not its own column.** Rebag writes it at the start of the
  variant's first option (`Excellent | Item # 144157430`, `Very good | #
  14490586`, `Great | Item # 449971/1`), in `variants[0].options[0]` and
  `variants[0].title`, and as a `bc-filter-<grade>` tag (`Pristine`,
  `Excellent`, `Great`, `Very Good`, `Fair`; at least one of the five is on
  24,953 of the newest 25,000 listings). The spelling is not uniform
  (`Very good` and `Very Good`), and older records put the product name in the
  first option instead (seen on 2023-2024 listings in collections), so it is
  left as sent rather than parsed into a column.
- **No reductions.** See `on_sale` above: `discount_percent` is null, never 0.
- **Not every record is a listing.** Now and then the feed carries an internal
  record with `vendor` `Rebag`, no photo, no tags and an empty `product_type`
  (one "Order ...: Item ... Payment" record in the newest 25,000). It is
  returned as sent and billed like any row; `brands` excludes it.
- **The oldest listings are out of reach.** See the 25,000 limit below.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.00035** per listing row written (`listing-scraped`), i.e. $0.35 per
  1,000 listings. A row that is not written is not charged: listings filtered
  by `brands` or `publishedAfter`, and repeats another collection already
  returned, are free.

### How it fetches

It reads `/products.json`, the public catalogue feed every Shopify shop serves
(and `/collections/<name>/products.json` for a collection). Measured
2026-10-18: HTTP 200 JSON, about 1.3 MB per 250 listings, no key or cookie
needed. A refusal (403, 429, 430, 5xx), a 200 that is not the feed, or a
dropped connection is treated as the address being blocked, and the actor
rotates to a fresh one and retries; one HTTP 500 with an empty body was seen
on page 100 and answered on the next try.

Things worth knowing, all measured:

- **Newest-published first.** `published_at` never increased down the feed
  (all 100 pages, 25,000 listings, back to 2026-09-17). `created_at` is not in
  order. That is why the cut-off is on `published_at`.
- **At most 25,000 listings per list.** Shopify refuses any page beyond
  `page * 250 = 25,000` with HTTP 400. Rebag has more than that (its brand
  collections alone: Louis Vuitton 15,021, Chanel 7,903), so an unfiltered
  run with no `publishedAfter` stops at the window and logs the list as
  capped. Listings older than the newest 25,000 (about a month, today) cannot
  be read by anyone through the feed.
- **Filters on the feed are ignored.** `?vendor=`, `?product_type=`, `?q=`,
  `?sort_by=`, `?order=` all return the same page as sending nothing, so brands
  are matched on the rows instead. Brand collections do filter (`louis-vuitton`:
  250 of 250 Louis Vuitton) but are not in date order. A brand run on the
  catalogue sees only that brand's listings from the newest 25,000.
- **An unknown collection looks empty.** The feed answers an unknown name with
  an empty list; the actor asks the collection's own record, and a name that
  does not exist fails instead of being reported as empty.
- **Only `shop.rebag.com` is read.** `www.rebag.com` is Rebag's marketing site
  and has no feed.

If Rebag changes its feed, the run fails with a message instead of returning
empty rows.

# Actor input Schema

## `brands` (type: `array`):

Return only listings by these brands, one per line, spelled as Rebag spells them (Louis Vuitton, Chanel, Hermes, Gucci, Tiffany & Co., Cartier). Matching ignores case and extra spaces but is otherwise exact. Other listings are read but not returned and not charged. Leave empty for every brand.

## `publishedAfter` (type: `string`):

Return only listings that went live on Rebag after this moment: a span back from now (24 hours, 3 days, 90 minutes, 1 week), a date (2026-10-16, midnight UTC) or a date-time (2026-10-16T12:00:00Z). This is the listing's publish time (published_at), not the record's creation time (created_at), which can be months older for a relisted item. On the whole catalogue the run stops at the first older listing, because Rebag's feed is newest-published first, so a short window is fast and cheap. Leave empty for no cut-off.

## `collections` (type: `array`):

Rebag collections to read instead of the whole catalogue, one per line: the name from the shop's address bar (louis-vuitton, chanel) or the whole link (https://shop.rebag.com/collections/louis-vuitton). A collection is in Rebag's own order, not newest first, so Published after filters it without stopping early. A collection with over 25,000 products (all-bags) can be read to 25,000 only. Leave empty to read the whole catalogue, newest first.

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

Return at most this many listings for the catalogue or for each collection. The feed holds 250 per page. Up to 25,000 are accepted, which is the most Shopify serves for any one list.

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

Use Apify's automatic datacenter proxy (the default). A refused request is retried from a fresh address.

## Actor input object example

```json
{
  "brands": [],
  "publishedAfter": "24 hours",
  "collections": [],
  "maxItems": 250,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "brands": [],
    "publishedAfter": "24 hours",
    "collections": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/rebag-listings").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 = {
    "brands": [],
    "publishedAfter": "24 hours",
    "collections": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/rebag-listings").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 '{
  "brands": [],
  "publishedAfter": "24 hours",
  "collections": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/rebag-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/rebag-listings"
        }
    }
}
```

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/og6Tl8nVxi5TKaP9e/builds/adFibukIfSXPSzW7k/openapi.json
