# Marktplaats Scraper \[💰$1/1K] | NL + BE | Seller Leads (`ahmed_jasarevic/marktplaats-nl-scraper`) Actor

Scrape marktplaats.nl plus 2dehands.be and 2ememain.be by keyword or pasted URL. Get title, price, full description, location, category, attributes, images, view and favorite counts, plus seller lead data: seller name, ID, verified status, profile URL, reviews URL and contact options.

- **URL**: https://apify.com/ahmed_jasarevic/marktplaats-nl-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 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

## Marktplaats Scraper — Dutch & Belgian Classifieds Data (NL + BE)

Scrape **[marktplaats.nl](https://www.marktplaats.nl)** and its sister platforms **[2dehands.be](https://www.2dehands.be)** and **[2ememain.be](https://www.2ememain.be)** — one shared backend, one dataset — by keyword or by pasted URL. Get listing title, price and price type, full description, city and coordinates, category, attributes, image URLs, view and favorite counts, plus seller lead-generation data: seller name and ID, verified/professional status, profile and all-ads URLs, reviews URL, own-website link, member-since date, contact options and city. One row per listing, tagged with its platform.

Built for Dutch and Belgian classifieds market research, competitor price monitoring, seller lead generation, and building structured resale databases. The default dataset is one row per listing, optionally enriched from the listing's own detail page.

### Scrape Dutch & Belgian Classifieds For Market Research & Lead Generation

- **Price monitoring on marktplaats.nl** — fixed, bid, free or negotiable price types with view and favorite counts
- **Seller lead generation** — seller name, ID, verified/professional status, profile and all-ads URLs, reviews URL and contact options
- **Cross-border market coverage** — one `platform: "all"` run fans the same keyword out to the Netherlands and both Belgian platforms
- **Building a resale or e-commerce database** — full description, attributes map, image URLs and category tree
- **Competitor and inventory research** — category browsing with parent category and `postedAt` timestamps
- **Vehicle and product attribute extraction** — `attributes` / `attributesRaw` carry brand, mileage, fuel type and similar structured fields where the listing publishes them

### How It Works

![How the Marktplaats Scraper works: keyword searches become listing rows with prices, seller details and contact options.](https://api.apify.com/v2/key-value-stores/oeuA0kLOyhbRM4fzt/records/how-it-works-marktplaats.webp)

The Actor reads the internal search JSON behind Marktplaats, 2dehands and 2ememain, then follows offset pagination without a browser. Detail pages add the full description, exact posting date and seller lead fields.

Each row covers one listing with its price type, category, location, images, seller profile and contact options. Use it to track prices and build seller lead lists across the Benelux.

No browser is used — this is a plain HTTP `CheerioCrawler`. Three public surfaces are read, in order of preference:

1. **Internal search/browse JSON API (primary).** `GET https://www.marktplaats.nl/lrp/api/search?query=<q>&limit=50&offset=0&searchInTitleAndDescription=true&viewOptions=list-view` (same path on `2dehands.be` and `2ememain.be`) returns the same payload the page renders: `listings[]`, `totalResultCount`, `facets`, `searchRequest`, `categoriesById`. It needs no cookies, no consent cookie, no auth and no JavaScript, and it makes pagination trivial (`offset` / `limit`, up to 50 per page).
2. **Embedded `__NEXT_DATA__` JSON blob.** For a user-supplied search or category URL, the served Next.js HTML embeds the whole first result set and the exact original search request (`props.pageProps.searchRequestAndResponse`), which is then replayed against the JSON API for pages 2..n.
3. **Inline state blobs on the listing (VIP) page.** `window.__CONFIG__` carries the price, the exact posted timestamp (`stats.since`), the full category, the seller object (ID, name, type, active-since, profile and all-ads URLs, contact options), the gallery image URLs and the ad type; `window.__ENV_CONFIG__` carries the seller's reviews URL and the `/externalUrl/redirect/…` link to the seller's own website; and the DOM holds the **full, untruncated description**. These are fetched with plain HTTP through the crawler's request function, so the enrichment adds no rendering cost.

All three hosts return HTTP 200 to a normal request, so `PlaywrightCrawler` is never needed — that keeps runs fast and cheap.

### Input Parameters

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `searches` | array | No | `["fiets"]` | Keywords; one backend query each. |
| `startUrls` | array | No | — | Search pages, category pages or single listing URLs. |
| `platform` | enum | No | `marktplaats` | `marktplaats` / `2dehands` / `2ememain` / `all` (fan-out to all three). |
| `maxItems` | integer | No | `100` | Hard cap across the whole run. |
| `maxPagesPerSearch` | integer | No | `3` | 50 listings per backend page. |
| `includeDetails` | boolean | No | `true` | Fetch listing pages for the full description, the exact date and the seller lead fields. |
| `detailConcurrency` | integer | No | `8` | Parallel detail-page fetches (1–20). |
| `maxConcurrency` | integer | No | `3` | Keep 2–4 for polite crawling. |
| `maxRequestsPerCrawl` | integer | No | `300` | Backend pages plus detail pages. |
| `proxy` | object | No | off | Standard Apify proxy picker (group/country chosen in the UI). |

Free-plan runs are capped at **10 items and 1 result page per search**; paying runs get the full `maxItems` / `maxPagesPerSearch`.

### Output Fields

One row per listing. Two dataset views are available: **Overview** (all listings) and **Seller leads** (seller-outreach columns only).

| Group | Fields |
| --- | --- |
| Listing | `platform`, `itemId`, `url`, `title` |
| Price | `priceEur`, `priceType`, `priceTypeLabel` (`fixed` / `bid` / `free` / `negotiable`), `isAuction`, `isFree` |
| Description | `description` (full text when detail pages are on), `descriptionTruncated` |
| Location | `city`, `country`, `latitude`, `longitude`, `distanceMeters` |
| Category | `categoryId`, `category` (full name), `categoryParent` |
| Attributes | `attributes` (key → value map), `attributesRaw` |
| Images | `images[]`, `imageCount`, `primaryImage` |
| Seller (lead-gen) | `sellerId`, `sellerName`, `sellerVerified`, `sellerType`, `sellerIsProfessional`, `sellerProfileUrl`, `sellerAdsUrl`, `sellerReviewsUrl`, `sellerWebsiteUrl`, `sellerActiveSince`, `sellerContactOptions`, `sellerCity`, `sellerCountry` |
| Timing | `postedLabel` (e.g. "Vandaag"), `postedAt` (ISO 8601 from `stats.since`) |
| Extras | `priorityProduct`, `traits`, `verticals`, `viewCount`, `favoriteCount`, `adType`, `reserved` |

### Example Input

Scrape used bikes on marktplaats and both Belgian platforms:

```json
{
  "searches": ["racefiets", "veldrijfiets"],
  "platform": "all",
  "maxItems": 300,
  "maxPagesPerSearch": 6
}
```

### Example Output

```json
{
  "platform": "marktplaats",
  "itemId": "v4329876543",
  "url": "https://www.marktplaats.nl/v/fietsen-en-toerfietsen/m1234567899-gazelle-racefiets.html",
  "title": "Gazelle Racefiets Carbon Maat 56",
  "priceEur": 850,
  "priceType": "fixed",
  "priceTypeLabel": "fixed",
  "isAuction": false,
  "isFree": false,
  "description": "Gazelle carbon racefiets, maat 56, 11-speed Shimano 105. Weinig gebruikt, altijd binnen gestald. Ophalen in Utrecht of verzenden mogelijk.",
  "descriptionTruncated": false,
  "city": "Utrecht",
  "country": "NL",
  "latitude": 52.0907,
  "longitude": 5.1214,
  "distanceMeters": null,
  "categoryId": "509",
  "category": "Fietsen en Tourfietsen",
  "categoryParent": "Sport en Spel",
  "attributes": {
    "Merk": "Gazelle",
    "Conditie": "Zo goed als nieuw",
    "Frame maat": "56",
    "Aantal versnellingen": "11"
  },
  "attributesRaw": "Merk: Gazelle; Conditie: Zo goed als nieuw",
  "images": [
    "https://images.marktplaats.nl/api/v1/lots-v2/abc123/foto.jpg"
  ],
  "imageCount": 6,
  "primaryImage": "https://images.marktplaats.nl/api/v1/lots-v2/abc123/foto.jpg",
  "sellerId": "user_99887766",
  "sellerName": "fietsliefhebber",
  "sellerVerified": true,
  "sellerType": "PRIVATE",
  "sellerIsProfessional": false,
  "sellerProfileUrl": "https://www.marktplaats.nl/u/99887766/",
  "sellerAdsUrl": "https://www.marktplaats.nl/u/99887766/",
  "sellerReviewsUrl": "https://www.marktplaats.nl/u/99887766/#reviews",
  "sellerWebsiteUrl": "/externalUrl/redirect/abc123/",
  "sellerActiveSince": "2018-03-14",
  "sellerContactOptions": ["chat", "phone"],
  "sellerCity": "Utrecht",
  "sellerCountry": "NL",
  "postedLabel": "14 okt 26",
  "postedAt": "2026-10-14T09:23:11.000Z",
  "priorityProduct": false,
  "traits": [],
  "verticals": ["bicycle"],
  "viewCount": 342,
  "favoriteCount": 7,
  "adType": "regular_ad",
  "reserved": false
}
```

### Automate Classifieds Monitoring With Schedules & Webhooks

- **Schedule the Actor** daily or weekly to re-run a keyword and diff new listings, price drops and new sellers.
- **Webhooks** — configure a run-success webhook so each finished run POSTs to n8n, Make or Zapier and lands in a CRM or spreadsheet.
- **Dataset views** — pin the "Seller leads" view when the goal is outreach rather than market analysis.
- **Apify API** — pull the dataset programmatically with the JavaScript or Python client, or export JSON / CSV / Excel from the console.
- Recurring runs are what keep a resale database current; listings and prices move daily.

### Related Actors

- [Marktplaats Scraper](https://apify.com/ivanvs/marktplaats-scraper) — the most-used Marktplaats scraper on Apify.
- [Marktplaats.nl Scraper](https://apify.com/haketa/marktplaats-scraper) — a long-running Marktplaats scraper with wide adoption.
- [Marktplaats.nl Scraper 🤎 $0.9/1K Netherlands Data API](https://apify.com/azzouzana/marktplaats-nl-scraper) — a low-price Marktplaats option.
- [Marktplaats.nl Scraper — Search, Paste-URL & Seller · 24 Fields](https://apify.com/memo23/marktplaats-nl-scraper) — Marktplaats with a seller-focused field set.
- [OLX Scraper](https://apify.com/ahmed_jasarevic/olx-scraper) — classifieds across seven OLX country sites, for markets beyond NL and BE.

### Frequently Asked Questions

#### Why use this Actor instead of the official Marktplaats API?

Marktplaats does operate an official API (API 2.0), but it is seller-side only: through it you have access to **your own ads**, and ads from other advertisers are not accessible. There is also a deep-pagination cap on that API (5,000 results). This Actor instead reads the same first-party search endpoint the site's own frontend calls, so you can search and export **anyone's** listings — including full descriptions, exact posted timestamps and seller lead fields — with no API key and no contract.

#### What are alternatives to Marktplaats for Dutch and Belgian classifieds data?

Three routes exist. First, the official Marktplaats API — free, but only for your own advertisements and capped at 5,000 results. Second, third-party classifieds APIs that resell Marktplaats data (and 2dehands / 2ememain) at a higher per-record price. Third, self-serve scraping of the same public JSON endpoint (this Actor and the ones in Related Actors). OLX is the usual companion for markets outside the Netherlands and Belgium.

#### Can I search 2dehands.be and 2ememain.be too?

Yes — set `platform: "all"`. All three sites are served by the same codebase and the same `/lrp/api/search` endpoint, so only the hostname changes; rows are tagged with `platform` and de-duplicated on `platform + itemId`. You can also set `platform` to `2dehands` or `2ememain` to target one Belgian site.

#### Does this Actor return the full description and the exact posted date?

Yes, but only when `includeDetails` is `true` (the default). The search endpoint returns a description truncated to roughly 200 characters and a human-readable `postedLabel`; the listing page's inline state objects supply the full untruncated text and an exact ISO 8601 `postedAt` from `stats.since`. With details off you still get the truncated description and the label.

#### How much data can I get out of one search?

The backend caps each result page at 50 listings and allows roughly 100 pages per query, so a single query tops out near 5,000 listings. `maxPagesPerSearch` (default 3) and `maxItems` (default 100) are the Actor's own limits on top of that. Free-plan runs are capped at 10 items and 1 result page per search.

#### Can an AI agent call this Actor?

Yes. It is a standard Apify Actor, so any MCP client or agent can start a run through the Apify API or the Apify MCP server, wait for it to finish, and read the dataset items. The minimal input and output field list are in the next section.

#### How much does it cost?

Pay-per-event: one `result` event per listing returned ($1 per 1,000 listings), plus a small Actor-start event scaled by memory. There is no charge for backend pages that return no listing.

### For AI Agents & LLM Apps

Purpose: return structured classifieds listings (title, price, description, location, category, attributes, images, seller lead fields) from marktplaats.nl, 2dehands.be and 2ememain.be as JSON rows.

Minimal input (the default — a single keyword on marktplaats):

```json
{ "searches": ["fiets"] }
```

Variant — three keywords fanned out across all three platforms, with a higher cap:

```json
{
  "searches": ["racefiets", "veldrijfiets", "stadsfiets"],
  "platform": "all",
  "maxItems": 300,
  "maxPagesPerSearch": 6
}
```

Output fields (default dataset): `platform`, `itemId`, `url`, `title`, `priceEur`, `priceType`, `priceTypeLabel`, `isAuction`, `isFree`, `description`, `descriptionTruncated`, `city`, `country`, `latitude`, `longitude`, `distanceMeters`, `categoryId`, `category`, `categoryParent`, `attributes`, `attributesRaw`, `images`, `imageCount`, `primaryImage`, `sellerId`, `sellerName`, `sellerVerified`, `sellerType`, `sellerIsProfessional`, `sellerProfileUrl`, `sellerAdsUrl`, `sellerReviewsUrl`, `sellerWebsiteUrl`, `sellerActiveSince`, `sellerContactOptions`, `sellerCity`, `sellerCountry`, `postedLabel`, `postedAt`, `priorityProduct`, `traits`, `verticals`, `viewCount`, `favoriteCount`, `adType`, `reserved`.

Behaviors an agent should know:

- `searches` and `startUrls` are the two drivers. `searches` runs one backend query per keyword; `startUrls` accepts search pages, category pages or single listing URLs. If both are given, both are processed.
- `platform` controls the host: `marktplaats` (default), `2dehands`, `2ememain`, or `all` to fan one keyword out to all three (rows are tagged `platform` and de-duplicated on `platform + itemId`).
- `includeDetails` defaults to `true` and is what supplies the full description, the exact `postedAt` and the seller lead fields; setting it to `false` leaves you with the search endpoint's ~200-character description and a `postedLabel` only.
- `maxPagesPerSearch` (default 3) caps backend pages per keyword at 50 listings each; the backend itself allows roughly 100 pages per query before it runs dry.
- `sellerWebsiteUrl` is a `/externalUrl/redirect/…` path (a working lead link), not a bare domain, and only exists when the seller published a website.
- `postedAt` is only populated when `includeDetails` is `true`.
- Free-plan runs are capped at 10 items and 1 result page per search.

Billing: pay-per-event — one `result` event per listing returned ($1 / 1,000). Budget by listing count, not by page count, since backend pages that yield no listing bill nothing.

### Legal & Compliance Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by Marktplaats, eBay Kleinanzeigen or their operators. It reads only publicly visible search results and listing pages — no login, no account and no access to private or member-only data. Seller names, profile URLs, contact options and own-website links are already displayed publicly on each listing page. You are responsible for your own compliance with Marktplaats's Terms of Service and with applicable data-protection law (including the GDPR for Dutch and Belgian personal data) — in particular before using seller contact details for unsolicited commercial outreach.

### SEO Keywords

marktplaats scraper, dutch classifieds data, belgian classifieds data, marktplaats api alternative, marktplaats data export, 2dehands scraper, 2ememain scraper, seller lead generation netherlands, classifieds price monitoring, marktplaats search api, second hand marketplace data, resale market research, marktplaats listings export, dutch ecommerce data, belgian ecommerce data, used car data netherlands, product price tracking netherlands, classifieds scraper netherlands, marktplaats seller data, online marketplace scraper, nl classifieds api, be classifieds data, marketplace lead generation

# Actor input Schema

## `searches` (type: `array`):

Keywords to search for (e.g. "honda civic", "iPhone 13"). Each keyword is queried directly against the internal search backend on every selected platform.

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

Direct listing or search/category page URLs. Supported: search pages (…/q/query/), category pages (…/l/category/…) and single listing pages (…/v/…).

## `platform` (type: `string`):

Which marketplace to scrape. "all" fans the same query out to Marktplaats (NL), 2dehands.be and 2ememain.be (BE) — they share one backend.

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

Maximum number of listings to return in total.

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

How many backend result pages (50 listings each) to pull per keyword/URL before moving on.

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

Also open each listing page to get the FULL description, the exact posted timestamp and the seller lead-gen fields (profile/ads/reviews URLs, professional vs consumer, active-since, contact options).

## `detailConcurrency` (type: `integer`):

How many listing detail (VIP) pages are fetched in parallel when "Fetch detail pages" is on. Higher is faster but more aggressive; 8–12 is a good balance.

## `maxConcurrency` (type: `integer`):

Maximum number of parallel requests. Keep this modest (2–4) to stay under rate limits.

## `maxRequestsPerCrawl` (type: `integer`):

Hard cap on total HTTP requests (backend pages + detail pages).

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "searches": [
    "fiets"
  ],
  "startUrls": [],
  "platform": "marktplaats",
  "maxItems": 100,
  "maxPagesPerSearch": 3,
  "includeDetails": true,
  "detailConcurrency": 8,
  "maxConcurrency": 3,
  "maxRequestsPerCrawl": 300,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "searches": [
        "fiets"
    ],
    "startUrls": [],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/marktplaats-nl-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 = {
    "searches": ["fiets"],
    "startUrls": [],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/marktplaats-nl-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 '{
  "searches": [
    "fiets"
  ],
  "startUrls": [],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/marktplaats-nl-scraper --silent --output-dataset

```

## MCP server setup

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