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

Subito.it scraper by keyword: run a search on Subito, Italy's largest classifieds site, for one row per listing. Monitoring: new listings, price drops and gone ones, a sold items tracker with sell-through rate. No login, no proxy needed. Pay per listing; empty searches are free.

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

## Subito Scraper: New Listing & Price Drop Alerts

You type a search the way you'd type it into Subito's own search box — "iphone", "fiat panda",
"appartamento 3 locali" — and this actor runs it against **subito.it's own search-results pages**,
Italy's largest classifieds marketplace, and returns one clean row per listing: title, price,
condition, category, city, seller type, and a permanent link. No login required, no proxy needed.

Turn on monitoring and the same search becomes a **Subito alert for new listings and price
drops**: scheduled daily, each run returns only what is new or cheaper since the last one. Add the
sold signal and it also tells you which listings went (a **Subito sold items tracker** with a
sell-through rate and the search's median price). See "Monitoring" and "Sold signal and
sell-through" below.

Subito has no anti-bot wall on its search pages — a plain HTTP request returns the full,
server-rendered result set, so this actor needs no proxy at all, which keeps it cheap and fast.

### Who it's for

A reseller or arbitrage buyer watching one category (phones, cars, furniture) for underpriced
listings wants a live feed of what's actually posted right now, across many search terms at once,
without refreshing Subito's own search page by hand. A market-research team tracking asking prices
for a product category, or a relocation scout scanning one region's listings, gets the same shape
here: paste a list of search terms, get back a flat row per listing, and pay only for listings
actually returned — a search that finds nothing costs nothing.

This actor is Subito's counterpart to `leboncoin-listing-lookup` (France) and
`marktplaats-listing-lookup` (Netherlands) in this catalogue: same search-by-keyword shape, one row
per listing, monitoring built in from day one.

### Why this one

- **Reads Subito's own structured data, not scraped text.** Every field here comes from the same
  `__NEXT_DATA__` JSON block Subito's own React app renders from — not regex'd out of visible page
  text, so prices, IDs, and location fields are exact, typed values rather than parsed strings.
- **No proxy, no anti-bot wall.** A bare HTTP request to Subito's search pages returns a normal 200
  with the full result set — confirmed directly, not assumed, across a dozen live requests while
  building this actor. That keeps the price down: there's no per-request proxy cost baked in, unlike
  DataDome-defended sites in this same catalogue.
- **Pages past a single screen.** Subito shows 42 listings per page (30 organic + 12
  gallery/promoted); this actor pages automatically up to `maxListingsPerSearch` (up to 500), so a
  broad search doesn't cap out at one page's worth.
- **Works across every Subito category, not just one.** Electronics, vehicles, real estate, jobs,
  general goods — Subito's per-listing attributes vary by category (storage and condition for a
  phone, mileage for a car), and this actor carries all of them through in a generic `attributes`
  object instead of hardcoding one category's fields and dropping the rest.
