# Wallapop Listings Extractor (`kawsar/wallapop-listings-extractor`) Actor

Wallapop listings extractor that scrapes public Wallapop ads for price, images, location, and seller info so you can monitor second-hand markets without manual browsing.

- **URL**: https://apify.com/kawsar/wallapop-listings-extractor.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 results

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

## Wallapop Listings Extractor: Scrape Wallapop Search and Category Listings

Wallapop Listings Extractor is an Apify actor that collects public Wallapop listings from category pages, SEO landing pages, and search URLs. Each result is one ad with title, description, price, images, seller details, shipping flags, and the public item URL.

It is built for second-hand market research, price monitoring, resale sourcing, and inventory discovery across Wallapop country sites such as Spain, Italy, Portugal, France, Germany, Netherlands, and Belgium.

### Why this actor

Wallapop category pages embed real listing data in the page payload. This actor reads that structured data first, then normalizes every ad into a flat dataset row. It filters out category navigation links and other non-listing objects so you do not get empty titles like "Sillas de comedor" with null prices.

You get:

- Clean listing rows with URL, title, price, and images
- Seller name and seller id when Wallapop exposes them
- Shipping and reserved flags when present
- Export to CSV, JSON, Excel, or XML from the Apify dataset
- A max-items cap so each run stays predictable

### What data does this actor extract?

Only fields Wallapop actually returns are written to the dataset. Empty or unknown values are omitted (no `null` placeholders).

| Field | Type | Usually on category/SEO pages | Description |
| --- | --- | --- | --- |
| `listingId` | string | yes | Wallapop listing id |
| `url` | string | yes | Public item URL (`/item/...`) |
| `itemTitle` | string | yes | Listing title |
| `itemDescription` | string | yes | Seller description |
| `price` / `currency` | number / string | yes | Asking price |
| `categoryName` | string | yes | Category label |
| `images` | array | yes | Image URLs |
| `sellerId` / `sellerName` | string | yes | Public seller fields |
| `isReserved` / `isShippable` | boolean | yes | Flags when present |
| `locationCity` / `locationRegion` / `locationCountry` | string | only if in payload | Location (often missing on category cards) |
| `latitude` / `longitude` | number | only if in payload | Coordinates when Wallapop includes them |
| `createdAt` / `modifiedAt` | string | only if in payload | Timestamps when Wallapop includes them |
| `sourceUrl` | string | yes | Input URL for the row |
| `scrapedAt` | string | yes | Collection timestamp (UTC) |
| `error` | string | failures only | Present only when a source URL fails |

Category and SEO landing pages usually include title, description, price, images, seller, and shipping. They often do **not** include city, coordinates, or timestamps. Those keys are left out of the row instead of being filled with `null`.

### Supported start URLs

| URL type | Example | Notes |
| --- | --- | --- |
| Category / SEO landing | `https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio` | Best source. Full listing fields are usually present. |
| Search page | `https://es.wallapop.com/search?keywords=iphone` | Uses keyword from the URL when page data is limited. |
| Item page | `https://es.wallapop.com/item/...` | Single listing when the page exposes item data. |

Tip: prefer Wallapop category or SEO landing URLs for the richest fields. Those pages typically include description, seller, images, and shipping details in one response.

### How to use

1. Open **Wallapop Listings Extractor** on Apify.
2. Keep or replace the prefilled `startUrls` value with your Wallapop category or search URL.
3. Optionally set `maxItems` (default `100`, max `1000`).
4. Click **Start**.
5. Open the Dataset tab and export CSV, JSON, Excel, or XML.

#### Example input

```json
{
  "startUrls": [
    "https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio"
  ],
  "maxItems": 50,
  "requestTimeoutSecs": 60
}
```

#### Example output

```json
{
  "listingId": "wzvgooeov7zl",
  "url": "https://es.wallapop.com/item/silla-de-escritorio-ergonomica---escritorio-pequen-1304443889",
  "itemTitle": "Silla de escritorio ergonómica + escritorio pequeñ",
  "itemDescription": "Silla de escritorio NIHM + escritorio a juego...",
  "price": 80,
  "currency": "EUR",
  "categoryName": "Hogar y Jardín",
  "images": [
    "https://cdn.wallapop.com/images/10420/lk/mr/__/c10420p1304443889/i6744808030.jpg?pictureSize=W800"
  ],
  "sellerId": "8x6q9d4ekqzy",
  "sellerName": "Nacho  L.",
  "isReserved": false,
  "isShippable": true,
  "sourceUrl": "https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio",
  "scrapedAt": "2026-09-22T04:30:00.000000+00:00"
}
```

