# Milanuncios Scraper - Spain Classifieds API (`dami_studio/milanuncios-scraper`) Actor

Scrape Milanuncios, Spain's biggest classifieds site: listing id, title, price in EUR, category path, province and city, description, private vs professional seller, publish date, photos and URL. Cars, property, phones, furniture, jobs. $1.00 per 1,000 listings, no proxy needed.

- **URL**: https://apify.com/dami\_studio/milanuncios-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** E-commerce, Lead generation, Real estate
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Milanuncios Scraper — Spain's classifieds as JSON

Pulls listings from [Milanuncios](https://www.milanuncios.com), Spain's largest general classifieds
site (Adevinta, sibling of Fotocasa and InfoJobs). Cars, property, phones, furniture, jobs, pets —
all 17 sections and 2,302 categories.

Per listing you get the id, title, full description, price in EUR, the category path, province and
city, whether the seller is a private individual or a professional, publish and update timestamps,
the photos and the listing URL.

$1.00 per 1,000 listings, plus $0.001 per run start. Flat on every plan.

### What a listing looks like

```json
{
  "listingId": "611038030",
  "title": "Sofa Cama",
  "description": "Vendo sofa Cama de color verde nuevo en buem estado\nmedidas 171 largo × 1,03 Ancho × 1,76 Alto",
  "price": 250,
  "priceText": "250 €",
  "currency": "EUR",
  "previousPrice": null,
  "priceIncludesTaxes": null,
  "sellerType": "private",
  "sellerId": "233110658",
  "sellerName": "Marcos",
  "categoryId": 486,
  "categoryName": "Sillas sofás sillones",
  "categorySlug": "sillas-sofas-y-sillones",
  "sectionId": 30,
  "sectionName": "Casa y Jardín",
  "categoryPath": "Casa y Jardín > Muebles > Sillas sofás sillones",
  "province": "Jaén",
  "provinceId": 23,
  "city": "Baeza",
  "cityId": 27466,
  "region": "Andalucía",
  "latitude": null,
  "longitude": null,
  "publishedAt": "2026-08-21T13:58:38Z",
  "updatedAt": "2026-08-21T13:58:38Z",
  "transaction": "supply",
  "isHighlighted": false,
  "isNew": true,
  "reserveStatus": "RELEASED",
  "contactByPhone": false,
  "contactByChat": true,
  "attributes": { "color": "verde", "itemCondition": "ALMOST_NEW" },
  "images": ["https://images.milanuncios.com/api/v1/ma-ad-media-pro/images/d4e74c88-...?rule=hw396_70"],
  "imageCount": 2,
  "url": "https://www.milanuncios.com/sillas-sofas-y-sillones/sofa-cama-611038030.htm",
  "scrapedAt": "2026-08-21T16:20:11.016Z"
}
```

`attributes` is a per-category bag of whatever Milanuncios attached to the ad. Cars carry
`kilometers`, `year`, `fuel`, `transmission`, `hp`, `doors`, `color`, `warranty`,
`environmentalLabel`. Furniture carries `itemCondition` and `color`. Property carries room counts and
floor area. It's passed through as-is rather than flattened, because every category is different.

### Input

| Field | What it does |
|---|---|
| `query` | Search terms in Spanish — `sofa cama`, `iphone 15`, `piso alquiler`. |
| `category` | Name, slug or id: `Coches`, `Inmobiliaria`, `Telefonía`, `coches-de-segunda-mano`, `13`. Accent-insensitive, so `Telefonia` works too. |
| `searchUrls` | Paste Milanuncios URLs instead. Category, search text, price range, seller type and sort order are all read back out of the URL. |
| `provinces` | `Madrid`, `Barcelona`, `A Coruña`, or INE codes 1–52. |
| `sellerType` | `private` (particulares) or `professional` (dealers, agencies, shops). |
| `sort` | `relevance`, `cheap`, `expensive` work everywhere. `newest` and `oldest` only work in Motor — see below. |
| `minPrice` / `maxPrice` | EUR bounds. |
| `transaction` | `supply` (things for sale) or `demand` (wanted ads). Milanuncios carries both. |
| `maxItems` | Total listings across all searches. Each one is a charged result. |

You need at least one of `query`, `category` or `searchUrls`. An empty run returns a single labelled
sample row and charges nothing.

### Why it's cheap to run

Milanuncios' web pages sit behind F5 Shape. Request one from outside Spain and you get "Pardon Our
Interruption" with a GeeTest captcha. We measured that block on a residential Canadian address, on
three US static-ISP addresses, across three TLS fingerprints, with a Googlebot user-agent, and in a
real headful Chrome.

The site's own data doesn't come from those pages. It comes from a separate API gateway host that
answers a plain HTTP request with full JSON. So this launches no browser, uses no proxy, and does one
request per 100 listings. A 200-listing run is two requests, and the price reflects that.

### Limits

- **No phone numbers or seller contact details.** The API says whether a seller accepts phone or chat
  contact (`contactByPhone`, `contactByChat`), but the number itself sits behind a separate
  authenticated endpoint and is personal data. Not scraped.
- **8,300 results is the ceiling for any one search.** Milanuncios stops paginating at offset 8200.
  Past that it silently restarts from the beginning, so the actor stops rather than bill you for
  duplicates. To go deeper, split the search — by province, by price band, or by sub-category. Ten
  provinces is ten separate searches and ten separate ceilings.
- **`newest` and `oldest` only work in Motor.** Milanuncios returns zero rows for those orderings
  anywhere else. Ask for `newest` on Inmobiliaria and the actor falls back to `relevance` and says so
  in the log rather than handing you an empty dataset.
- **Photos are 396 px.** The image service whitelists one size rule. The URLs in `images` already
  carry it; the bare image URL 404s.
- **No result-count field.** Milanuncios reports a match count in its own response but caps it at
  10,000, so it's a floor rather than a count. It goes in the run log and deliberately not on the
  rows.
- **No coordinates on most ads.** `latitude` / `longitude` are usually null. Milanuncios only exposes
  them for a minority of listings.
- **Province filtering is done here, not there.** Milanuncios' own province filter is loose and
  returns neighbouring provinces too — we measured 80 of 100 rows actually in Madrid when asking for
  Madrid. This actor drops the other 20 and never charges you for them.

### Cost

You're charged for listings that land in your dataset. Diagnostics, sample rows and listings dropped
by the province filter are all free.

| Listings | Cost |
|---|---|
| 100 | $0.10 |
| 1,000 | $1.00 |
| 10,000 | $10.00 |

Plus $0.001 per run start.

### Questions

**What is Milanuncios?** Spain's largest general classifieds site, owned by Adevinta. Roughly the
Spanish equivalent of Craigslist or Gumtree — cars, property, jobs, electronics, furniture, pets and
services.

**Can I scrape Milanuncios cars specifically?** Yes. Set `category` to `Coches` (id 13), `Motos` for
motorbikes, `Furgonetas` for vans, or a specific make like `Audi` or `BMW` — each make is its own
category. Car ads carry mileage, year, fuel type, transmission, horsepower and the Spanish
environmental label in `attributes`.

**Can I filter to private sellers only?** Yes, `sellerType: "private"`. That's a real filter on
Milanuncios' side, not a post-filter. `professional` gives you dealers, agencies and shops.

**Can I scrape a specific province or city?** Province, yes — set `provinces`. City-level filtering
isn't exposed, but every row carries `city` so you can filter downstream.

**How many listings can I get?** Up to 8,300 per search. Split by province to multiply that — the 52
provinces are 52 independent searches. `maxItems` goes up to 50,000 across all searches in one run.

**Does it need a proxy?** No. Leaving it off is faster. You can supply your own if your setup
requires it.

**Is the data live?** Yes, fetched at run time from Milanuncios' own search backend. `publishedAt`
and `updatedAt` come straight from the ad.

**What language is the data in?** Spanish, as published. Titles, descriptions, category names,
province names and attribute values are Milanuncios' own text. Field names are English.

**How do I get the full-size photo?** You can't. Milanuncios' image service whitelists one size rule
(`hw396_70`, 396 px, AVIF) and 404s everything else. The URLs in `images` already include it.

**Why is a listing I can see on the website missing?** Most likely the 8,300-result depth limit, or
the `newest` sort outside Motor. The run log names both cases explicitly.

# Actor input Schema

## `query` (type: `string`):

What to search for, in Spanish - for example "sofa cama", "iphone 15", "piso alquiler". Leave empty to browse a whole category.

## `category` (type: `array`):

Optional. Milanuncios category by name, slug or id. Sections: Motor, Inmobiliaria, Empleo, Telefonía, Informática, Casa y Jardín, Moda y complementos, Deportes y náutica, Mascotas y agricultura, Aficiones y ocio, Imagen y Sonido, Juegos, Bebés, Formación y libros, Servicios, Negocios, Comunidad. Sub-categories work too (Coches, Motos, Furgonetas, Viviendas, Móviles, Portátiles). 2302 categories are recognised.

## `searchUrls` (type: `array`):

Optional. Paste Milanuncios search or category URLs instead of filling in the fields above, e.g. https://www.milanuncios.com/coches-de-segunda-mano/?desde=5000\&vendedor=part. The category, search text, price range, seller type and order in the URL are all read.

## `provinces` (type: `array`):

Optional. Restrict to one or more Spanish provinces by name ("Madrid", "Barcelona", "A Coruña", "Valencia") or INE code 1-52. Milanuncios' own province filter also returns neighbouring provinces, so this actor filters the results exactly - listings outside your provinces are dropped and never charged.

## `sellerType` (type: `string`):

Return only private sellers (particulares) or only professional sellers (dealers, agencies, shops).

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

Newest first and Oldest first only work inside the Motor section - Milanuncios returns nothing for them in other categories, so the actor falls back to Most relevant and says so in the log.

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

How many listings to return in total across all searches. Each returned listing is one charged result. Milanuncios caps any single search at 8300 results; add provinces, price bands or sub-categories to go past that.

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

Optional lower price bound.

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

Optional upper price bound.

## `transaction` (type: `string`):

Milanuncios carries both offers (someone selling) and wanted ads (someone looking to buy).

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

Optional. This actor does not need a proxy - Milanuncios' search API answers the Apify container directly, which is why it is cheap. Supply your own proxy only if you want the traffic routed somewhere specific.

## Actor input object example

```json
{
  "query": "sofa cama",
  "category": [],
  "searchUrls": [],
  "provinces": [],
  "sellerType": "any",
  "sort": "relevance",
  "maxItems": 100,
  "transaction": "supply",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per listing in the default dataset: id, title, price in EUR, category, province and city, description, private vs professional seller, publish date, photos and the listing URL. Empty or blocked runs return a single uncharged row instead.

# 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 = {
    "query": "sofa cama",
    "category": [],
    "searchUrls": [],
    "provinces": [],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/milanuncios-scraper").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 = {
    "query": "sofa cama",
    "category": [],
    "searchUrls": [],
    "provinces": [],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/milanuncios-scraper").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 '{
  "query": "sofa cama",
  "category": [],
  "searchUrls": [],
  "provinces": [],
  "maxItems": 100
}' |
apify call dami_studio/milanuncios-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/BuPtAUPFISpqSdrYs/builds/a8kKdXLPPgFVL4CQS/openapi.json
