Documentation Python quickstart Blog Free tools Enterprise solutions hello@quanticdata.ioLog in

Collectors · Classifieds & vehicles

Subito.it Scraper API in Python

Classified ads from Subito.it — motori by km/year/fuel, immobili by mq/locali, everything by price, comune and seller. One POST from Python with the input, rows back as JSON with 39 fields, $0.001 per delivered ad. No proxies or parsers to maintain.

A Python requests snippet that posts {
A Python requests call to the subito_search collector returns one dict per ad, at $0.001 each.

First call

Install, call, read the rows.

pip install requests
The only dependency.
import os, requests

r = requests.post(
    "https://api.quanticdata.io/v1/scraper/collectors/subito_search/run",
    headers={"Authorization": f"Bearer {os.environ['QD_API_KEY']}"},
    json={
        "query": "iphone 15",
        "title_only": True,
        "max_results": 30,
    },
    timeout=120,
)
r.raise_for_status()
run = r.json()["payload"]
print(run["count"], "rows,", run["cost"]["usd"], "USD")
for row in run["results"]:
    print(row.get("ad_id"), row.get("title"), row.get("url"), row.get("price"))
Python: one Subito.it ads run (iPhone in tutta Italia), printing ad_id, title, url, price

The key comes from an environment variable, never from the code. The run answers in the same request when it finishes in time; payload.results holds the rows and payload.cost what they cost.

Request parameters

What the collector takes.

Input of the Subito.it ads collector
ParameterTypeRequiredMeaning
querystringnoWhat to search, e.g. "iphone 15". Optional when a category is set — leaving it out browses that category by filters alone, which is how a motori or immobili search usually works.
categorystring: all, motori, auto, accessori-auto, moto-e-scooter, accessori-moto, nautica, caravan-e-camper, veicoli-commerciali, immobili, appartamenti, camere-posti-letto, ville-singole-e-a-schiera, terreni-e-rustici, garage-e-box, loft-mansarde, case-vacanza, uffici-locali-commerciali, lavoro, offerte-lavoro, servizi, cerco-lavoro, attrezzature, elettronica, informatica, videogiochi, audio-video, fotografia, telefonia, casa-e-persona, arredamento-casalinghi, elettrodomestici, giardino-fai-da-te, abbigliamento-accessori, bambini-giocattoli, sport-hobby, animali, accessori-per-animali, musica-film, libri-riviste, strumenti-musicali, sport, biciclette, hobby-collezionismo, vari, annunci-varino (default all)Subito category to search in. "all" searches every category (and disables Subito's own price/seller filtering — this collector re-applies it).
regionstring: italia, abruzzo, basilicata, calabria, campania, emilia-romagna, friuli-venezia-giulia, lazio, liguria, lombardia, marche, molise, piemonte, puglia, sardegna, sicilia, toscana, trentino-alto-adige, umbria, valle-d-aosta, venetono (default italia)Italian region to search in. "italia" searches the whole country.
citystringnoOptional province inside the region, as it appears in a Subito URL ("roma", "milano", "reggio-emilia"). Needs `region`.
townstringnoOptional comune inside the province, as it appears in a Subito URL ("ladispoli", "sesto-san-giovanni"). Needs `city`. This is the level real-estate searches usually want.
ad_typestring: sale, free, wantedno (default sale)Which kind of ad: for sale, given away for free, or wanted.
sortstring: recent, relevance, price_asc, price_descno (default recent)Result order.
title_onlybooleanno (default false)Match the query against ad titles only. Subito's default also matches the description, which pulls in loosely related ads.
shippable_onlybooleanno (default false)Only ads the seller will ship.
min_priceintegernoLowest price in euro. Ads with no stated price are excluded when set.
max_priceintegernoHighest price in euro. Ads with no stated price are excluded when set.
seller_typestring: any, private, companyno (default any)Private sellers, verified dealers, or both.
min_kmintegernoMotori. Lowest mileage in kilometres. Applied to the ads even in the categories where Subito offers no mileage filter (veicoli commerciali, caravan).
max_kmintegernoMotori. Highest mileage in kilometres.
min_yearintegernoMotori. Earliest registration year.
max_yearintegernoMotori. Latest registration year.
fuelstring: petrol, diesel, lpg, electric, cng, hybrid, mild_hybrid_petrol, mild_hybrid_diesel, full_hybrid_petrol, full_hybrid_diesel, plugin_hybrid_petrol, plugin_hybrid_dieselnoMotori. Subito splits hybrids by kind, so "hybrid" is its own value and does not cover the mild/full/plug-in ones.
gearboxstring: manual, automatic, sequentialnoMotori. Transmission type.
vehicle_conditionstring: used, km0, newnoMotori. Used, zero-km or new.
min_sizeintegernoImmobili. Smallest floor area in square metres.
max_sizeintegernoImmobili. Largest floor area in square metres.
min_roomsintegernoImmobili. Fewest locali.
max_roomsintegernoImmobili. Most locali (Subito caps its own filter at "more than 10").
max_resultsintegerno (default 30)How many ads to deliver at most (1–150). You pay only for delivered ads.

Response fields

39 fields per ad.

Fields of each row (ad)
FieldTypeWhat it holds
rankinteger1-based position in the delivered results.
pageintegerResult page the ad came from.
ad_idstringSubito listing id (the number ending the ad URL).
titlestringAd title.
urlstring, nullableAd URL.
pricestring, nullablePrice as shown ("450 €"). Null for free and wanted ads.
price_valuenumber, nullableParsed price in euro.
categorystring, nullableCategory the ad is filed under ("Telefonia").
category_slugstring, nullableCategory slug ("telefonia").
conditionstring, nullableItem condition as stated ("Come nuovo - perfetto o ricondizionato").
kminteger, nullableMotori. Exact mileage — Subito's card shows only the bucket ("70.000 - 74.999").
yearinteger, nullableMotori. Registration year.
fuelstring, nullableMotori. Fuel as a stable key ("diesel", "plugin_hybrid_petrol"), matching the input enum; the Italian label is in features.
gearboxstring, nullableMotori. "manual", "automatic" or "sequential".
vehicle_conditionstring, nullableMotori. "used", "km0" or "new".
size_sqminteger, nullableImmobili. Floor area in square metres.
roomsinteger, nullableImmobili. Number of locali.
datestring, nullablePublication time as ISO 8601 with the Europe/Rome offset in force ("2026-09-03T00:56:18+02:00"; +01:00 in winter).
regionstring, nullableRegion ("Emilia-Romagna").
citystring, nullableProvince ("Parma").
townstring, nullableComune ("Parma").
seller_typestring"private" or "company".
seller_namestring, nullableShop or advertiser name, when stated.
seller_idstring, nullableSubito user id of the seller.
shippablebooleanSeller offers shipping.
shipping_costnumber, nullableShipping cost in euro, when stated.
promotedbooleanPaid visibility (gallery placement).
urgentbooleanMarked urgent by the seller.
descriptionstring, nullableFull ad text (first 600 characters) — not the truncated card excerpt.
thumbnailstring, nullableFirst photo.
imagesstring[]Every photo, in the ad's order.
featuresobjectEvery other attribute the ad states, as label → value ("Km": "142.000", "Superficie": "85 mq"). Keys depend on the category.
ad_typestring, nullableAd type as Subito words it ("In vendita", "In regalo", "Cercasi").
ad_uuidstring, nullableStable UUID of the ad.
province_codestring, nullableTwo-letter province code (RM, MI, NA…).
town_istatstring, nullableISTAT code of the comune.
shop_idstring, nullableSubito shop id when the seller has a shop page.
image_countintegerNumber of photos on the ad.
phone_availablebooleanTrue when the seller shows a phone number on the ad.

Add ?format=csv to the runs endpoint to get the same rows as CSV.

Long runs

Run in the background, then poll.

A run that needs more time can go to the background: send "async": true, get 202 with the run id, and poll the runs endpoint until the status is done. Reading a run is free.

import os, time, requests

H = {"Authorization": f"Bearer {os.environ['QD_API_KEY']}"}
r = requests.post("https://api.quanticdata.io/v1/scraper/collectors/subito_search/run", headers=H,
                  json={**{"query":"iphone 15","title_only":True,"max_results":30}, "async": True}, timeout=30)
run_id = r.json()["payload"]["run_id"]
while True:
    run = requests.get(f"https://api.quanticdata.io/v1/scraper/collectors/runs/{run_id}", headers=H, timeout=30).json()["payload"]
    if run["status"] in ("done", "failed"):
        break
    time.sleep(5)
print(run["status"], run["count"])
Python: background run and polling

Errors

What can come back, and what is billed.

Collector run errors
StatusMeaningBilled
400The input does not match the collector (payload.errors)No
401Missing or wrong API keyNo
402Balance and free credit do not cover the run: top upNo
422The input can never resolve; retrying the same input cannot helpNo
424The run failed at the source (blocked, timed out, layout changed); safe to retryNo
429Rate limit or a per-account brake; wait for Retry-AfterNo

Only delivered rows are billed: a run that delivers nothing costs nothing.

Price

$0.001 per delivered ad.

What Subito.it ads rows cost at list price
RowsCost
1$0.001
1,000$1.00
10,000$10.00

Up to 150 ads per run; split larger jobs into several runs. The $2 free credit every month covers about 2,000 ads. No subscription; paid tiers lower the unit price. All collector prices: collector pricing.

Before you run it

Questions developers ask

Is there a free Subito.it ads API?

Every account gets $2 of free usage each month, about 2,000 ads of this collector at $0.001 each, with no card.

Do I have to handle proxies, retries or blocks?

No. The collector runs on our network and handles them; a run blocked at the source returns 424 and is not billed.

How many rows can one run return?

Up to 150 ads per run (the max_results input, where the collector has one).

Can an AI agent run it?

Yes: the MCP server exposes it as the run_collector tool, with the same input and price. See the MCP server.

Run it on the free credit.

Create an API key, export it as QD_API_KEY and run the example. $0.001 per delivered ad, no subscription.