# Marktplaats Scraper: Listings & Prices (`tortuga/marktplaats-scraper`) Actor

Marktplaats.nl listings from any keyword or search, category or seller URL: title, price and price type, condition, city and distance, posted date, attributes, photos, shipping options, seller name and business flag, with optional full descriptions. Dutch classifieds data, no login.

- **URL**: https://apify.com/tortuga/marktplaats-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listings

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?

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

## Marktplaats Scraper: Listings, Prices & Sellers

Scrape Marktplaats listings from Marktplaats.nl, the largest classifieds site in the Netherlands: title, price and price type (fixed, "Bieden", free, "Zie omschrijving"), condition, delivery option, category, city and distance, posting date, attributes, all photos, seller name and listing URL. Start from any Marktplaats search, category or seller URL (with the filters you set on the site), or just type a few keywords with a price range, a postcode and a radius. Turn on **Include listing details** to add the full description, the complete "Kenmerken" table, the seller type (private or business), views and favourites, the exact posting time and the shipping options.

It reads the same JSON search service the Marktplaats website loads, so one request returns up to 100 listings and a run of a few hundred listings finishes in seconds on Apify's datacenter proxies. Export to JSON, CSV or Excel, or pull the results through the API into your app, a spreadsheet, a price-monitoring workflow or an LLM pipeline.

### What data does Marktplaats Scraper extract?

