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

Selency scraper by keyword: French vintage furniture and decor with price, material, style and dealer info, plus new-listing and price-drop alerts. No login required. Pay per listing; misses and quiet runs are free.

- **URL**: https://apify.com/accountable\_eel/selency-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

## Selency 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 searches Selency, France's vintage furniture and decor marketplace, the way you would in
your browser: type keywords in French (or any language) or paste a category link, and get one row
per listing with the title, price in euros, material, style, category, the main photo and the link.
Turn on monitoring and each run returns only the listings that appeared, or got cheaper, since the
previous run.

### Who it's for

- **Dealers and sourcing agents** hunting vintage pieces on the French market who lose good finds to
  whoever refreshes the page fastest. A watchlist on "commode scandinave" or "fauteuil vintage", run
  every hour, puts new listings in your Discord or Telegram without keeping a tab open.
- **Interior designers** researching what a style or material genuinely costs on the French vintage
  market right now.
- **Resellers** who want a price-check before they flip a piece, or a running log of a keyword's
  price movement.
- **Bot and workflow builders** who are tired of maintaining their own scraper each time Selency
  changes its site. You get a stable JSON row per listing and keep your own logic.

### Why this one

- **Free-text French keyword search**, not a fixed category list — search exactly the way a Selency
  buyer does ("chaise scandinave", "vaisselle Digoin", "luminaire art deco"). A pasted
  `selency.fr/c/<category>` link also works.
- **Monitoring built in, not bolted on.** `deltaMode` remembers what each watchlist has seen. 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.
- **Dealer transparency.** Selency mixes professional dealers and private sellers; `sellerType` tells
  you which, straight from Selency's own seller flag. You get an anonymous seller hash to group
  listings by seller without a name.
- **Material and style, not just price.** Selency tags most listings with a material (bois, teck,
  laiton...) and a style (scandinave, art déco, vintage...) — useful filters for a design-focused
  search that a plain keyword match would miss.

### 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` | Selency's listing ID, the listing link and its title |
| `price`, `currency` | The price in euros |
| `category`, `material`, `style` | Selency's own tags, in French, when it shows them |
| `isDiscounted`, `discountPct` | Selency's own discount flag and percentage (its own permanent record, independent of this actor's monitoring) |
| `postedAt` | When the listing was published |
| `imageUrl` | Link to the main photo (links only, nothing is downloaded) |
| `country` | The seller's country |
| `sellerType`, `sellerHash` | `pro` or `private`, and an anonymous 16-character seller hash |
| `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`, `listingCount`, `totalAvailable`, `truncated` | The search summary |
| `newCount`, `priceDropCount`, `monitorStatus` | Monitoring summary |

Not in this actor: a structured condition grade. Selency is a 100% pre-owned/vintage marketplace (no
listing sampled during this build carried anything but "used"), so there is no varying condition
signal worth a column — every item is, by definition, a used/vintage piece.

### Monitoring: new listings and price drops

The recipe most buyers use:

1. Put your search in `searches` (keywords, or paste a Selency category link), 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.

```json
{
  "searches": ["commode scandinave"],
  "maxPrice": 800,
  "deltaMode": true,
  "skipFirstRun": true,
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 10
}
```

How it decides:

- **New** means this watchlist has never returned that listing ID before.
- **Price drop** means the euro price is at least `minPriceDropPct` below the price last seen. The
  remembered price updates every run, so a second cut is measured from the latest price. This is
  independent of Selency's own `isDiscounted`/`discountPct` flag, which is always included either way.
- 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, oldest forgotten first.

**The window limitation.** A run only sees the newest `maxListingsPerSearch` listings (60 by
default). A listing that drops in price after it has slid out of that window is not seen again. For
price-drop alerts keep searches narrow or raise `maxListingsPerSearch`.

**France only.** This actor reads Selency's `.fr` site and its FR search index. Selency also runs
`.co.uk` and `.nl` sites; those are not covered by this actor.