### Input parameters

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `startUrls` | array | recommended | category URL prefill | Wallapop category, SEO, search, or item URLs |
| `keywords` | array | no | empty | Optional keyword searches when you do not have a URL |
| `countryCode` | string | no | `ES` | Market for keyword search URL building |
| `maxItems` | integer | no | `100` | Max listings per run (`1`–`1000`) |
| `requestTimeoutSecs` | integer | no | `60` | Per-request timeout in seconds |

### Use cases

- **Price monitoring**: track asking prices for phones, bikes, furniture, or collectibles over time
- **Resale sourcing**: watch a category URL for newly posted inventory and underpriced ads
- **Market research**: build a second-hand dataset for a category or keyword across a Wallapop country site
- **Competitor checks**: compare similar Wallapop listings before you set your own price
- **Downstream workflows**: feed listing rows into Google Sheets, databases, alerts, or internal tools

### How pagination works

Wallapop SEO category pages usually embed about 80 listings in the first response. When `maxItems` is higher, the actor continues with:

1. Location variants of the same landing (for example `/sillas-de-escritorio/madrid`, `/barcelona`)
2. Related SEO keyword landings from the page footer
3. Search API offsets when those pages still leave room under `maxItems`

Results are deduplicated by listing id/URL, and the run stops once `maxItems` is reached.

The actor only keeps rows that look like real listings:

- Must include a public `/item/...` URL and a title
- Prefers rows with listing id, price, images, and seller fields
- Drops category navigation labels and suggested-keyword chips that are not ads
- Deduplicates by `listingId` or item URL within a run
- Omits fields Wallapop did not return (no `null` city/coords/dates fillers)

If a source URL fails completely, one compact error row is written with `error`, `sourceUrl`, and `scrapedAt` only.

### Countries

Keyword search can target:

- Spain (`ES`) → `es.wallapop.com`
- Italy (`IT`) → `it.wallapop.com`
- Portugal (`PT`) → `pt.wallapop.com`
- France (`FR`) → `fr.wallapop.com`
- Germany (`DE`) → `de.wallapop.com`
- Netherlands (`NL`) → `nl.wallapop.com`
- Belgium (`BE`) → `be.wallapop.com`

If your start URL already uses a country host, that host is used for item URLs and country inference.

### FAQ

**Why did I previously get null prices and category titles?**
Older parsing treated suggested category links as listings. The actor now reads the structured listing array from category/SEO pages and rejects navigation-only objects.

**Which URL should I use for best results?**
Use a Wallapop category or SEO landing URL such as `/muebles-deco-y-jardin/sillas-de-escritorio`. Those pages usually include description, seller, images, and shipping fields.

**Do I need a Wallapop account?**
No. The actor reads public listing pages only.

**How many listings can I get per run?**
Up to 1000, controlled by `maxItems`.

**Why are city, coordinates, or dates sometimes missing?**
Category and SEO search cards often do not include those fields. The actor does not invent them and does not write `null`. If Wallapop includes location or timestamps on a richer payload, those keys appear on that row.

**Can I run this on a schedule?**
Yes. Use Apify Schedules to refresh a category or keyword daily and export or push the dataset downstream.

### Notes and compliance

This actor is independent and is not affiliated with, endorsed by, or sponsored by Wallapop. Only collect public data you are allowed to use, and follow Wallapop terms plus applicable privacy laws (including GDPR where relevant). Do not use the output for harassment or unsolicited contact.

Paste a category URL, set `maxItems`, and run Wallapop Listings Extractor on Apify.

# Actor input Schema

## `startUrls` (type: `array`):

Wallapop category, SEO landing, search, or item page URLs. Example: https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio

## `keywords` (type: `array`):

Optional. Keywords to search on Wallapop when you do not already have a URL. One phrase per line.

## `countryCode` (type: `string`):

Wallapop market used when building search URLs from keywords. Ignored when the start URL already includes a country host.

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

Maximum number of Wallapop listings to collect per run.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout in seconds.

## Actor input object example

```json
{
  "startUrls": [
    "https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio"
  ],
  "keywords": [
    "iphone 14",
    "bicicleta"
  ],
  "countryCode": "ES",
  "maxItems": 100,
  "requestTimeoutSecs": 60
}
```

# Actor output Schema

## `listings` (type: `string`):

Dataset of clean Wallapop listings with title, price, images, seller, and shipping fields.

# 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 = {
    "startUrls": [
        "https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/wallapop-listings-extractor").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 = { "startUrls": ["https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio"] }

# Run the Actor and wait for it to finish
run = client.actor("kawsar/wallapop-listings-extractor").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 '{
  "startUrls": [
    "https://es.wallapop.com/muebles-deco-y-jardin/sillas-de-escritorio"
  ]
}' |
apify call kawsar/wallapop-listings-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/wallapop-listings-extractor"
        }
    }
}
```

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/bKpqEDbLbtpJJgKrm/builds/1uw4U4EDsWlW4j4eA/openapi.json