| Field | Description |
|---|---|
| `listingId`, `url` | Marktplaats listing id (`m2116011581`; `a...` for Admarkt business ads) and listing URL |
| `title`, `description` | Title and the description (the search snippet; the full text with **Include listing details**) |
| `price`, `priceText`, `priceType`, `currency` | Asking price in EUR as a number (`99.0`), the price as shown (`"€ 99,00"`, `"Bieden vanaf € 125,00"`, `"Zie omschrijving"`) and its kind: `fixed`, `bid`, `free`, `see_description`, `exchange`, `negotiable`, `on_request`, `reserved` |
| `condition`, `delivery`, `shippingAvailable` | e.g. `"Gebruikt"`, `"Ophalen of Verzenden"`, `true` |
| `attributes` | Every attribute the search shows, as `{key: value}`: `{"condition": "Gebruikt", "delivery": "Ophalen", "brand": "Gazelle", "frameHeight": "50 tot 53 cm", ...}` |
| `category`, `categoryId`, `l1CategoryId`, `categoryKeys` | e.g. `"Fietsen \| Dames \| Damesfietsen"`, `447`, `445`, `["fietsen-en-brommers", "fietsen-dames-damesfietsen"]` |
| `city`, `country`, `latitude`, `longitude`, `distanceKm` | The town shown on the listing and its centre coordinates (not the seller's address); distance from your postcode when you search around one |
| `postedAt`, `dateText` | The date the search shows, as ISO (`"2026-10-30"`) and as shown (`"Eergisteren"`, `"28 okt 26"`); it moves when a seller bumps the listing. With details `postedAt` is the exact time the listing was first placed (`"2026-09-03T08:20:23Z"`) |
| `sellerId`, `sellerName`, `sellerUrl`, `sellerVerified`, `sellerWebsiteUrl` | Seller id, display name, the seller's listings page, verified badge, website link of business advertisers |
| `sellerType` | `business` or `private`. From a search answer only business advertisers are recognised; with details every listing gets it |
| `photos`, `photoCount`, `thumbnailUrl` | All photo URLs in large size |
| `status`, `isReserved` | `active` or `reserved` |
| `isTopAd`, `promotionLabel`, `isAdmarkt`, `stickerText` | Paid placement (`"Dagtopper"`, `"Topadvertentie"`), Admarkt business ad, promotional sticker text |
| `searchUrl`, `position`, `scrapedAt` | The search the listing came from, its rank in that search and when it was scraped |
| With details: `specifications`, `sellerSince`, `sellerActiveYears`, `sellerProfileUrl`, `sellerCity`, `viewCount`, `favoriteCount`, `categoryPath`, `shippingOptions`, `biddingEnabled`, `currentMinimumBid`, `bids`, `buyerProtection`, `adType` | The "Kenmerken" table as `{"Conditie": "Gebruikt", "Merk": "Gazelle"}`, "6 jaar" on Marktplaats, profile page, views, favourites, shipping carriers and prices, bidding status, `detailsFetched: true` |

### How to scrape Marktplaats listings

1. Open [marktplaats.nl](https://www.marktplaats.nl), search, and set the filters you want (category, price, postcode and distance, condition, "Aangeboden sinds", sort).
2. Copy the URL from the address bar into **Start URLs**. Add as many searches as you like; category pages, seller pages and single listing URLs work too.
3. Or skip the browser: type **Search terms** (one per line) and set **Min / Max price**, **Postcode** + **Distance**, **Sort** and **Offered since**.
4. Set **Max items**, tick **Include listing details** if you need the full description and the seller type, and click **Start**. Download the results as JSON, CSV or Excel, or read them through the API.

### Which Marktplaats URLs work

- Search results: `https://www.marktplaats.nl/q/elektrische+fiets/` (page 2: `.../p/2/`)
- Category pages: `https://www.marktplaats.nl/l/fietsen-en-brommers/fietsen-dames-damesfietsen/`, including a keyword inside a category (`.../q/gazelle/`) and the SEO filter pages (`.../f/gazelle/1234/`)
- Seller pages: `https://www.marktplaats.nl/u/030-fietsen/39689712/` (all listings of one seller)
- Single listings: `https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-dames-damesfietsen/m2116011581-...` (returns that listing with full details)
- Filters in the URL hash are applied: `#PriceCentsFrom:5000|PriceCentsTo:20000|postcode:1012AB|distanceMeters:10000|sortBy:SORT_INDEX|sortOrder:DECREASING|offeredSince:Vandaag|f:30`

Marktplaats serves at most 5,000 listings per search (50 pages of 100). To collect more, split the search by category, price band or distance and add each as its own start URL; listings that appear in several of your searches are saved and charged only once per run.

### Input example

```json
{
  "startUrls": [
    { "url": "https://www.marktplaats.nl/l/fietsen-en-brommers/elektrische-fietsen/#PriceCentsFrom:50000|PriceCentsTo:150000|postcode:3511AA|distanceMeters:25000" },
    { "url": "https://www.marktplaats.nl/u/030-fietsen/39689712/" }
  ],
  "searchTerms": ["gazelle damesfiets", "cortina u4"],
  "minPrice": 100,
  "maxPrice": 600,
  "postcode": "1012AB",
  "distanceKm": 25,
  "sort": "newest",
  "offeredSince": "Een week",
  "maxItems": 300,
  "maxPagesPerSearch": 5,
  "includeDetails": false
}
```

### Output example

```json
{
  "listingId": "m2116011581",
  "title": "Dames fietsen heren fietsen oma fietsen Low budget",
  "description": "Wij van 030 fietsen hebben weer nieuwe voorraad 2e hands fietsen dames fietsen heren fietsen oma fietsen kinder fietsen zeer grote voorraad van 300 rijklare fietsen nu zeer scherpe prijzen vanaf ...",
  "price": 99.0,
  "priceText": "€ 99,00",
  "priceType": "fixed",
  "currency": "EUR",
  "condition": "Gebruikt",
  "delivery": "Ophalen of Verzenden",
  "shippingAvailable": true,
  "categoryId": 447,
  "l1CategoryId": 445,
  "category": "Fietsen | Dames | Damesfietsen",
  "categoryKeys": ["fietsen-en-brommers", "fietsen-dames-damesfietsen"],
  "city": "Utrecht",
  "country": "Nederland",
  "latitude": 52.093055771437,
  "longitude": 5.1234611252344,
  "distanceKm": null,
  "postedAt": "2026-10-30",
  "dateText": "Eergisteren",
  "sellerId": 39689712,
  "sellerName": "030 fietsen",
  "sellerType": null,
  "sellerVerified": false,
  "sellerUrl": "https://www.marktplaats.nl/u/030-fietsen/39689712/",
  "sellerWebsiteUrl": null,
  "attributes": { "condition": "Gebruikt", "delivery": "Ophalen of Verzenden", "brand": "Overige merken" },
  "photos": ["https://images.marktplaats.com/api/v1/hz-mp-pro-listing/images/1c/1c1eb733-9db3-4e64-81fd-7db3b013c77d?rule=ecg_mp_eps$_85.jpg"],
  "photoCount": 1,
  "thumbnailUrl": "https://images.marktplaats.com/api/v1/hz-mp-pro-listing/images/1c/1c1eb733-9db3-4e64-81fd-7db3b013c77d?rule=ecg_mp_eps$_85.jpg",
  "url": "https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-dames-damesfietsen/m2116011581-dames-fietsen-heren-fietsen-oma-fietsen-low-budget",
  "status": "active",
  "isReserved": false,
  "isAdmarkt": false,
  "isTopAd": true,
  "promotionLabel": "Dagtopper",
  "stickerText": null,
  "detailsFetched": false,
  "searchUrl": "https://www.marktplaats.nl/q/fiets/#sortBy:SORT_INDEX|sortOrder:DECREASING",
  "position": 1,
  "scrapedAt": "2026-11-01T12:40:00+00:00"
}
```

With **Include listing details** the same listing also carries `"sellerType": "business"`, `"sellerSince": "6 jaar"`, `"specifications": {"Conditie": "Gebruikt", "Merk": "Overige merken"}`, `"viewCount": 5933`, `"favoriteCount": 59`, `"postedAt": "2024-05-17T12:23:56Z"`, the full multi-line description, `shippingOptions` and `biddingEnabled`.

### Monitor new Marktplaats listings on a schedule

Turn on **Only new or changed items** to watch a search: each run remembers what earlier runs returned and outputs only listings that are new or whose price, price type or status (reserved) changed. Unchanged listings are dropped before they are saved, so they are not charged, and with details on their pages are not even opened. **Max items** then sets how many listings are checked per run (keep the newest-first sort, e.g. the newest 50-100 of a search, and **Offered since** "Today" or "Last week" to keep runs small). Save the input as a task and add a Schedule in Apify (every 15 minutes, hourly or daily); give each watch its own **Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or `changed`), and changed items have `previousValues` with the old values, e.g. `{"price": 125.0}`.

### Does it need a login or a proxy?

No login is needed and none is used: the scraper reads what any visitor sees. Marktplaats answers Apify's standard datacenter proxies (the default) for search results and listing pages, so no residential proxy is needed. A search request returns up to 100 listings in one 0.4 MB answer and a listing page is about 0.1 MB, so a run of 1,000 listings takes a few seconds and a few tenths of a cent of platform usage, which is included in the price.

### Pricing

Pay per result: you are charged per listing saved to the dataset, and an extra detail event for each listing page opened when **Include listing details** is on. There is no start fee, and platform usage (proxy traffic and compute) is included in the event prices. See the Pricing tab for the current prices; use `maxItems` to cap the cost of each run.

### Integrations and API

Run it from the Apify API, schedule it (for example every hour for new listings around your postcode), and send the results to Google Sheets, Slack, Make, Zapier, n8n or a webhook. The run's `SUMMARY` record in the key-value store lists the request counts, the number of matching listings per search and any errors.

### Is it legal to scrape Marktplaats?

This Actor collects publicly visible listing data that anyone can see without an account. It does not log in, never requests phone numbers (they sit behind a click on the site), and exports no seller address: the coordinates are those of the town shown on the listing, and the description is exported as the seller wrote it. Seller names are personal data under the GDPR when they belong to private individuals: you are responsible for having a legitimate purpose and a legal basis for processing them, and for respecting Marktplaats' terms of use. If in doubt, ask a lawyer.

### Support

Found a bug or need a field that is not there? Open an issue on the Issues tab with the input you used and the run link.

### Related scrapers

- [Gumtree UK Scraper](https://apify.com/tortuga/gumtree-scraper): Listings, Prices & Sellers
- [Kleinanzeigen Scraper](https://apify.com/tortuga/kleinanzeigen-scraper): Listings, Prices & Sellers
- [Vinted Scraper](https://apify.com/tortuga/vinted-scraper): Listings, Prices & Sellers (All Countries)
- [OLX Brazil Scraper](https://apify.com/tortuga/olx-brazil-scraper): Listings, Prices & Sellers
- [Allegro Scraper](https://apify.com/tortuga/allegro-scraper): Offers, Prices & Sellers (Poland)

### Found it useful?

A ★ review on this Actor's Apify Store page helps other users find it and tells us what to improve. Issues and feature requests are welcome in the Actor's **Issues** tab.

# Actor input Schema

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

Marktplaats.nl pages to scrape: search results (https://www.marktplaats.nl/q/elektrische+fiets/), category pages (https://www.marktplaats.nl/l/fietsen-en-brommers/fietsen-dames-damesfietsen/), seller pages (https://www.marktplaats.nl/u/030-fietsen/39689712/) or single listings (https://www.marktplaats.nl/v/.../m2116011581-...). Filters set on the site (price, postcode and distance, condition, sort, 'Aangeboden sinds') travel in the URL after '#' and are applied too. Leave empty if you use Search terms.

## `searchTerms` (type: `array`):

Keywords searched site-wide, one per line, as you would type them in the Marktplaats search box, e.g. "fiets", "iphone 15", "playmobil". The price, postcode, distance, sort and offered-since fields below apply to these searches.

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

Used with Search terms: lowest asking price in euros.

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

Used with Search terms: highest asking price in euros. Listings without a price ("Bieden", "Zie omschrijving") are still included, as on the site.

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

Used with Search terms: a Dutch postcode to search around, e.g. 1012AB. Each result then carries its distance from it.

## `distanceKm` (type: `integer`):

Used with Postcode: search radius in kilometres (the site offers 3, 5, 10, 15, 25, 50 and 75 km; any whole number works). Leave empty for the whole country.

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

Used with Search terms. Newest first is the best choice for monitoring new listings. Start URLs keep the sort set in the URL.

## `offeredSince` (type: `string`):

Used with Search terms: only listings placed today (Vandaag), since yesterday (Gisteren) or in the last week (Een week). Leave empty for all listings.

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

Stop after this many listings in total (across all searches). Keeps the cost predictable. Marktplaats serves at most 5,000 listings per search; split bigger searches by category, price range or distance.

## `maxPagesPerSearch` (type: `integer`):

Stop each search after this many result pages of up to 100 listings each (1-50). Useful when you monitor several searches in one run and only the newest listings matter.

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

Also open every listing page for the full description, the complete 'Kenmerken' table, seller type (private or business), seller profile and 'years on Marktplaats', view and favourite counts, exact posting time, shipping options and bidding status. One extra request per listing; charged as an extra 'detail' event (see pricing).

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new listings or listings whose price or status changed. Use with a Schedule; unchanged listings are not charged. With this on, Max items is the number of listings checked per run (e.g. the newest 100).

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

Marktplaats answers Apify datacenter proxies (the default) for search results and listing pages; no residential proxy is needed. A search request returns up to 100 listings (about 0.4 MB), a listing page is about 0.1 MB.

## Actor input object example

```json
{
  "searchTerms": [
    "fiets"
  ],
  "sort": "newest",
  "maxItems": 20,
  "maxPagesPerSearch": 1,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchTerms": [
        "fiets"
    ],
    "maxItems": 20,
    "maxPagesPerSearch": 1,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/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 = {
    "searchTerms": ["fiets"],
    "maxItems": 20,
    "maxPagesPerSearch": 1,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/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 '{
  "searchTerms": [
    "fiets"
  ],
  "maxItems": 20,
  "maxPagesPerSearch": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/marktplaats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/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/17yotoKRPJkJIdY7u/builds/g98wzkURCv5acxaBa/openapi.json