### Price

- **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 is never
  billed.

### 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~selency-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"searches":["chaise scandinave"]}'
   ```
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:

- Search in French for the best coverage ("commode" not "dresser") — Selency's own catalog is French,
  and Algolia's text match favors the listing's own language.
- `includeKeywords`/`excludeKeywords` match the title, category, material and style before billing, so
  "reproduction" in `excludeKeywords` never costs you a row.
- `minPrice`/`maxPrice` filter on Selency's own current price (after any discount), applied inside the
  search itself, not after.

### Input

```json
{
  "searches": [
    "chaise scandinave"
  ]
}
```

One search per line — any French (or other) keywords, e.g. "chaise scandinave", "commode vintage", "luminaire art deco". A pasted selency.fr category link (.../c/<category>) also works. No login required. Accepted formats: chaise scandinave, commode vintage, https://www.selency.fr/c/meubles.

### Sample output

| query | found | status | searchQuery | listingCount | totalAvailable | truncated | newCount | priceDropCount | monitorStatus | listings | listingId | title | price | currency | category | material | style | isDiscounted | discountPct | postedAt | imageUrl | country | sellerType | sellerHash | sellerId | sellerName | changeType | isNew | previousPrice | priceDropPct | firstSeenAt | url | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| chaise scandinave | true | OK | <search> | <listings returned> | <total matching on selency> | <more results were available> | <new listings this run> | <price drops this run> | \<monitoring status (quiet / seeded runs)> | \<all listings found (full list)> | <selency listing id> | <title> | \<price (eur)> | <currency> | \<category (selency's own, in french)> | \<material, when selency shows one> | \<style, when selency shows one> | \<selency's own discount flag> | \<selency's own discount %> | \<posted (published)> | <image> | \<seller's country> | \<seller type (pro / private)> | <anonymous seller hash> | \<seller/shop id (raw seller info only)> | \<seller name (raw seller info only)> | \<new / price-drop / seen> | \<is this listing new?> | \<previous price seen by this monitor (eur)> | \<price drop % (this monitor)> | <first seen on a run> | <listing link> | 1970-01-01T00:00:00.000Z |

A real row from a `chaise` run (2026-09-22), trimmed:

```json
{
  "searchQuery": "chaise scandinave",
  "listingCount": 5,
  "totalAvailable": 26378,
  "listingId": "c34367ffb890396b9d9b3c9191410868",
  "url": "https://www.selency.fr/p/CDY21CVC/chaises-longues-en-cuir-de-style-mid-century-par-burkhard-vogtherr-pour-rosenthal-annees-1970",
  "title": "Chaises longues en cuir de style mid-century par Burkhard Vogtherr pour Rosenthal, années 1970.",
  "price": 1099,
  "currency": "EUR",
  "category": "S'asseoir",
  "material": "bois (Matériau)",
  "style": "vintage",
  "isDiscounted": true,
  "discountPct": 15,
  "postedAt": "2026-09-18T09:25:39.000Z",
  "imageUrl": "https://images.selency.com/08f41df2-ac9c-4ff7-b7af-98c5aadb552d.jpg",
  "country": "PL",
  "sellerType": "pro",
  "sellerHash": "9e0a2f6c1d5b8347"
}
```

### 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~selency-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"searches":["chaise scandinave"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~selency-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"searches":["chaise scandinave"]}` (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~selency-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 "Selency Scraper: Vintage Furniture Price 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`, `material` and `url` to a Discord or
Slack webhook. Google Sheets users can append the same rows 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 | Free-text French keyword search, material/style tags, built-in new-listing and price-drop monitoring | France only; no structured condition grade, because Selency is 100% pre-owned by design |
| Checking Selency by hand | Free, plus your time | Full control | Doesn't scale past a handful of searches and misses whatever appears between visits |

### 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 a pro/private flag and 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 Selency.

### 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
Selency'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`.

**Does it cover selency.co.uk or selency.nl?**
No — this actor reads the French site and index only. See "France only" above.

**Why is `material` or `style` sometimes empty?**
Selency only tags a listing with these when the seller filled them in — not every listing has both.

**What do I need to set up?**
Nothing. No Selency 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 "Selency Scraper: New Listing
& Price Drop Alerts".

### Related actors

- [1stDibs Listing Lookup](https://apify.com/accountable_eel/1stdibs-listing-lookup): the same one
  row per listing shape for 1stDibs' global luxury furniture and design marketplace.
- [Grailed Listing Lookup](https://apify.com/accountable_eel/grailed-listing-lookup): sold-price
  comps and new-listing alerts for resale menswear and streetwear.
- [Vinted Listing Lookup](https://apify.com/accountable_eel/vinted-listing-lookup): new-listing and
  price-drop alerts across 22 Vinted second-hand fashion sites.

# Actor input Schema

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

One search per line — any French (or other) keywords, e.g. "chaise scandinave", "commode vintage", "luminaire art deco". A pasted selency.fr category link (.../c/<category>) also works. No login required. Accepted formats: chaise scandinave, commode vintage, https://www.selency.fr/c/meubles. You're only charged for the ones we actually find — a miss costs nothing.

## `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. Matched against the title, category, material and style.

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

Optional. Matched against the title, category, material and style.

## `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.

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

Forced to "Newest" whenever monitoring is on, so two runs can be compared listing-by-listing.

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

Selency's search returns up to 1,000 matches per query (Algolia's own pagination window); this actor pages in batches of 60 to reach your limit. You pay per listing returned, so this is also your budget control.

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

Optional. Leave empty for no minimum.

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

Optional. Leave empty for no maximum.

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

Turns this actor into a monitor. A listing counts as new when its Selency listing ID has not been returned by a previous run of the same watchlist, and as a price drop when its EUR price falls since it was last seen. Already-seen, unchanged listings are dropped before you are billed, so a quiet run costs only the run fee. The first run has nothing to compare against, so (unless "Seed silently" is on) it returns everything and remembers it.

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

Leave empty and we derive one from this run's search settings, so two schedules with different settings keep separate memories. Type your own name to keep one memory across a settings change, or to have two schedules share one.

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

Include newly-seen listings when monitoring is on. Turn off to get price-drop alerts only.

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

Include listings whose price dropped since this watchlist last saw them (based on the price you were shown, independent of Selency's own discount flag below). Turn off to get new-listing alerts only.

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

A listing must drop by at least this percentage since it was last seen by THIS monitor to be reported as a price-drop.

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

Instead of returning every current listing as "new" the first time a watchlist runs, this banks them silently and starts alerting from the second run on.

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

Off by default. When on, adds the seller's Selency shop ID and display name. An anonymous seller hash is always included either way.

## `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": [
    "chaise scandinave"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "sort": "relevance",
  "maxListingsPerSearch": 60,
  "deltaMode": false,
  "deltaName": "",
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 5,
  "skipFirstRun": false,
  "includeSellerInfo": false,
  "columns": [
    "searchQuery",
    "listingCount",
    "totalAvailable",
    "truncated",
    "newCount",
    "priceDropCount",
    "monitorStatus",
    "listings",
    "listingId",
    "title",
    "price",
    "currency",
    "category",
    "material",
    "style",
    "isDiscounted",
    "discountPct",
    "postedAt",
    "imageUrl",
    "country",
    "sellerType",
    "sellerHash",
    "sellerId",
    "sellerName",
    "changeType",
    "isNew",
    "previousPrice",
    "priceDropPct",
    "firstSeenAt",
    "url"
  ],
  "expandRows": true,
  "maxConcurrency": 5,
  "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": [
        "chaise scandinave"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/selency-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": ["chaise scandinave"],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/selency-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": [
    "chaise scandinave"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/selency-listing-lookup --silent --output-dataset

```

## MCP server setup

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