- **Monitoring built in from day one: new listings, price drops, and a sold signal.** Tick one box
  and a scheduled search returns only listings that are new or cheaper since its last run, read
  newest first (Subito's own default order — no forced sort needed). Opt in to "Alert on gone
  listings" and it also returns the ones that disappeared, with `gonePresumedSold`, `daysListed`,
  the watchlist's `sellThroughRate` and the search's `medianPriceEur`. Unchanged listings are never
  billed.
- **Never charged for a miss, or for a listing outside your price range.** A search that finds
  nothing, or where every result falls outside your `minPrice`/`maxPrice` filter, still gets a row
  explaining what happened — and costs nothing.
- **No private-seller contact data.** Subito's own search response never exposes a private seller's
  name or phone number on the results page — only a business seller's shop name is returned, and
  any phone number or email address embedded in a listing's own description text is redacted.

### What you get

One row per listing by default. (Turn off "One row per listing" in the Input tab to get one row per
*search* instead, with the whole listing list nested in `listings`.) Every row carries these
fields:

| Field | Type / format | Description |
| --- | --- | --- |
| `query` | text | The search term you passed in, unchanged. |
| `found` | boolean | `true` if the search returned at least one listing. `false` rows are never charged. |
| `status` | text | `OK`, `NOT_FOUND` (no listings for that search), `BAD_FORMAT` (a blank line), or `BLOCKED`. |
| `searchQuery` | text | The search text actually sent to Subito. |
| `listingCount` | number | How many listings this search returned after your price filters — this is exactly what you're charged for. |
| `totalAvailable` | number | Subito's own total-match count for this search. |
| `truncated` | boolean | `true` if more listings were available than this run read. |
| `listings` | array | The full listing list. Present in every row; it's what gets expanded into separate rows in "one row per listing" mode. |
| `listingId` | text | Subito's own numeric listing ID (the number its listing URL ends with). |
| `title` | text | Listing title. |
| `description` | text | Listing description, truncated to 500 characters, with any embedded phone number or email address redacted. |
| `price` | number | Price in EUR, or `null` for a free/exchange/price-on-request listing. |
| `condition` | text | Subito's own condition label, when the category has one (e.g. "Come nuovo - perfetto o ricondizionato"). |
| `category` | text | Subito's own category name, e.g. "Informatica". |
| `city` / `region` | text | Seller's stated location, as Subito displays it. |
| `sellerType` | text | `business` or `private`, from Subito's own listing owner data. |
| `sellerName` | text | Shop name for a business seller. `null` for a private seller — Subito's search results never expose one. |
| `publishedAt` | text | Subito's own listing timestamp, verbatim (see FAQ on why this isn't reformatted). |
| `url` | link | Permanent link to the listing on subito.it. |
| `image` | link | Thumbnail image URL. |
| `imageCount` | number | How many photos the listing has. |
| `isPromoted` | boolean | `true` for a gallery/promoted listing injected into the results grid rather than an organic search match. Returned and billed like any other row. |
| `attributes` | object | Every category-specific attribute Subito shows on the listing (phone storage, vehicle mileage, property size, etc.) as a flat key/value object — see "Why this one". |
| `scrapedAt` | date (ISO) | When this actor fetched the row. |

With monitoring on (`deltaMode`, or a named watchlist in `deltaName`), rows also carry these. They
are present but `null` on a plain run, so the columns never shift:

| Field | Type / format | Description |
| --- | --- | --- |
| `changeType` | text | `new`, `price-drop`, `gone` (delisted since the last run, see "Sold signal"), or `seen` (named watchlist with monitoring off). |
| `isNew` | boolean | `true` when this watchlist has never returned the listing before. |
| `previousPrice` / `priceDropPct` | number | On `price-drop` rows: the price last seen and how much cheaper it is now, in %. |
| `firstSeenAt` / `lastSeenAt` / `daysListed` | date / number | When the watchlist first and last saw the listing, and the days between. |
| `lastPrice` / `gonePresumedSold` | number / boolean | On `gone` rows only: the last price seen, and whether it looks like a sale (see "Sold signal"). |
| `newCount` / `priceDropCount` / `goneCount` | number | Per search: new listings, price drops, and listings that went gone this run (gone is counted even with the gone alert off). |
| `monitorStatus` | text | `NEW_ROWS`, `NO_NEW_ROWS` (a quiet run: one summary row, no listings billed), or `SEEDED` (first run with "Seed silently" on). |
| `sellThroughRate` | number | Listings gone / listings ever tracked by this watchlist, 0-1, over its lifetime. |
| `medianPriceEur` | number | Median price of every listing this run read within your price filters, not just the rows returned. |

A search that returns no listings comes back as a single `found: false` row with a
`status`/`message` explaining why, and is never charged.

### Price

- **Listing returned**: $1.9 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.

