# Marktplaats Scraper - Listings, Prices & Sellers (`sian.agency/marktplaats-scraper`) Actor

Scrape Marktplaats.nl listings by keyword, category or pasted URL: price, condition, delivery, location with GPS, seller, photos and full descriptions. Covers 2dehands.be and 2ememain.be too.

- **URL**: https://apify.com/sian.agency/marktplaats-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** E-commerce, Lead generation, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.79 / 1,000 listing searches

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?

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

## Marktplaats Scraper — Listings, Prices & Sellers 🇳🇱

[![Store-SIÁN Agency](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Store-Craigslist Scraper](https://img.shields.io/badge/Store-Craigslist%20Scraper-5F1D82)](https://apify.com/sian.agency/craigslist-scraper?fpr=sian) [![Store-eBay Data Scraper](https://img.shields.io/badge/Store-eBay%20Data%20Scraper-E53238)](https://apify.com/sian.agency/ebay-data-scraper?fpr=sian) [![Store-Avito Property Scraper](https://img.shields.io/badge/Store-Avito%20Property%20Scraper-00AAFF)](https://apify.com/sian.agency/avito-property-scraper?fpr=sian)

#### 🎉 100 ads per request, from $0.90 per 1,000 — the cheapest Marktplaats API on the Store

##### Cars, bikes, furniture, phones and property, on marktplaats.nl plus 2dehands.be and 2ememain.be

***

### 🔎 What is the Marktplaats Scraper — and when should you use it?

The **Marktplaats Scraper** turns public classified ads from Marktplaats.nl and its two Belgian sister sites into clean, structured rows you can filter, export and feed straight into a spreadsheet, database or AI agent. No account, no portal API key, no browser automation to maintain.

**Use it when you need:** ads from a keyword, a whole category or a search URL you paste. Each row carries the title, the asking price and how that price works, the condition the seller claims, whether they ship or expect collection, the city with coordinates, the seller, every photo and the category's own attribute table. Cars come with mileage and fuel, bikes with frame size, phones with storage. Ask for the ad page too and each row also gets the view count, the favourite count, the exact posting timestamp, the untruncated text and the seller's profile.

**Use something else when:** the ad is not on one of these three sites. Use [Craigslist Scraper](https://apify.com/sian.agency/craigslist-scraper?fpr=sian) for the same local classifieds pattern in North America and beyond, where this one covers the Low Countries. Use [eBay Data Scraper](https://apify.com/sian.agency/ebay-data-scraper?fpr=sian) for auction and retail listings with shipping and sold prices, where Marktplaats is largely local and cash-in-hand. Use [Avito Property Scraper](https://apify.com/sian.agency/avito-property-scraper?fpr=sian) for the equivalent Russian classifieds board. Seller phone numbers and email addresses are not returned, because the site does not publish them — buyers contact sellers through its own inbox. Sold prices are not available either: ads disappear when they sell and the site keeps no public archive, so what comes back is asking prices on live ads.

### 🤖 Use with AI agents

Already connected to the [Apify MCP server](https://mcp.apify.com)? Just ask for this Actor by name: sian.agency/marktplaats-scraper

**Your agent can pay for its own runs.** This Actor is eligible for [agentic payments](https://docs.apify.com/platform/actors/publishing/monetize), so an agent can discover it, run it and settle the bill over [x402](https://www.x402.org/) (USDC on Base) or [Skyfire](https://www.skyfire.xyz/) — without an Apify account or API token of its own. Billing is the same either way: per successful row, never for errors.

Otherwise copy this prompt into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```text
I want listings and prices from Marktplaats using the Apify Actor `sian.agency/marktplaats-scraper`.

Use it when I need: ads from a keyword, a whole category or a search URL you paste. Each row carries the title, the asking price and how that price works, the condition the seller claims, whether they ship or expect collection, the city with coordinates, the seller, every photo and the category's own attribute table. Cars come with mileage and fuel, bikes with frame size, phones with storage. Ask for the ad page too and each row also gets the view count, the favourite count, the exact posting timestamp, the untruncated text and the seller's profile.

Don't use it when: the ad is not on one of these three sites — use craigslist-scraper or ebay-data-scraper or avito-property-scraper instead.

How to call it: give `query` a keyword, or pick a `category`, or both. Narrow with `minPrice`, `maxPrice`, `condition`, `delivery`, `buyItNowOnly`, `postedSince`, or a `postcode` plus `radiusKm`. `sort` takes `newest`, `price-asc` or `price-desc`. Set `site` to `2dehands.be` or `2ememain.be` for the Belgian market. `includeDetails` opens each ad's own page for view counts, favourites, the exact timestamp and the full text, at an extra charge per ad. To pull one seller's whole inventory, set `operation` to `seller` and pass `sellers`; to expand ads you already have, set `operation` to `detail` and pass `listingUrls`; to reuse a search you built on the site, paste it into `searchUrls`.

Start with this input:
{
  "operation": "search",
  "query": "racefiets",
  "category": "fietsen-en-brommers",
  "condition": "used",
  "maxPrice": 800,
  "sort": "price-asc",
  "maxResults": 200
}

Ask me what they are looking for and which market — the Dutch site or one of the two Belgian ones — plus whether they want a price ceiling, then run the Actor and summarise the results as a table.
```

**Things you can ask your agent for:**

- *Find every electric bike under 800 euros posted in the last week within 25 km of Amsterdam, cheapest first.*
- *Pull the full inventory of this Marktplaats car dealer and show me asking price against mileage.*
- *Track second-hand iPhone prices on Marktplaats and 2dehands daily, and tell me which listings are new since yesterday.*

Machine-readable API, MCP config and OpenAPI definition for this Actor are published at [apify.com/sian.agency/marktplaats-scraper.md](https://apify.com/sian.agency/marktplaats-scraper.md).

### 📋 Overview

**Marktplaats is where the Netherlands buys and sells second-hand.** The Cars section alone carries around 250,000 live ads. This actor turns any slice of that into rows you can sort, filter and put in a spreadsheet.

**What you get:**

- ✅ **100 ads per request**: one call brings back a hundred rows, so a 5,000-ad sweep is fifty requests, not five hundred.
- ⚡ **From $0.90 per 1,000 ads**: under every comparable tool on the Store. There is no key to buy and no proxy bill behind it.
- 🎯 **41 fields per ad**: asking price and how the price works, condition, delivery, city with coordinates, seller, category attributes and every photo.
- 🇧🇪 **Three markets, one actor**: marktplaats.nl in Dutch, 2dehands.be in Dutch, 2ememain.be in French. Nothing else on the Store reaches the Belgian inventory at all.
- 🏪 **A whole seller's stock in one run**: hand it a dealer and get their entire forecourt with asking prices.
- 🔗 **Paste a URL and it just works**: sub-categories, car makes and models, fuel type, frame size. The site resolves the address itself, so filters this actor has never heard of still apply.
- ✨ **Ad-page enrichment on demand**: view counts, favourites, the exact posting timestamp, the untruncated text and the seller's profile.

***

### ✨ Features

- 🔍 **Keyword and category search**: search the whole site, one of 36 sections, or a keyword inside a section.
- 🏪 **Seller inventory**: every live ad one seller or dealer has, from their profile URL or numeric ID.
- 📄 **Ad detail**: open an ad by URL or by bare ID and get the fields a search result cannot carry.
- 🌐 **Pasted search URLs**: copy any address from the site and the filters travel with it.
- 💶 **Price bands**: min and max in whole euros, applied by the site before it counts results.
- 📍 **Postcode radius**: centre on a postcode and every row comes back with a measured distance.
- ✨ **Condition and delivery filters**: new, as-new, used, refurbished, not working; ships or collection only.
- ⚡ **Buy-it-now filter**: skip every bidding and negotiate-by-message ad in one click.
- 🆕 **Posted-today filter**: run it on a schedule and pay only for what appeared since the last run.
- ↕️ **Five sort orders**: newest, oldest, relevance, cheapest first, most expensive first.

***

### 🎬 Quick Start

Pick a keyword or a category, set how many ads you want, press Start. There is no account to connect and no key to paste. Results land in a dataset you can export as JSON, CSV or Excel.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~marktplaats-scraper/runs?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"operation":"search","query":"racefiets","category":"fietsen-en-brommers","maxResults":200}'
```

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose what to search

Type a keyword, pick one of the 36 categories, or paste a search URL you built on the site. Any of the three works on its own.

#### Step 2: Narrow it

Set a price band, a condition, a postcode radius, or "posted today". Every filter is applied by the site before it counts results, so a narrow search is a cheap search.

#### Step 3: Press Start

Results appear as they arrive. Export as JSON, CSV or Excel, or read them straight off the API.

**That's it. Within about a minute you'll have:**

- Every matching ad with its asking price and condition
- The city and coordinates for each one, and the distance if you set a postcode
- The seller behind every ad, ready to expand into their whole inventory

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|---|---|---|---|
| `operation` | string | No | `search`, `seller` or `detail`. Defaults to `search`. |
| `site` | string | No | `marktplaats.nl`, `2dehands.be` or `2ememain.be`. |
| `query` | string | No | Keyword to search for, in the site's own language. |
| `category` | string | No | One of 36 top-level sections. Empty searches everything. |
| `searchUrls` | array | No | Search or category URLs copied from the site. |
| `listingUrls` | array | No | Ad URLs, for the `detail` operation. An ID-only ad is addressed as `https://link.marktplaats.nl/<ad id>`. |
| `sellers` | array | No | Seller profile URLs or numeric IDs, for the `seller` operation. |
| `maxResults` | integer | No | Whole-run ad budget. Defaults to 100. |
| `includeDetails` | boolean | No | Open each ad's page for the extra fields. Bills one extra event per ad. |
| `minPrice` / `maxPrice` | integer | No | Price band in whole euros. 0 means no bound. |
| `condition` | string | No | `new`, `as-new`, `used`, `refurbished`, `not-working`. |
| `delivery` | string | No | `shipping` or `pickup`. |
| `buyItNowOnly` | boolean | No | Only ads with an immediate purchase price. |
| `postedSince` | string | No | `today`, `yesterday`, `week` or `always`. |
| `postcode` / `radiusKm` | string / integer | No | Centre the search and add a distance to every row. |
| `sort` | string | No | `newest`, `oldest`, `relevance`, `price-asc`, `price-desc`. |

**Example — a keyword search with filters:**

```json
{
  "operation": "search",
  "query": "racefiets",
  "category": "fietsen-en-brommers",
  "condition": "used",
  "maxPrice": 800,
  "sort": "price-asc",
  "maxResults": 200
}
```

**Example — one dealer's whole inventory:**

```json
{
  "operation": "seller",
  "sellers": ["https://www.marktplaats.nl/u/automobielbedrijf-jaarsma/21238785/"],
  "maxResults": 500
}
```

**Example — expand ads you already have:**

```json
{
  "operation": "detail",
  "listingUrls": ["m2436480962", "m2435202000"]
}
```

***

### 📤 Output

Every row is flat, and all three operations return the same shape, so results merge cleanly. **41 fields**, including:

| Field | Type | Description |
|---|---|---|
| `itemId` | string | The site's own ad ID. Stable — this is what you dedupe on. |
| `listingTitle` | string | The ad headline as the seller wrote it. |
| `price` | number | Asking price in euros. Empty when the seller named none. |
| `priceType` | string | `FIXED`, `MIN_BID`, `SEE_DESCRIPTION`, `FREE` and the rest. |
| `condition` | string | What the seller selected: Nieuw, Gebruikt, Refurbished… |
| `delivery` | string | Whether they ship, expect collection, or offer both. |
| `city` / `latitude` / `longitude` | string / number | Where the item is. |
| `distanceKm` | number | Distance from your postcode, when you set one. |
| `imageUrls` | array | Every photo on the ad. |
| `sellerId` / `sellerName` | number / string | Who is selling. Feed the ID back in for their whole stock. |
| `attributes` | object | The category's own fields — mileage, fuel, frame size, storage. |
| `viewCount` / `favoriteCount` | number | How much attention the ad is getting. Needs enrichment. |
| `postedAt` | string | Exact posting timestamp, ISO 8601. Needs enrichment. |

**Example row:**

```json
{
  "itemId": "m2436480962",
  "listingTitle": "jongens Batavus fiets 10-12 jaar met mand en versnellingen",
  "url": "https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-dames-damesfietsen/m2436480962-jongens-batavus-fiets",
  "price": 50,
  "priceText": "€ 50,00",
  "priceType": "FIXED",
  "condition": "Gebruikt",
  "delivery": "Ophalen",
  "city": "Enkhuizen",
  "country": "NL",
  "latitude": 52.701828425806,
  "longitude": 5.2859389814468,
  "postedLabel": "Vandaag",
  "postedAt": "2026-08-29T10:01:23Z",
  "viewCount": 133,
  "favoriteCount": 2,
  "imageCount": 6,
  "sellerId": 7530354,
  "sellerName": "Francois",
  "sellerType": "CONSUMER",
  "sellerActiveYears": 19,
  "categoryName": "Fietsen | Dames | Damesfietsen",
  "attributes": { "condition": "Gebruikt", "brakeType": "Terugtraprem" },
  "site": "marktplaats.nl",
  "status": "success"
}
```

***

### 💼 Use Cases & Examples

#### 1. Resale sourcing and price arbitrage

**Resellers who need the bottom of a price distribution, not a sample of it.**

**Input:** a category, `sort: "price-asc"`, `buyItNowOnly: true`, a price ceiling.
**Output:** the cheapest live stock in that section, with photos and the seller behind each one.
**Use:** buy under market and relist. Turning on the ships-to-buyer filter makes the whole country local.

#### 2. Used-car and dealer inventory tracking

**Dealers and market analysts watching what the trade is actually asking.**

**Input:** the Cars category, or a dealer's seller ID.
**Output:** asking price against mileage, fuel and transmission, across a make or a single forecourt.
**Use:** price your own stock against the live market instead of against last quarter's guide.

#### 3. Second-hand price research

**Analysts who need a defensible number for what a used thing is worth.**

**Input:** a keyword, a wide price band, `includeDetails: true`.
**Output:** thousands of asking prices with the condition claimed, how long each ad has been up and how many people looked at it.
**Use:** separate a fair price from an optimistic one, at a sample size a manual check could never reach.

#### 4. New-listing monitoring and alerts

**Buyers hunting something scarce, and traders who want first look.**

**Input:** a narrow search plus `postedSince: "today"`, on a schedule.
**Output:** only the ads that appeared since your last run.
**Use:** a daily watch on a niche category that costs cents, because you never re-pay for yesterday.

#### 5. Seller and trade lead generation

**Agencies selling to small businesses that advertise here openly.**

**Input:** a trade-heavy category with `includeDetails: true`.
**Output:** business sellers with their name, type, years active and public profile page.
**Use:** build a prospect list of car dealers, tradespeople or furniture shops with proof they are trading.

#### 6. Property and rental sourcing

**Anyone working the private-landlord end of the Dutch market.**

**Input:** Houses & rooms, a postcode radius, `postedSince: "week"`.
**Output:** rooms, apartments and houses posted by owners rather than agencies, with coordinates.
**Use:** reach a listing before it hits the portals, or map supply and asking rent by neighbourhood.

#### 7. Cross-border price comparison

**Traders working both sides of the Dutch-Belgian border.**

**Input:** the same query run against `marktplaats.nl` and `2dehands.be`.
**Output:** two datasets in one shape, with a `site` column to split on.
**Use:** find the categories where Belgian stock is systematically cheaper, and move it.

***

### 🔗 Integration Examples

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/marktplaats-scraper').call({
  operation: 'search',
  query: 'racefiets',
  category: 'fietsen-en-brommers',
  maxPrice: 800,
  sort: 'price-asc',
  maxResults: 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/marktplaats-scraper').call(run_input={
    'operation': 'search',
    'query': 'racefiets',
    'category': 'fietsen-en-brommers',
    'maxPrice': 800,
    'sort': 'price-asc',
    'maxResults': 200,
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['listingTitle'], item['price'])
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~marktplaats-scraper/runs?token=YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"operation":"search","query":"racefiets","maxPrice":800,"sort":"price-asc"}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: a daily schedule.
2. **HTTP Request**: run this actor with `postedSince: "today"`.
3. **Process**: compare the returned `itemId` list against yesterday's.
4. **Action**: post the new ads to Slack, or append them to a sheet.

***

### 📊 Performance & Pricing

#### FREE tier (try it now)

- **25 ads per run**, with every feature and every field switched on
- No credit card, no key, no account on the site
- Enough to see the exact shape of the data before you commit

#### PAID tier (production)

- **Unlimited ads per run**, up to the site's own 5,000-per-query ceiling
- Roughly 100 ads per second on a plain search
- Charged per ad returned. Failed inputs come back as rows explaining why, and are never charged.

💰 **From $0.90 per 1,000 ads**, falling to $0.70 at DIAMOND. Ad-page enrichment is $2.50 per 1,000 when you switch it on, and nothing when you don't.

🔗 [View current pricing](https://apify.com/sian.agency/marktplaats-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: Do I need an API key, a login or a proxy?**
A: No. Type a keyword and press Start.

**Q: How many ads can one search return?**
A: Up to 5,000. That is the site's own paging ceiling, not ours — the result counter will happily say 250,000 while only the first 5,000 are reachable. To go wider, split the query into more categories, tighter price bands, or a postcode radius per region.

**Q: Which sites does it cover?**
A: Marktplaats.nl plus its two Belgian sister sites, 2dehands.be in Dutch and 2ememain.be in French. The categories and filters are identical on all three.

**Q: Can I paste a URL instead of filling in filters?**
A: Yes. The site resolves the address itself, so sub-categories, car makes and models and fuel-type filters all carry over. The one exception is a filter the site keeps behind a `#` — those never leave your browser, so set them with the fields.

**Q: What does "Open each ad's page" add, and what does it cost?**
A: View count, favourite count, the exact posting timestamp, the untruncated description, every photo instead of just the first, and current bids. You also get the seller's profile with their type and years active. It costs one extra request per ad, billed as one Listing Detail event on top of the listing row.

**Q: Does it return seller phone numbers or email addresses?**
A: No. The site routes buyer contact through its own inbox and hides phone numbers behind a click, so there is nothing to read. You do get the seller's public profile URL, name, type and years active.

**Q: Why is the price empty on some rows?**
A: The seller did not set one. `priceType` tells you which case it is — a fixed price, a minimum bid, on request, free, or see-description. Turn on buy-it-now if you only want ads with a real number.

**Q: Can I get sold prices or price history?**
A: Not from the site — ads disappear when they sell and there is no public archive. Run this on a schedule and diff your own snapshots, which is how everyone builds that dataset.

***

### 🐛 Troubleshooting

**A search returns fewer ads than the match count says**

- The site caps any single query at 5,000 retrievable results. The counter reports the whole catalogue, not what you can page through.
- Split the query: add a category, tighten the price band, or run a postcode radius per region.

**A pasted URL comes back with "not a search or category page"**

- That address is an ad, a seller profile or the homepage. Open the results page on the site and copy the address from there.
- Ad URLs belong in **Ad URLs** with the operation set to Listing Detail. If all you have is the ad ID, address it as `https://link.marktplaats.nl/<ad id>`.

**A price filter dropped ads you expected to see**

- Setting either bound excludes ads with no fixed price — bidding, on request, see-description — because the site filters on the price field itself.
- Clear the bounds and filter on `price` in your own export instead.

**A seller comes back with "no live ads right now"**

- The ID resolved, but that account currently has nothing listed. Sellers go quiet between batches.
- Check the ID: it is the numeric segment of a profile URL, `/u/name/7530354/`, not the ad ID.

**The condition column is empty on some rows**

- Condition is optional when a seller posts, and some categories do not offer it at all.
- Filtering on condition returns only ads where the seller set it, which is a smaller and cleaner set.

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

Marktplaats, 2dehands and 2ememain are trademarks of their respective owners. This actor is not affiliated with, endorsed by, or sponsored by any of them.

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue on the [actor's Issues tab](https://apify.com/sian.agency/marktplaats-scraper/issues)
- Check the [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `operation` (type: `string`):

🎯 **ONE OPERATION PER RUN.** Each returns the same row shape, so results merge cleanly.

🔍 **Listing Search** — a keyword, a whole category, or a search URL you paste. 100 ads per request.
🏪 **Seller Listings** — every live ad a seller or dealer has, from their profile URL or numeric ID.
📄 **Listing Detail** — ad URLs or IDs in, and back come view count, favourites, the exact posting timestamp, the untruncated text, the whole photo gallery and the seller's profile.

## `site` (type: `string`):

🌍 **WHICH SITE TO READ.** All three run the same catalogue software, so categories and filters behave identically.

🇳🇱 **marktplaats.nl** — the Dutch market, and by far the largest.
🇧🇪 **2dehands.be** — the Belgian market in Dutch.
🇧🇪 **2ememain.be** — the same Belgian inventory in French.

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

🔑 **WHAT TO SEARCH FOR.** Searches the ad title and body, in the site's own language where it matters ('fiets' finds more than 'bicycle').

💡 **TIP:** leave this empty and pick a category to sweep that whole section — the fastest way to build a full inventory snapshot.

🧩 Keyword and category combine: 'iphone' inside 📱 Phones & telecom is narrower than either alone.

## `category` (type: `string`):

🗂️ **WHICH SECTION TO SWEEP.** 🌐 All categories searches the whole site.

💡 **TIP:** an empty keyword plus a category returns that section newest-first — the shape you want for a daily monitor.

🔗 **Going deeper:** to target a sub-category (Elektrische fietsen, a specific car make), open it on the site and paste that address into 🌐 Search URLs instead.

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

🌐 **PASTE URLS INSTEAD OF FILLING THE FORM.** Copy any search, category or sub-category address from the site and drop it here.

🧠 **The site resolves each URL itself**, so every filter baked into it is honoured — sub-categories, car makes and models, fuel type, frame size, and facets added after this actor shipped.

📥 **BULK EDIT:** paste many URLs, one per line, or upload a .txt file.

⚠️ Filters the site keeps behind a `#` never leave your browser — set those with the fields below.

## `listingUrls` (type: `array`):

📄 **USED BY THE LISTING DETAIL OPERATION.** Which ads to open.

✅ **SUPPORTED:** the full ad URL, copied from your browser or taken from any row this actor returns.

🧠 Only have the ad ID? Address it as `https://link.marktplaats.nl/m0000000000` (or `link.2dehands.be`, `link.2ememain.be`) and the site resolves it to the live ad — so an ad that moved category still opens.

📥 **BULK EDIT:** paste many, one per line, or upload a .txt file.

## `sellers` (type: `array`):

🏪 **USED BY THE SELLER LISTINGS OPERATION.** Whose inventory to pull.

✅ **SUPPORTED:** the seller profile URL from any of their ads (`https://www.marktplaats.nl/u/name/7530354/`), or the bare numeric seller ID.

💡 **TIP:** every row this actor returns carries 👤 Seller ID — feed those straight back in here to expand a dealer you found in a search.

## `maxResults` (type: `integer`):

🔢 **HOW MANY ADS TO RETURN**, across everything the run touches.

📦 Each request brings back up to 100 ads, so the run finishes on the first request that crosses your number.

⚠️ The site stops paginating any single query at 5,000 results. To go past that, split the query — more categories, tighter price bands, or a postcode radius per region.

## `includeDetails` (type: `boolean`):

📄 **OPEN EACH AD'S OWN PAGE** for the fields a search result cannot carry: 👁️ view count, ❤️ favourites, 🕒 the exact posting timestamp, the untruncated description, the complete photo gallery, 🔨 current bids and the seller's profile with their type and years active.

💰 **COSTS EXTRA:** one additional request per ad, billed as one Listing Detail event on top of the listing row. Leave it off and you pay for listing rows only.

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

💵 **CHEAPEST ASKING PRICE TO INCLUDE**, in whole euros. 0 means no lower bound.

⚠️ Setting either bound drops ads with no fixed price — bidding, on request, see description — because the site filters on the price field itself.

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

💰 **MOST EXPENSIVE ASKING PRICE TO INCLUDE**, in whole euros. 0 means no upper bound.

💡 **TIP:** narrow price bands are how you get past the 5,000-result ceiling on a big category — run €0-100, €100-250, €250-500 and merge.

## `condition` (type: `string`):

✨ **RESTRICT TO ONE CONDITION.** Sellers pick this themselves when they post, so it is the ad's own claim rather than an inspection — but it is the field buyers filter on, and it splits a category cleanly into retail-grade and second-hand stock.

## `delivery` (type: `string`):

📦 **HOW THE ITEM CHANGES HANDS.**

🚚 **Ships to buyer** turns a local classifieds sweep into a national one: those sellers post anywhere in the country, so distance stops mattering.

🤝 **Collection only** is the opposite — pair it with a postcode radius for genuinely local stock.

## `buyItNowOnly` (type: `boolean`):

⚡ **ONLY ADS A BUYER CAN PURCHASE IMMEDIATELY** at the listed price, skipping every bidding and negotiate-by-message listing.

💡 **TIP:** this is the subset with a real, comparable number in the price field — turn it on before you compute any average.

## `postedSince` (type: `string`):

🆕 **RESTRICT TO RECENTLY POSTED ADS.**

💡 **TIP:** 🌅 Today is the cheap way to run this on a schedule — each run then bills only the ads that appeared since the last one, instead of re-paying for the whole category.

## `postcode` (type: `string`):

📮 **CENTRE THE SEARCH ON A POSTCODE.** 1011AB for Amsterdam, 3011 for Rotterdam, 2000 for Antwerp on the Belgian sites.

⚠️ **Needs 📏 Search radius** to do anything on its own.

📏 When both are set, every row comes back with a measured 📏 Distance (km).

## `radiusKm` (type: `integer`):

📏 **HOW FAR FROM THE POSTCODE TO LOOK**, in kilometres. 0 searches the whole country.

💡 **TIP:** a ring of 25 km searches around the five biggest cities covers most of the population and keeps each query under the 5,000-result ceiling.

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

↕️ **WHICH ADS COME FIRST.**

🕒 **Newest first** is what you want for monitoring.

💡 **TIP:** ⬆️ Cheapest first finds the bottom of a price distribution without paging through all 5,000 results — flip to ⬇️ most expensive and you have both ends in two small runs.

## Actor input object example

```json
{
  "operation": "search",
  "site": "marktplaats.nl",
  "query": "iphone",
  "category": "",
  "searchUrls": [
    "https://www.marktplaats.nl/l/fietsen-en-brommers/elektrische-fietsen/"
  ],
  "listingUrls": [
    "https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-dames-damesfietsen/m2436480962-jongens-batavus-fiets"
  ],
  "sellers": [
    "https://www.marktplaats.nl/u/automobielbedrijf-jaarsma/21238785/"
  ],
  "maxResults": 100,
  "includeDetails": false,
  "minPrice": 0,
  "maxPrice": 0,
  "condition": "any",
  "delivery": "any",
  "buyItNowOnly": false,
  "postedSince": "always",
  "postcode": "1011AB",
  "radiusKm": 0,
  "sort": "newest"
}
```

# Actor output Schema

## `marktplaatsListings` (type: `string`):

Every listing this run returned.

## `scrapingSummary` (type: `string`):

HTML summary showing successful and failed results with key metrics

# 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 = {
    "operation": "search",
    "site": "marktplaats.nl",
    "query": "iphone",
    "category": "",
    "searchUrls": [],
    "listingUrls": [],
    "sellers": [],
    "maxResults": 100,
    "includeDetails": false,
    "minPrice": 0,
    "maxPrice": 0,
    "condition": "any",
    "delivery": "any",
    "buyItNowOnly": false,
    "postedSince": "always",
    "postcode": "",
    "radiusKm": 0,
    "sort": "newest"
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/marktplaats-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 = {
    "operation": "search",
    "site": "marktplaats.nl",
    "query": "iphone",
    "category": "",
    "searchUrls": [],
    "listingUrls": [],
    "sellers": [],
    "maxResults": 100,
    "includeDetails": False,
    "minPrice": 0,
    "maxPrice": 0,
    "condition": "any",
    "delivery": "any",
    "buyItNowOnly": False,
    "postedSince": "always",
    "postcode": "",
    "radiusKm": 0,
    "sort": "newest",
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/marktplaats-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 '{
  "operation": "search",
  "site": "marktplaats.nl",
  "query": "iphone",
  "category": "",
  "searchUrls": [],
  "listingUrls": [],
  "sellers": [],
  "maxResults": 100,
  "includeDetails": false,
  "minPrice": 0,
  "maxPrice": 0,
  "condition": "any",
  "delivery": "any",
  "buyItNowOnly": false,
  "postedSince": "always",
  "postcode": "",
  "radiusKm": 0,
  "sort": "newest"
}' |
apify call sian.agency/marktplaats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sian.agency/marktplaats-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/PC0kCOfj7eMX54WDp/builds/qJgJOWzSpbwA4Z5PM/openapi.json
