Subito Scraper: New Listing & Price Drop Alerts
Pricing
from $0.95 / 1,000 listing returneds
Subito Scraper: New Listing & Price Drop Alerts
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.
Pricing
from $0.95 / 1,000 listing returneds
Rating
0.0
(0)
Developer
Adrian Voss
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
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
attributesobject 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'ssellThroughRateand the search'smedianPriceEur. 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/maxPricefilter, 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
- In the Apify Console. Open the actor page and click Start — the
searchesfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
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"]}'
- 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:
iphonefiat pandaappartamento 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
{"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 | <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)> | <price (eur)> | <seller type (business/private)> | <promoted/gallery ad> | <is this listing new?> | <change (new / price-drop / gone / seen)> | <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:
- Put your searches in
searchesand setminPrice/maxPrice/regionif you want to narrow the field. - 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. - Optionally turn on Seed silently so the first run remembers today's listings without sending all of them to your webhook.
- Save it as a Task and add a Schedule: daily is the usual cadence, hourly for a busy search.
- 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.
{"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_ROWSandlistingCount: 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
deltaNameto 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: truewhen 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 onlygone.firstSeenAt,lastSeenAt,daysListed,lastPricetell you how long it was up (as far as your runs saw it) and what it was asking.sellThroughRateis 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 whenalertOnGoneis off.medianPriceEuris 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:
- 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.
- 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.
{"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.
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
maxListingsPerSearchcovers; otherwise listings in between are missed and no sold signal can be seen for them. - Use
minPrice/maxPrice/regionto cut noise from a broad category search before you pay for rows you don't want, rather than filtering client-side after the fact. attributesvaries 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.sellerTypelets 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 — the same search-by-keyword shape, for France's leboncoin.fr.
- Marktplaats Listing Lookup — the same shape, for the Netherlands' Marktplaats.
- Kleinanzeigen Search Lookup — the same shape, for Germany's Kleinanzeigen.