**Proposed pricing (not yet live — set by the account owner on the Apify Console's Monetization
tab, undercutting the niche's leaders):** **$1.90 per 1,000 listings returned**, plus a $0.00005
start fee per run. Each listing is billed only once, whether returned as a plain row, a new-listing
alert, a price-drop alert, or a gone/sold-signal row — there is no separate event for monitoring.
Misses (`found: false`) and listings outside your price filter are never charged. Since Subito needs
no proxy at all, this is priced below `leboncoin-listing-lookup` ($2/1k, which pays for UNBLOCKER).

You're charged **per listing returned**, not per search — a search that returns 40 listings costs
forty, a search that returns none costs nothing, and a blank line costs nothing. Because you pay
per listing, `maxListingsPerSearch` is your budget control.

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

Paste one search per line:

```
iphone
fiat panda
appartamento 3 locali milano
```

**Narrow the results** — applied here, to the listings after they arrive:

| Input | What it does |
| --- | --- |
| `region` | Narrow every search to one of Italy's 20 regions. Leave as "All Italy" (default) to search nationwide. |
| `minPrice` | Drop listings priced below this (EUR). |
| `maxPrice` | Drop listings priced above this (EUR). |
| `sort` | "Newest first" (default, a no-op — Subito's own order already is newest-first) or a price sort applied to the listings this run already fetched. |
| `maxListingsPerSearch` | Most listings to return per search, up to 500. Subito shows 42 per page; this actor pages automatically to reach your limit. |

### Input

```json
{
  "searches": [
    "iphone"
  ]
}
```

One search per line — any keywords, e.g. "iphone 14", "fiat panda", "appartamento 3 locali". No login required. Accepted formats: iphone, fiat panda, appartamento 3 locali milano.

### Sample output

| query | found | status | searchQuery | listingCount | totalAvailable | truncated | newCount | priceDropCount | monitorStatus | goneCount | sellThroughRate | medianPriceEur | listings | listingId | title | price | condition | category | city | region | sellerType | publishedAt | url | isPromoted | isNew | changeType | firstSeenAt | lastSeenAt | daysListed | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| iphone | true | OK | <search> | <listings returned> | <total matching on subito> | <more results were available> | <new since last run> | <price drops since last run> | <monitoring status> | \<gone since last run (delisted, most often sold)> | \<sell-through rate, watchlist lifetime (0-1)> | \<median price of the search, eur> | \<all listings found (full list)> | <subito listing id> | <title> | \<price (eur)> | <condition> | <category> | <city> | <region> | \<seller type (business/private)> | <published> | <listing link> | \<promoted/gallery ad> | \<is this listing new?> | \<change (new / price-drop / gone / seen)> | <first seen on a run> | <last seen on a run> | \<days listed (first to last seen)> | 1970-01-01T00:00:00.000Z |

A miss comes back as a row with `"found": false` and is never charged.

### Monitoring: new listings and price drops

The recipe for a Subito alert on new listings:

1. Put your searches in `searches` and set `minPrice` / `maxPrice` / `region` if you want to narrow
   the field.
2. Turn on **Only return listings that are new, or cheaper, since the last run** (`deltaMode`).
   Subito's own default order is already newest-first, so no forced sort is needed.
3. Optionally turn on **Seed silently** so the first run remembers today's listings without sending
   all of them to your webhook.
4. Save it as a Task and add a **Schedule**: daily is the usual cadence, hourly for a busy search.
5. Add a webhook or integration on the Task for **Run succeeded** (Slack, Discord, Telegram via n8n
   or Make, or an append to Google Sheets). Each run's dataset holds only the new and price-drop
   rows.

```json
{
  "searches": ["iphone 15 pro", "bici elettrica"],
  "maxPrice": 800,
  "deltaMode": true,
  "skipFirstRun": true,
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 10
}
```

How it decides:

- **New** means this watchlist has never returned that Subito listing ID before.
- **Price drop** means the price is at least `minPriceDropPct` (default 5%) below the price last
  seen. 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` and `listingCount: 0`, and costs only the start fee.
- Each watchlist remembers up to 5,000 listings per search, oldest forgotten first, and forgets any
  listing it has not seen for 30 days. The memory lives in a named key-value store in your own
  Apify account (`subito-listing-lookup-delta`), so it survives between scheduled runs.
- The watchlist name is derived from your price and region filters, so two schedules with different
  filters never share a memory. Set `deltaName` to choose your own.

**The read-window limit.** Each run reads up to `maxListingsPerSearch` listings (default 42, one
page). If more new listings than that appear between two runs, the ones past the window are never
seen; schedule busy searches more often, or raise `maxListingsPerSearch`, or narrow them (a model, a
price band, a region).

### Sold signal and sell-through

Turn on **Alert on gone listings** (`alertOnGone`) next to `deltaMode` and a watchlist also returns
the listings it saw on its previous run that have since disappeared from the search.

**What "gone" means, honestly.** Subito does not show sold ads or confirm a sale on its public
search pages; a sold ad simply stops appearing. So does an ad the seller deleted, one that expired,
or one edited so it no longer matches your search (a price raised above your `maxPrice` is
recognised and not counted). **`gone` means delisted: most often sold, sometimes withdrawn.** Treat
it as a strong signal, not a receipt.

- **`gonePresumedSold: true`** when the listing's last price was at or under the search's median
  price and it was seen on at least 2 runs in a row. A fairly priced listing that stayed up and then
  vanished is the pattern of a sale; one seen once, or priced above the market, is only `gone`.
- **`firstSeenAt`, `lastSeenAt`, `daysListed`, `lastPrice`** tell you how long it was up (as far as
  your runs saw it) and what it was asking.
- **`sellThroughRate`** is listings gone / listings ever tracked over the lifetime of the watchlist.
  It is on every row and on the summary row of a quiet run, and it counts gone listings even when
  `alertOnGone` is off.
- **`medianPriceEur`** is the median price of every listing this run read within your price filters,
  not just the rows returned.

**How a run decides a listing is gone, not just out of view.** A run reads up to
`maxListingsPerSearch` listings, and a listing pushed off that window by newer ones is still for
sale. A run calls a listing gone in only two cases:

1. **The search is small enough that this run read every match** (Subito reports fewer matches than
   this run read, and they all came back). Then any remembered listing that is missing is gone.
2. **The fetch is verified newest first.** Subito's own default order is newest-first, but this
   actor checks it fresh on every run rather than assuming it (every listing's own timestamp must be
   present and non-increasing) — it then remembers each listing's position, counts the new arrivals
   above it, and calls it gone only if it should still sit well inside the window: at least 2 places
   above the bottom, and with a listing date newer than the listings near the bottom, so a re-bumped
   ad can't make another look gone.

Anything else gets no gone check: a watchlist's first run, a fetch that comes back empty or blocked,
or a fetch that is not verifiably in date order. Gallery/promoted listings are never called gone,
because their place in the results grid isn't earned by recency — a missing one proves nothing. On
any doubt the answer is "still for sale". On a busy search where more new listings arrive between
two runs than `maxListingsPerSearch` covers, raise the limit or schedule more often.

A gone listing is reported once. If it shows up again later, it is taken back off the sell-through
count. Gone rows are billed as ordinary `listing` rows, only when `alertOnGone` is on, and are built
from what the watchlist already remembers, so they make no extra request.

```json
{
  "searches": ["iphone 13", "nintendo switch oled"],
  "maxPrice": 600,
  "deltaMode": true,
  "deltaName": "resale-sold-signal",
  "alertOnNew": false,
  "alertOnPriceDrop": false,
  "alertOnGone": true
}
```

Scheduled daily and sent to Google Sheets, that returns only the listings that went, with
`gonePresumedSold`, `daysListed` and the running `sellThroughRate`: a Subito sold items tracker,
without login, updated automatically.

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

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~subito-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"searches":["iphone"]}` (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~subito-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 "Subito Scraper | Apify" — the agent will find and run this actor.

### Tips

- Run "Try it first" on a handful of searches you already know return results for, to sanity-check
  the shape before spending on a full list.
- For alerts, schedule the Task often enough that fewer new listings appear between two runs than
  `maxListingsPerSearch` covers; otherwise listings in between are missed and no sold signal can be
  seen for them.
- Use `minPrice`/`maxPrice`/`region` to cut noise from a broad category search before you pay for
  rows you don't want, rather than filtering client-side after the fact.
- `attributes` varies by category — inspect a few real rows for your search term before building a
  downstream schema around specific attribute keys, since a phone search and a car search return
  different keys.
- `sellerType` lets you split business listings (shops, resellers) from private-party ones if you
  only want one or the other.

### Data & privacy

This actor only reads Subito's own public search-results pages — no login, no account access. It
never surfaces a private seller's name or phone number: Subito's search response doesn't include
them for a private listing in the first place, and any phone number or email address that turns up
inside a listing's own free-text description is redacted (`[redacted]`) before it reaches your
dataset. A business seller's shop name is returned, since that's the seller's own public storefront
identity, not a private individual's contact detail.

### vs. alternatives

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** (`subito-listing-lookup`) | $0.0019 per listing returned (proposed; less on paid Apify plans), $0.00005 actor start, nothing for a search that finds nothing | One row per Subito listing — title, price, condition, category, city, seller type, and link — filtered by min/max price and region; monitoring mode for new listings, price drops and a sold signal with sell-through rate; no proxy cost | Reads up to `maxListingsPerSearch` (default 42, up to 500) per search rather than a whole category; gone detection needs either a small search or a verified newest-first fetch. Publish timestamps are passed through verbatim, without a timezone marker (see FAQ). |
| **Doing it yourself** | Your time, tracking Subito's own `__NEXT_DATA__` shape as it changes, and handling category-specific fields by hand | The same data | The generic attribute handling and paging this actor already does are the maintenance burden it absorbs. |

Prices for third-party tools are their published figures as of September 2026 and are not tracked
here — check the vendor before relying on the comparison.

### FAQ

**Why is a row empty, or why does `found` say `false`?**
Either the input line is blank (`status: BAD_FORMAT`), Subito returned an error
(`status: BLOCKED`, HTTP 403/429/503), the request failed after retries
(`status: REQUEST_FAILED`), or the search genuinely has no matching listings right now
(`status: NOT_FOUND`). Check the `message` column for the specific reason. None of these are
billed.

**Am I charged for a miss?**
No. You're only charged for listings actually returned. A blocked search, a search with zero
matches, or a search where every result falls outside your price filter all produce a row (unless
you turn on "Hide rows with no result") and none of them cost anything.

**Why is `publishedAt` not a normal ISO timestamp?**
Subito's own data returns it as a plain `"YYYY-MM-DD HH:MM:SS"` string with no timezone marker.
Rather than guess a timezone and fabricate a false-precision ISO instant, this actor passes the
value through exactly as Subito sends it.

**Does this actor page through more than one screen of results?**
Yes, automatically, up to `maxListingsPerSearch` (default 42, up to 500). `totalAvailable` still
reports Subito's true match count so you know how many more exist; `truncated` is `true` whenever
there are more than this run read.

**Do I need to configure proxies?**
No. Subito has no anti-bot wall on its search pages, so this actor makes plain requests with no
proxy at all — there's nothing to configure and no proxy cost baked into the price.

**Can I get a Subito alert for new listings?**
Yes. Turn on `deltaMode`, save the input as an Apify Task and schedule it (daily is typical). Each
run returns only listings that are new or dropped in price since the previous run of that
watchlist, read newest first; a run with nothing new bills no listings. See "Monitoring".

**Does it find sold listings?**
Not directly: Subito does not publish sales. With `deltaMode` and `alertOnGone` on, it returns
listings that disappeared since the last run (`changeType: gone`), flags the likely sales
(`gonePresumedSold`) and keeps a running `sellThroughRate`. Gone means delisted: most often sold,
sometimes withdrawn. See "Sold signal and sell-through" for how it avoids calling a listing gone
when it has only slid off the read window.

**Can an AI agent call this directly?**
Yes. It's registered on the Apify MCP server — an agent in Claude, Cursor, or another MCP client
can find and run it by name ("Subito Scraper | Apify"), or you can call the REST endpoint shown
above from any script or workflow tool.

### Related actors

- [Leboncoin Listing Lookup](https://apify.com/accountable_eel/leboncoin-listing-lookup) — the same
  search-by-keyword shape, for France's leboncoin.fr.
- [Marktplaats Listing Lookup](https://apify.com/accountable_eel/marktplaats-listing-lookup) — the
  same shape, for the Netherlands' Marktplaats.
- [Kleinanzeigen Search Lookup](https://apify.com/accountable_eel/kleinanzeigen-search-lookup) — the
  same shape, for Germany's Kleinanzeigen.

# Actor input Schema

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

One search per line — any keywords, e.g. "iphone 14", "fiat panda", "appartamento 3 locali". No login required. Accepted formats: iphone, fiat panda, appartamento 3 locali milano. 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. 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.

## `region` (type: `string`):

Narrow every search to one Italian region. Leave as "All Italy" to search nationwide.

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

Optional. Drop listings priced below this. Leave empty for no minimum.

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

Optional. Drop listings priced above this. Leave empty for no maximum.

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

"Newest first" is a no-op — Subito's own default order already is newest-first (confirmed live). "Price" re-orders only the listings this run already fetched; it does not change which listings are fetched.

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

Subito returns up to 42 listings per page (30 organic + 12 gallery/promoted); this actor pages automatically up to this limit. You pay per listing returned, so this is also your budget control.

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

Turns a search into a watchlist: a Subito alert for new listings and price drops. A listing is new when its Subito 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. Turn on "Alert on gone listings" below to also get listings that disappeared (a sold signal). Every row then carries the watchlist's sell-through rate and the search's median price. Unchanged listings are removed before you are billed, so a quiet run bills no listings and returns one summary row. Schedule it daily and send the results to Slack, Discord, Telegram, Google Sheets or n8n.

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

Leave empty and one is derived from this run's price/region filters, so two schedules with different filters keep separate memories. Type your own name to keep one memory across a filter change, or to have two schedules share one. 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.

## `alertOnGone` (type: `boolean`):

Off by default. With monitoring on, also return listings this watchlist saw on its previous run that have since disappeared from the part of the search the run could see: delisted, most often sold, sometimes withdrawn. Subito never confirms a sale. gonePresumedSold is true when the last price was at or under the search's median and the listing was seen on at least 2 runs in a row. Billed as ordinary listing rows, no extra request.

## `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 wall of messages on day one. Alerts start from the second run.

## `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": [
    "iphone"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "region": "",
  "sort": "newest",
  "maxListingsPerSearch": 42,
  "deltaMode": false,
  "deltaName": "",
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "alertOnGone": false,
  "minPriceDropPct": 5,
  "skipFirstRun": false,
  "columns": [
    "searchQuery",
    "listingCount",
    "totalAvailable",
    "truncated",
    "newCount",
    "priceDropCount",
    "monitorStatus",
    "goneCount",
    "sellThroughRate",
    "medianPriceEur",
    "listings",
    "listingId",
    "title",
    "price",
    "condition",
    "category",
    "city",
    "region",
    "sellerType",
    "publishedAt",
    "url",
    "isPromoted",
    "isNew",
    "changeType",
    "firstSeenAt",
    "lastSeenAt",
    "daysListed"
  ],
  "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": [
        "iphone"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

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

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

```

## MCP server setup

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