Marktplaats.nl Scraper
Pricing
from $1.50 / 1,000 results
Marktplaats.nl Scraper
Scrape listings from Marktplaats.nl, 2dehands.be and 2ememain.be — Benelux's largest classifieds platforms with 10M+ active listings. Extract price, seller info, condition, location and category via internal JSON API. No browser needed.
Pricing
from $1.50 / 1,000 results
Rating
0.0
(0)
Developer
Haketa
Maintained by CommunityActor stats
1
Bookmarked
14
Total users
5
Monthly active users
13 days ago
Last modified
Categories
Share
Marktplaats.nl Scraper — Dutch Classifieds Data Extractor for Cars, Real Estate, Electronics, Fashion & Used Items
The most complete Marktplaats.nl data extraction tool on Apify. Pull live listings from the Netherlands' largest classifieds marketplace — plus its Belgian sister sites 2dehands.be (Flemish) and 2ememain.be (French) — with prices in EUR, normalized condition flags, seller type (particulier / zakelijk), category-specific attributes, location, images and full descriptions. Built for price benchmarking, used-car arbitrage, rental real-estate comps, reseller market intel, dropshipping research and demand-trend analytics across the Benelux region.
What This Actor Does
The Marktplaats.nl Scraper is a production-ready Apify Actor that extracts live classified listings from marktplaats.nl — the Netherlands' dominant consumer-to-consumer marketplace with over 10 million active listings at any moment — and from the two Belgian sister platforms that share its backend: 2dehands.be (Flemish-speaking Belgium) and 2ememain.be (French-speaking Belgium / Wallonia). The three sites are operated by the same group and expose the same internal JSON API, so a single actor covers the entire Benelux second-hand market.
Marktplaats has been the default place Dutch consumers go to buy and sell used cars, apartments, bicycles (fietsen are a whole vertical of their own), electronics, furniture, fashion, jobs, services and antiques since the late 1990s. The actor hands you back the same data a buyer sees — but as clean, normalized JSON ready for a warehouse, a dashboard, a price-monitoring system or an ML training pipeline. In a single run you can pull thousands of listings filtered by keyword, category, postcode radius, price band and sort order, with optional detail-page enrichment for full descriptions and category-specific attribute tables.
Each record can include:
- Listing core —
listingId(Marktplaatsm-identifier),title,pricein EUR (parsed from the API'spriceCentsinteger field), normalizedpriceType(fixed/bidding/free/asking/trade/negotiable/on_request/see_description), the original DutchpriceTypeOriginal(Vaste prijs,Bieden,Gratis,Vraagprijs,Ruilen,Nader overeen te komen),currency(alwaysEUR) - Condition — normalized
condition(new/like_new/used/not_applicable) and the original DutchconditionOriginal(Nieuw,Zo goed als nieuw,Gebruikt,Niet van toepassing) — with Belgian French fallbacks (Neuf,Comme neuf,Utilisé) where applicable - Taxonomy — L1
categoryand L2subcategorynames (e.g.Auto's→BMW,Telecommunicatie→Mobiele telefoons,Huis en Inrichting→Banken) - Seller —
sellerName,sellerId, andsellerType(privatefor particulieren /businessfor zakelijke verkopers and dealers flagged with the SOI-498 trade label) - Geo —
locationcity/district string (Amsterdam, Rotterdam, Den Haag, Utrecht, Eindhoven, Groningen, Tilburg, Almere and every Dutch and Belgian gemeente in between) - Recency —
datein ISO format (the Marktplaats publish/refresh timestamp) - Media —
imagesarray with the largest-available image URLs from the listing gallery - Logistics —
shippingAvailableboolean indicating whether the seller supports Marktplaats's verzendservice - Category-specific attributes — a flexible
attributesobject that surfaces vehicle specs (kilometerstand,bouwjaar,brandstof,transmissie), property details (oppervlakte,slaapkamers,huurprijs), phone specs (merk,model,opslag) and whatever else the vertical exposes - Description — partial from the API search response, full from the detail page when
scrapeDetails: true - Metadata — the originating
platform(marktplaats.nl/2dehands.be/2ememain.be), thesearchQueryandsearchCategoryused, full canonicalurl, and ascrapedAtISO timestamp on every row
Whether you run a Rotterdam used-car dealership, an Amsterdam sneaker reseller, a Den Haag rental-comp analytics product or a market-intel team tracking second-hand pricing across the Benelux, this actor is the fastest path from Marktplaats.nl to a usable dataset — without writing a line of scraping code.
Why scrape Marktplaats yourself when this exists?
Marktplaats looks like a simple classifieds site. Scraping it at any meaningful scale is not. Teams who try DIY hit the same wall:
- The public site is a Next.js SPA —
requests.get()against a search URL returns a thin HTML shell with no listings; the data only appears after JavaScript executes - The internal JSON API at
/lrp/api/searchis undocumented and the schema is not stable; field names change without notice (sellerInformationvsseller,imageUrlsvspictures,vipUrlvsselfLink,categorySpecificDescriptionvsdescription) - Prices come back as
priceCentsintegers (a €1,499 BMW is149900) and must be divided cleanly — naive string parsing of the rendered€ 1.499,00Dutch number format breaks on the thousands-separator dot priceTypeis an opaque uppercase enum (FIXED,BID,FAST_BID,MIN_BID,FREE,ASKING,TRADE,SEE_DESCRIPTION,RESERVED) that has to be mapped to both human English and the Dutch labels shown on the site- Condition is buried inside the
attributesarray underkey: "condition", with Dutch values (Zo goed als nieuw) that need translation to a stable English enum - Pagination is capped at 5000 results per query (
offset × limit < 5000) — exceed it and the API silently returns emptylistings - Private vs business sellers are not a clean flag — the API uses a
showSoi498Labelboolean derived from the EU's Sales of Items 498 commercial-trader label - Belgian variants (
2dehands.be,2ememain.be) share the schema but switch theAccept-Languagerequirement and the price-type labels into Flemish and French — easy to break a parser that hard-codes Dutch - Cloudflare and bot-fingerprinting checks kick in for unbranded user agents — the API returns
403to anything that doesn't look like a real Chrome on Windows withnl-NLlocales - Detail-page descriptions live inside the
__NEXT_DATA__JSON blob, not the rendered DOM — extracting them requires parsing the Next.js hydration payload and falling back to JSON-LD<script type="application/ld+json">when missing - Listings disappear — sold or expired ads return 404 within hours of removal; scraping must be tolerant
- Image URLs come in multiple resolutions (
mediumUrl,largeUrl,extraExtraLargeUrl) inside nested arrays (imageUrlsand/orpictures) — you have to walk both and pick the highest-resolution variant
This actor solves every one of those: direct internal-API calls via got-scraping with realistic Chrome fingerprints bypass bot detection without needing a browser, the parser normalizes EUR prices and price-type enums, condition flags and seller signals are translated into stable English values while preserving the Dutch originals for display, category-aware logic populates vehicle and property fields automatically, and the pipeline pushes deduplicated records straight to the Apify dataset.
Quick Start
One-Click Run
- Open the actor page on Apify Store and click "Try for free"
- Type a search term in Query (e.g.
iphone 15,bmw 320d,vouwfiets,bank tweezits) or leave it empty and pick a Category ID to browse a whole vertical - Optionally add a Dutch Postcode (e.g.
1012ABAmsterdam) plus a Distance in metres to constrain results to a radius - Hit Start — listings stream into your dataset and can be exported as JSON, CSV, Excel, HTML, XML or RSS straight from the Apify dataset view
API Run (Python)
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("haketa/marktplaats-scraper").call(run_input={"platform": "marktplaats.nl","query": "bmw 320d","categoryId": "91", # Auto's"postcode": "3011AA", # Rotterdam centrum"distanceMeters": 50000, # 50 km"minPrice": 500000, # €5,000 (in cents)"maxPrice": 2000000, # €20,000 (in cents)"sortBy": "PRICE","sortOrder": "INCREASING","scrapeDetails": True,"maxListings": 500,})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["price"], listing["location"], listing["sellerType"])
API Run (Node.js / TypeScript)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('haketa/marktplaats-scraper').call({platform: 'marktplaats.nl',query: 'iphone 15',categoryId: '31', // TelecommunicatiesubcategoryId: '1953', // Mobiele telefoons | Apple iPhonesortBy: 'SORT_INDEX',sortOrder: 'DECREASING',scrapeDetails: true,maxListings: 300,requestDelay: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(`Pulled ${items.length} iPhone 15 listings from Marktplaats.nl`);
API Run (cURL)
curl -X POST "https://api.apify.com/v2/acts/haketa~marktplaats-scraper/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"platform": "marktplaats.nl","query": "vouwfiets","categoryId": "1655","postcode": "1012AB","distanceMeters": 25000,"minPrice": 10000,"maxPrice": 80000,"sortBy": "SORT_INDEX","sortOrder": "DECREASING","scrapeDetails": true,"maxListings": 200}'
API Run (Belgian platforms)
# Same actor, different platform — Belgian Flemish 2dehands.berun = client.actor("haketa/marktplaats-scraper").call(run_input={"platform": "2dehands.be","query": "fiets","postcode": "1000", # Brussels"maxListings": 200,})# Belgian French 2ememain.berun = client.actor("haketa/marktplaats-scraper").call(run_input={"platform": "2ememain.be","query": "voiture","postcode": "4000", # Liège"maxListings": 200,})
How It Works
Marktplaats and its Belgian sister sites are server-rendered Next.js applications backed by a public-facing JSON search API at /lrp/api/search. This actor goes straight at that endpoint with realistic Chrome fingerprints — no headless browser, no Puppeteer, no Playwright for the search phase. Detail-page enrichment (when enabled) uses a separate lightweight HTML fetch that parses the embedded __NEXT_DATA__ hydration payload.
| Source endpoint | URL pattern | Returns |
|---|---|---|
| Search API (NL) | https://www.marktplaats.nl/lrp/api/search?query={Q}&l1CategoryId={C}&postcode={P}&distanceMeters={D}&priceFrom={F}&priceTo={T}&limit=30&offset={O} | { listings: [...], totalResultCount: N } |
| Search API (BE-NL) | https://www.2dehands.be/lrp/api/search?... | Same schema |
| Search API (BE-FR) | https://www.2ememain.be/lrp/api/search?... | Same schema |
| Detail page | https://www.{platform}/v/...{listingId}.html | Next.js HTML with __NEXT_DATA__ blob and JSON-LD Product/Offer |
Engineering details
- Direct API engine —
got-scrapingwith Chrome 120-126 fingerprints (nl-NL/nl-BElocales, desktop devices, Windows/macOS) hits the search endpoint without browser overhead, returning JSON in well under a second per page - Pagination —
offsetincrements byPAGE_SIZE = 30per page; the loop stops atMAX_OFFSET = 5000(the platform's hard cap), atmaxListings, whenlistingsis empty, or when no new IDs are added on a page - Retry with proxy rotation —
403/429responses trigger up to three retries with exponential backoff (3s × attempt) and a fresh Apify proxy URL each round - Price normalization —
priceInfo.priceCentsis divided by 100 to produce a clean EUR float; the actor never tries to parse the rendered Dutch€ 1.499,00string - Price-type enum mapping — the API's uppercase enum (
FIXED,BID,FAST_BID,MIN_BID,FREE,ASKING,TRADE,SEE_DESCRIPTION,NEGOTIABLE,ON_REQUEST,RESERVED) plus Dutch display strings (Vaste prijs,Bieden,Gratis,Vraagprijs,Ruilen,Nader overeen te komen) and Belgian-French equivalents (Prix fixe,Faire offre,Gratuit,Prix demandé,Échange) all collapse into a stable EnglishpriceTypevalue while the original is preserved aspriceTypeOriginal - Condition normalization — extracted from the
attributesarray underkey: "condition", then mapped from Dutch (Zo goed als nieuw/Gebruikt/Nieuw/Niet van toepassing) and French (Comme neuf/Utilisé/Neuf) to a clean English enum - Seller-type inference —
showSoi498Label(the EU commercial-trader badge) is checked first; presence flipssellerTypefromprivatetobusiness - Image walker — both
imageUrlsandpicturesnested arrays are walked, pickingextraExtraLargeUrl→largeUrl→mediumUrl→urlin that order so the largest-available image always wins - Category-specific attributes — every entry in the listing's
attributesarray (excludingcondition, which is normalized separately) and everyverticalsentry is flattened into a singleattributesobject — surfacing vehicle specs, property details, phone specs and any other vertical-specific fields the platform exposes - Detail-page enrichment — when
scrapeDetails: true, the canonical listing URL is fetched,__NEXT_DATA__is parsed for the fullpageProps.listingblob, and JSON-LDProduct/Offerblocks act as a fallback for missing descriptions and images - Deduplication — a
SetoflistingIds prevents the same ad being pushed twice when API pages overlap - Multi-platform support — switching
platformbetweenmarktplaats.nl,2dehands.be,2ememain.beautomatically swaps the base URL, the proxy locale hint and the price/condition label fallbacks
Input Parameters
{"platform": "marktplaats.nl","query": "iphone 15","categoryId": "31","subcategoryId": "","postcode": "1012AB","distanceMeters": 25000,"minPrice": 10000,"maxPrice": 80000,"sortBy": "SORT_INDEX","sortOrder": "DECREASING","scrapeDetails": false,"maxListings": 50,"requestDelay": 500,"proxyConfiguration": { "useApifyProxy": true }}
Parameter reference
| Parameter | Type | Default | Description |
|---|---|---|---|
platform | string | marktplaats.nl | Which Benelux platform to scrape. Choices: marktplaats.nl (Netherlands), 2dehands.be (Belgium Flemish), 2ememain.be (Belgium French). All three share the same backend and schema. |
query | string | iphone | Keyword search term. Searches across title and description (searchInTitleAndDescription=true). Examples: iphone 15, bmw 320, fiets, bank, vouwfiets. Leave empty to browse a whole category. |
categoryId | string | empty | Marktplaats L1 category ID. Leave empty for all categories. Common IDs: 31 (Telecommunicatie), 91 (Auto's), 504 (Computers en Software), 322 (Huis en Inrichting), 621 (Kleding Dames), 728 (Sport en Fitness), 1953 (Watches), 1655 (Fietsen en Brommers), 135 (Huizen en Kamers). See the Category Reference table below. |
subcategoryId | string | empty | L2 subcategory ID for a narrower search (e.g. Auto's → BMW). Leave empty for the entire L1 category. |
postcode | string | empty | Dutch or Belgian postcode that becomes the centre of the radius search. Examples: 1012AB (Amsterdam), 3011AA (Rotterdam), 2511DV (Den Haag), 3511AA (Utrecht), 5611AA (Eindhoven), 1000 (Brussels). |
distanceMeters | integer | 0 | Search radius from the postcode in metres. Only takes effect when postcode is set. Examples: 10000 (10 km), 25000 (25 km), 50000 (50 km), 100000 (100 km). 0 = no radius filter. |
minPrice | integer | 0 | Minimum price in cents (so 10000 = €100). 0 = no lower bound. |
maxPrice | integer | 0 | Maximum price in cents (so 100000 = €1,000). 0 = no upper bound. |
sortBy | string | SORT_INDEX | Sort key: SORT_INDEX (newest first), PRICE (price), OPTIMIZED (Marktplaats relevance ranking). |
sortOrder | string | DECREASING | Direction: DECREASING or INCREASING. Combine with sortBy: PRICE and INCREASING for cheapest-first. |
scrapeDetails | boolean | false | When true, fetch each listing's detail page for the full description and category-specific attribute tables (car specs, property details, etc.). Slower but more complete. |
maxListings | integer | 50 | Maximum total listings to scrape. 0 = unlimited. Note: Marktplaats hard-caps results at ~5,000 per query — use category + postcode + price filters to slice large searches into per-segment runs. |
requestDelay | integer | 500 | Delay between API calls in milliseconds (0–10000). Higher values are gentler on the platform and reduce the risk of 429 throttling. |
proxyConfiguration | object | Apify Proxy | Apify proxy settings. The internal API works without proxy from most IPs, but residential proxies improve reliability for very large runs. |
Output Schema
Every record uses the same flat JSON schema so downstream consumers (databases, CRMs, BI tools) can ingest the entire dataset without per-category branching.
Core fields
| Field | Type | Description |
|---|---|---|
listingId | string | Marktplaats listing identifier in m-/numeric form |
platform | string | Source platform: marktplaats.nl / 2dehands.be / 2ememain.be |
title | string | Listing title as displayed |
price | number | Price in EUR (already divided from priceCents) — null for Bieden, Gratis, Vraagprijs listings without an asking number |
priceType | string | Normalized: fixed / bidding / free / asking / trade / negotiable / on_request / see_description / reserved |
priceTypeOriginal | string | Original Dutch (or Flemish/French) label: Vaste prijs, Bieden, Gratis, Vraagprijs, Ruilen, Nader overeen te komen, Op aanvraag, Zie omschrijving, Gereserveerd |
currency | string | Always EUR |
condition | string | Normalized: new / like_new / used / not_applicable |
conditionOriginal | string | Original Dutch (or French): Nieuw / Zo goed als nieuw / Gebruikt / Niet van toepassing / Neuf / Comme neuf / Utilisé |
category | string | L1 category name (e.g. Auto's, Telecommunicatie, Huis en Inrichting) |
subcategory | string | L2 subcategory name (e.g. BMW, Mobiele telefoons, Banken) |
Seller fields
| Field | Type | Description |
|---|---|---|
sellerName | string | Seller display name |
sellerId | string | Marktplaats internal seller ID |
sellerType | string | private (particulier) / business (zakelijk, SOI-498 trade badge present) |
Location / recency fields
| Field | Type | Description |
|---|---|---|
location | string | City or district name (e.g. Amsterdam, Rotterdam-Zuid, Antwerpen) |
date | string | ISO timestamp of when the listing was posted/refreshed |
Content fields
| Field | Type | Description |
|---|---|---|
description | string | Partial from search API; full when scrapeDetails: true |
attributes | object | Category-specific attribute key/value pairs (vehicle specs, property details, phone specs, etc.) — null when none surfaced |
images | array<string> | Largest-available image URLs from the listing gallery |
shippingAvailable | boolean | true when the seller supports Marktplaats verzendservice |
Metadata fields
| Field | Type | Description |
|---|---|---|
url | string | Full canonical listing URL on the source platform |
searchQuery | string | The keyword used to find this listing |
searchCategory | string | The category ID used in the search |
scrapedAt | string | ISO-8601 timestamp of extraction |
Example: Used iPhone listing (Amsterdam, particulier)
{"listingId": "m2098765432","platform": "marktplaats.nl","title": "Apple iPhone 15 Pro 256GB Natural Titanium","price": 899.00,"priceType": "fixed","priceTypeOriginal": "Vaste prijs","currency": "EUR","condition": "like_new","conditionOriginal": "Zo goed als nieuw","category": "Telecommunicatie","subcategory": "Mobiele telefoons | Apple iPhone","sellerName": "Jeroen V.","sellerId": "48275621","sellerType": "private","location": "Amsterdam","date": "2026-05-14T09:42:00.000Z","description": "Nette iPhone 15 Pro 256GB, sinds december 2024 in bezit, altijd met hoesje en screenprotector gebruikt. Doos en originele kabel aanwezig. Accu 98%. Geen krasjes.","attributes": {"merk": "Apple","model": "iPhone 15 Pro","opslag": "256 GB","kleur": "Natural Titanium","garantie": "Ja, nog 7 maanden Apple-garantie"},"images": ["https://images.marktplaats.com/api/v1/listing-mp-p/images/9a/9aabc.../?rule=ecg_mp_eps$_84.jpg","https://images.marktplaats.com/api/v1/listing-mp-p/images/9a/9aabd.../?rule=ecg_mp_eps$_84.jpg"],"shippingAvailable": true,"url": "https://www.marktplaats.nl/v/telecommunicatie/mobiele-telefoons-apple-iphone/m2098765432-apple-iphone-15-pro-256gb-natural-titanium","searchQuery": "iphone 15","searchCategory": "31","scrapedAt": "2026-05-16T20:00:00.000Z"}
Example: Used BMW (Eindhoven, zakelijk dealer)
{"listingId": "m1987654321","platform": "marktplaats.nl","title": "BMW 320d Touring Sport Line | Pano | LED | Trekhaak","price": 18950.00,"priceType": "fixed","priceTypeOriginal": "Vaste prijs","currency": "EUR","condition": "used","conditionOriginal": "Gebruikt","category": "Auto's","subcategory": "BMW","sellerName": "Autobedrijf Van der Berg B.V.","sellerId": "11223344","sellerType": "business","location": "Eindhoven","date": "2026-05-15T11:15:00.000Z","description": "BMW 320d Touring Sport Line uit 2019. NL auto, 1 eigenaar, dealer onderhouden, NAP. Panoramadak, LED-koplampen, trekhaak, navigatie professional. Inruil mogelijk.","attributes": {"bouwjaar": "2019","kilometerstand": "98.450 km","brandstof": "Diesel","transmissie": "Automaat","carrosserie": "Stationwagon","vermogen": "190 pk","kleur": "Mineraalgrijs metallic","btw_marge": "Marge","apk": "Tot 03-2027"},"images": ["https://images.marktplaats.com/api/v1/listing-mp-p/images/aa/.../?rule=ecg_mp_eps$_84.jpg"],"shippingAvailable": false,"url": "https://www.marktplaats.nl/v/autos/bmw/m1987654321-bmw-320d-touring-sport-line-pano-led-trekhaak","searchQuery": "bmw 320d","searchCategory": "91","scrapedAt": "2026-05-16T20:00:00.000Z"}
Price-Type Reference
priceType | priceTypeOriginal (NL) | French (2ememain.be) | Meaning |
|---|---|---|---|
fixed | Vaste prijs | Prix fixe | Seller's listed price is firm |
bidding | Bieden | Faire offre | Buyers submit bids; no fixed price |
free | Gratis | Gratuit | Item is free — typically furniture, building leftovers |
asking | Vraagprijs | Prix demandé | Asking price — small negotiation expected |
trade | Ruilen | Échange | Seller wants to swap, not sell |
negotiable | Nader overeen te komen | — | Open to discussion, no number given |
on_request | Op aanvraag | — | Price disclosed on contact only (common for B2B) |
see_description | Zie omschrijving | — | Price details inside the description body |
reserved | Gereserveerd | — | Reserved for another buyer; still listed |
Condition Reference
condition | conditionOriginal (NL) | French (2ememain.be) | Meaning |
|---|---|---|---|
new | Nieuw | Neuf | Brand-new, often still sealed |
like_new | Zo goed als nieuw | Comme neuf | Used briefly, no wear |
used | Gebruikt | Utilisé | Normal second-hand condition |
not_applicable | Niet van toepassing | — | Category where condition is irrelevant (services, real estate) |
Category Reference (popular L1 IDs)
categoryId | Dutch L1 category | English | Notes |
|---|---|---|---|
91 | Auto's | Cars | Largest used-car marketplace in NL |
92 | Auto-onderdelen | Car parts | Mechanic and DIY supply chain |
1655 | Fietsen en Brommers | Bikes & mopeds | Bicycles dominate Dutch traffic |
135 | Huizen en Kamers | Houses & rooms | Sales + rentals, includes vakantiehuizen |
322 | Huis en Inrichting | Home & furnishing | Sofas, tables, lamps, decoration |
31 | Telecommunicatie | Telecom | Phones, smartwatches, accessories |
504 | Computers en Software | Computers & software | Laptops, desktops, components |
322-1133 | Witgoed en Apparatuur | White goods | Washers, dryers, fridges |
1525 | Audio, Tv en Foto | Audio, TV & photo | Cameras, hi-fi, televisions |
1953 | Sieraden, Tassen en Uiterlijk | Jewellery, bags, beauty | Watches, designer bags |
621 | Kleding | Dames Clothing — women's | Apparel, shoes, accessories |
728 | Sport en Fitness | Sport & fitness | Bikes, gym, outdoor gear |
1099 | Kinderen en Baby's | Kids & babies | Strollers, toys, clothing |
1100 | Dieren en Toebehoren | Animals & accessories | Pet listings (regulated separately) |
367 | Antiek en Kunst | Antiques & art | Collectibles, paintings |
2017 | Tickets en Kaartjes | Tickets | Events, concerts, public transport |
380 | Boeken | Books | Second-hand books |
356 | Vakantie | Holidays | Vakantiehuizen, last-minute deals |
33 | Werk en Personeel | Jobs & staff | Vacancies and CVs |
34 | Diensten en Vakmensen | Services & trades | Plumbers, painters, cleaning |
Use Cases
Price benchmarking & dynamic pricing
Pricing analysts, e-commerce operators and reseller platforms use Marktplaats data to anchor their pricing to the live Dutch second-hand market:
- Pull the median asking price for any model + condition combination (
iPhone 15 Pro 256GBlike_new) refreshed daily - Track price decay curves — how fast does a new iPhone or PlayStation lose value on the Dutch market?
- Compare zakelijk-dealer pricing vs particulier pricing on the same SKU to size the dealer margin
- Build city-level price heatmaps (Amsterdam vs Groningen vs Eindhoven) for the same product
Used-car arbitrage & dealer intelligence
Independent dealers, leasing companies and auto-fintech startups use Marktplaats's Auto's (categoryId 91) and Auto-onderdelen (92) verticals to:
- Identify undervalued private-party listings (
particulier,Vaste prijs< market median) for buy-and-flip - Track every BMW 3-series, Volkswagen Golf, Tesla Model 3 listed in the past 24 hours across NL
- Pull
kilometerstand,bouwjaar,brandstof,transmissie,APKattributes for full vehicle history records - Monitor competing dealers' inventory and price changes in real time
- Build BPM-tax and import calculators with live NL pricing benchmarks
- Spot trends: EV vs ICE listing volume by month, Tesla Model Y average price over time
Real estate & rental comps (Benelux)
Property analytics teams, agents and PropTech startups use Marktplaats's Huizen en Kamers category as a complementary signal to Funda and Pararius:
- Pull every rental listing in Amsterdam, Utrecht, Rotterdam, Den Haag with the
huurprijsattribute - Compare Marktplaats kamer-te-huur prices against student-housing supply
- Detect new vakantiehuis listings in coastal NL (Zandvoort, Scheveningen, Texel) within hours
- Track the long-tail of for-sale-by-owner (
particulier) listings that bypass MLS-style portals - Cross-reference rental prices across Dutch postcodes for rental-yield analysis
Reseller & dropshipping market intel
Amazon FBA sellers, bol.com merchants, and dropshippers researching the NL/BE market use the actor to:
- Discover hot product categories by tracking listing volume and median price over time
- Identify white-space opportunities — high search demand on Google Trends NL but low Marktplaats listing density
- Source second-hand stock at scale by monitoring
Gratis,Biedenand underpricedVaste prijslistings - Benchmark new-product retail pricing against the parallel Marktplaats used market
- Spot brand-counterfeit risks by sampling listings for premium brands (Stone Island, Moncler, Apple)
Demand-trend & consumer research
Market research firms, FMCG brands and trend agencies use the dataset to:
- Track week-over-week listing volume per category as a leading indicator of consumer sentiment
- Identify the most searched-for items by sampling top-of-page
OPTIMIZEDsort across keywords - Build "what Dutch consumers are letting go of" reports — rising listings of treadmills, espresso machines, gaming consoles
- Cross-reference with weather and seasonality data (e.g. fietsen sales spikes in March)
- Power academic studies of second-hand economy growth in the Benelux
Brand monitoring & IP protection
Brands, distributors and IP-protection teams use the actor to:
- Search for counterfeit listings of premium brands (Louis Vuitton, Nike, Apple, Rolex) for takedown actions
- Detect grey-market sales of branded goods outside authorized channel
- Monitor warranty fraud — products listed with claims of
garantiethat exceed manufacturer terms - Track stolen-goods patterns by category and region (high-value bicycles are a perennial NL theme)
- Build evidence packs of unauthorized seller activity with
sellerId,sellerName, listing URL and screenshots
Lead generation for B2B services
Marketing agencies, fintech startups and B2B SaaS vendors use the business seller filter to:
- Build prospect lists of Dutch zakelijke verkopers (car dealers, electronics shops, fashion resellers, jewellery merchants)
- Enrich CRM with the seller's category mix, location and listing volume as firmographic signals
- Identify high-volume dealers as ideal-customer-profile (ICP) targets for inventory-management software
- Power lookalike audiences for B2B advertising platforms
Insurance, valuation & second-hand market research
Insurers, actuaries and second-hand valuation platforms use Marktplaats as a live price-discovery layer:
- Anchor home-contents insurance payouts to real second-hand replacement costs
- Build automotive market-value engines for used-car insurance and finance underwriting
- Power "what is this worth?" consumer-facing apps with live Marktplaats medians
- Track depreciation curves for electronics, appliances, bicycles, instruments
Journalism & data reporting
Investigative journalists, public-interest media and data reporters use Marktplaats as a Dutch consumer-market mirror:
- Cover the rise (or fall) of specific consumer trends — e-bikes, heat pumps, gaming consoles, work-from-home equipment
- Investigate underground trades or regulated-goods listings (firearms, certain pet breeds, restricted plants)
- Map second-hand market activity to economic cycles, inflation, energy crises
- Source citizen-reporter listings for regional reporting
Sample Queries & Recipes
Recipe 1: All used iPhones under €700 in the Randstad
{"platform": "marktplaats.nl","query": "iphone","categoryId": "31","postcode": "1012AB","distanceMeters": 60000,"maxPrice": 70000,"sortBy": "PRICE","sortOrder": "INCREASING","maxListings": 500}
Recipe 2: Cheapest BMW 3-series across NL — full vehicle specs
{"platform": "marktplaats.nl","query": "bmw 320","categoryId": "91","sortBy": "PRICE","sortOrder": "INCREASING","scrapeDetails": true,"maxListings": 1000}
Recipe 3: Free items in Amsterdam — Gratis listings only
{"platform": "marktplaats.nl","query": "","postcode": "1012AB","distanceMeters": 20000,"maxPrice": 1,"maxListings": 200}
(Use maxPrice: 1 to capture Gratis items where priceCents is 0 or 1.)
Recipe 4: All zakelijke (business) sellers in the Telecom category
Run the actor with categoryId: "31" and filter sellerType === "business" downstream:
business_dealers = [r for r in records if r["sellerType"] == "business"]
Recipe 5: Rental rooms (kamers te huur) in Utrecht student belt
{"platform": "marktplaats.nl","query": "kamer huur","categoryId": "135","postcode": "3511AA","distanceMeters": 15000,"minPrice": 30000,"maxPrice": 100000,"sortBy": "SORT_INDEX","maxListings": 300}
Recipe 6: Vouwfietsen (folding bikes) in the Belgian Flemish region
{"platform": "2dehands.be","query": "vouwfiets","categoryId": "1655","postcode": "2000","distanceMeters": 50000,"scrapeDetails": true,"maxListings": 150}
Recipe 7: Dropshipping research — every PlayStation 5 listed today
{"platform": "marktplaats.nl","query": "playstation 5","categoryId": "504","sortBy": "SORT_INDEX","sortOrder": "DECREASING","maxListings": 500}
Then in Python:
from datetime import datetime, timezone, timedeltatoday = datetime.now(timezone.utc).date()todays = [r for r in records if datetime.fromisoformat(r["date"].replace("Z","+00:00")).date() == today]
Integration Examples
Google Sheets (via Apify Integration)
- Schedule the actor to run daily at 08:00 CET with your favourite keyword + category combination
- Add the "Export to Google Sheets" Apify integration to the schedule
- Get a fresh Marktplaats CSV in your Sheet every morning — ready for pivot tables and conditional formatting
Make.com / Zapier / n8n
Use the Apify connector available on all major automation platforms. Trigger downstream workflows on:
- New listings (latest run minus previous run) matching a watch-list query
- Price drops (compare today's price vs yesterday's by
listingId) - New zakelijk dealer accounts entering a category
- Specific keyword hits (e.g. trigger Slack/Telegram alert on any
Rolex Submarinerlisting under €5,000)
Power BI / Tableau / Looker / Metabase
Connect the Apify REST API as a data source, refresh on schedule, and build dashboards covering:
- Median price by category and city, week over week
- Listing-volume heat maps across Dutch provinces
- Sankey diagrams of category → subcategory → condition → price
- Time-series of new vs business listings per vertical
Postgres / Snowflake / BigQuery
Use the Apify webhook integration to POST run results directly to your data-warehouse ingestion endpoint after every scheduled run. Recommended table schema:
CREATE TABLE marktplaats_listings (listing_id TEXT PRIMARY KEY,platform TEXT,title TEXT,price_eur NUMERIC(12,2),price_type TEXT,condition TEXT,category TEXT,subcategory TEXT,seller_name TEXT,seller_id TEXT,seller_type TEXT,location TEXT,date TIMESTAMPTZ,shipping_available BOOLEAN,attributes JSONB,images TEXT[],url TEXT,scraped_at TIMESTAMPTZ);CREATE INDEX ON marktplaats_listings (category, subcategory);CREATE INDEX ON marktplaats_listings (seller_id);CREATE INDEX ON marktplaats_listings (date);CREATE INDEX ON marktplaats_listings USING GIN (attributes);
Salesforce / HubSpot CRM enrichment
Schedule the actor with a business-only category sweep, then upsert into Salesforce Accounts keyed on sellerId. Trigger Workflow Tasks when seller listing-volume crosses thresholds (e.g. "Dealer added 20+ new car listings this week — sales rep follow-up").
Webhooks & alerting
Use Apify webhook events to fire HTTP POSTs on every run completion. Combine with a small Lambda/Cloud Function to:
- Push new matching listings to Slack, Telegram or Discord watch channels
- Email subscribers when their saved-search criteria match
- Update internal price-alert tables in real time
Major Dutch & Belgian Markets at a Glance
| Metro area | Country | Population | Marktplaats significance |
|---|---|---|---|
| Amsterdam | NL | 1.2M (metro 2.5M) | Largest concentration of listings — premium electronics, fashion, cars, bikes |
| Rotterdam | NL | 660K (metro 1.5M) | Port-city character — heavy on tools, machinery, vehicles, imports |
| Den Haag (The Hague) | NL | 560K | Government and expat hub — international diplomats relocating drive churn |
| Utrecht | NL | 365K | Centrally located student city — strong rental kamer-te-huur volume |
| Eindhoven | NL | 240K | Tech and Philips region — high electronics and component listing activity |
| Groningen | NL | 235K | Northern student city — bicycle and furniture market |
| Tilburg | NL | 225K | Brabant industrial belt — strong cars and tools verticals |
| Almere | NL | 220K | Fast-growing Flevoland city — heavy family-goods volume |
| Breda | NL | 185K | Brabant — vacation property and second-hand sport gear |
| Nijmegen | NL | 180K | University city — high bicycle and student-furniture turnover |
| Antwerpen | BE (Flemish) | 530K | Main Flemish hub for 2dehands.be |
| Gent | BE (Flemish) | 265K | Flemish student/cultural city |
| Brussels | BE (bilingual) | 1.2M | Cross-listed on both 2dehands.be and 2ememain.be |
| Liège | BE (French) | 195K | Main Walloon hub for 2ememain.be |
| Charleroi | BE (French) | 200K | Walloon industrial city — heavy vehicles and tools market |
Cost & Performance
| Metric | Value |
|---|---|
| Engine | Direct internal JSON API via got-scraping (no browser) |
| Runtime (50 listings, no detail enrichment) | ~10–20 seconds |
| Runtime (500 listings, no detail enrichment) | ~60–120 seconds |
Runtime (500 listings, scrapeDetails: true) | ~5–10 minutes (one HTML fetch per listing) |
| Cost per run | Pay-per-event — varies with listing count |
| Pricing model | Pay-per-event (transparent per-record pricing) |
| Data freshness | Live at run time — Marktplaats has no daily snapshot, the API reflects the platform state at the moment of each call |
| Authentication | None required |
| Proxy required | Apify Proxy enabled by default for resilience; the API accepts unproxied traffic from clean IPs too |
| Concurrency | Safe to run multiple parallel configurations (different category/postcode slices) |
| Memory footprint | 256 MB sufficient; 512 MB recommended for scrapeDetails: true |
| Hard cap per search | ~5,000 results (Marktplaats platform limit) — work around with category + postcode + price slicing |
Compliance, Privacy & Legal Notes
- Public data only — every field returned by this actor is publicly visible to any anonymous visitor of marktplaats.nl, 2dehands.be or 2ememain.be
- No PII collection beyond what the seller chose to publish — only the display name and seller ID as shown in the listing card
- No emails or phone numbers — Marktplaats hides direct contact data behind its messaging system; this actor does not attempt to unmask it
- No login or account data — the actor only reads public listings; it does not authenticate, post, message or otherwise interact with the platform
- GDPR / EU privacy — sellers post on Marktplaats with the reasonable expectation that their listings are public; aggregating that public data for legitimate business purposes (price benchmarking, market research, fraud detection) is generally permitted, but you remain the data controller and must respect data-subject rights (Articles 15-17 GDPR). Do not store or process personal data beyond what is necessary for your stated purpose, and honour deletion requests
- Robots & ToS — Marktplaats's robots.txt allows crawling of search pages with reasonable rate limits; the actor's default 500 ms inter-request delay sits well within polite-crawler territory. Always respect the platform's Terms of Service in your specific use case
- No CAPTCHA bypass that would imply automated account abuse — the actor only fetches anonymous public endpoints
Important: Marktplaats data may not be used for unlawful purposes including identity fraud, stalking, harassment, or unsolicited spam (CAN-SPAM, the Dutch Telecommunicatiewet, EU ePrivacy Directive). The user is responsible for downstream compliance.
Frequently Asked Questions
How fresh is the data?
Live at run time. Marktplaats does not publish a daily snapshot — the internal API reflects the state of the platform at the exact moment of each call. New listings appear in the dataset within seconds of being posted on the site; sold or removed listings vanish on the next run.
How many records will I get?
It depends on your query. Marktplaats hard-caps a single search at ~5,000 results (offset × limit < 5000). A broad search (Auto's in all of NL) hits that cap; a narrow search (bmw 320d in Eindhoven, 20 km radius) might return 50–200. For very large pulls, split your run into segments by category + postcode + price band.
Does this scraper require a login or API key to Marktplaats?
No. The actor calls only public, anonymous endpoints. You only need an Apify account to run it.
Does this work for Belgium too?
Yes. Set platform: "2dehands.be" for Flemish-speaking Belgium or platform: "2ememain.be" for French-speaking Belgium / Wallonia. All three platforms share the backend, so the schema is identical — only the price-type labels and condition values switch language.
Does it support Cloudflare-protected pages?
Marktplaats's internal search API does not sit behind a CAPTCHA, but it does check user-agent and locale headers. The actor uses got-scraping with realistic Chrome 120-126 fingerprints in nl-NL/nl-BE locales, which clears the platform's checks reliably.
Can I filter by price?
Yes — pass minPrice and maxPrice in cents (so €100 = 10000, €1,500 = 150000). For "free items only" set maxPrice: 1.
Can I filter by city?
Yes — use a Dutch or Belgian postcode plus a distanceMeters radius. The actor does not support raw city-name filtering at the API level (Marktplaats expects postcodes), but you can post-filter on the returned location field downstream.
Can I distinguish private sellers from business sellers?
Yes — the actor returns sellerType set to either private (particulier) or business (zakelijk, derived from the EU SOI-498 commercial-trader badge). Filter downstream as needed.
Can I get the seller's email or phone number?
No. Marktplaats hides contact information behind its in-platform messaging system. This actor only returns what is publicly visible on listing cards — sellerName and sellerId. Contacting sellers must be done through Marktplaats itself.
How do I get the full description and category-specific attributes?
Set scrapeDetails: true. The actor will then fetch each listing's detail page, parse the embedded __NEXT_DATA__ JSON and fall back to JSON-LD, returning the full description plus the complete attributes object (vehicle specs, property details, phone specs, etc.). This roughly doubles or triples runtime.
Can I schedule this to run automatically?
Yes — Apify's built-in Scheduler lets you trigger the actor hourly, daily, weekly or on any cron expression. Combine with the webhook or Google Sheets integration for a fully automated pipeline.
Does it work with the Apify free plan?
Yes — full functionality on the free tier. A run of 200 listings without detail enrichment typically uses a few cents of compute.
What output formats are supported?
JSON, CSV, Excel (XLSX), HTML, XML and RSS — directly from the Apify dataset view. The API also supports JSON Lines for streaming consumers.
Why is price sometimes null?
Because the listing uses a priceType other than fixed/asking — i.e. Bieden (bidding), Gratis (free), Ruilen (trade), Nader overeen te komen (negotiable), Op aanvraag (on request) or Zie omschrijving (see description) listings often do not carry a numeric price. The priceType and priceTypeOriginal fields tell you why.
Why is condition sometimes null?
Marktplaats sellers are not required to fill in the condition attribute, and certain categories (services, real estate, jobs) don't expose it. When the attribute is absent the field is null rather than guessed.
Why is my attributes object empty for some listings?
The attribute table varies by category and is partially populated even by the seller. A vintage book listing might only carry taal (language); a car listing typically carries 6–12 attributes. Enable scrapeDetails: true to pull the maximum available set from each listing's detail page.
Does the actor deduplicate?
Yes — a Set of listingIds prevents duplicates across paginated API pages. Across multiple runs you can deduplicate downstream using the listingId field as a primary key.
Can I scrape more than 5,000 results for a single broad query?
Not in a single search. Marktplaats's API hard-caps at ~5,000 results per query. To exceed this, slice your search into segments — for example, by L2 subcategory (l2CategoryId), price band (minPrice + maxPrice), or postcode radius — and merge the resulting datasets.
Can I run this for related Benelux marketplaces (Vinted, Bolcom, 2dehands.be)?
2dehands.be and 2ememain.be are supported natively via the platform parameter. Vinted, Bol.com and Funda are separate platforms with different APIs — for those, see the dedicated actors in the Related Apify Actors section below.
What if the actor returns zero listings?
Most common causes: the search query yielded no matches (try broader keywords or remove categoryId), the minPrice/maxPrice band is too narrow, the postcode + distance combination is too tight, or Marktplaats's platform-side filters returned no results. Check the actor's run log — the line [API] Total results: N tells you exactly what Marktplaats reported.
How do I report a bug or request a feature?
Open an issue on the Apify Store actor page or contact the developer directly through the Apify Console.
Related Apify Actors by Haketa
Building a multi-country marketplace dataset? These sibling actors cover other major regional classifieds platforms:
- Kleinanzeigen.de Scraper (Germany) — Germany's largest classifieds platform (formerly eBay Kleinanzeigen), 50M+ listings, full vehicle and real-estate attributes
- OfferUp Scraper (US) — US local-marketplace giant, ideal sibling for US used-goods coverage
- Kijiji.ca Scraper (Canada) — Canada's largest classifieds platform across all provinces
- TradeMe Scraper (New Zealand) — New Zealand's dominant marketplace for goods, cars and property
- Lelong.my Scraper (Malaysia) — Malaysia's veteran online marketplace (electronics, fashion, auto parts)
- Chotot.com Scraper (Vietnam) — Vietnam's leading classifieds marketplace
- Mourjan Scraper (MENA) — Pan-Arab classifieds across the Middle East and North Africa
- Immoweb.be Belgium Property Scraper — Belgium's #1 real-estate portal — perfect complement to Marktplaats's Belgian property listings
- Domain.com.au Property Scraper (Australia) — Australian real-estate sibling
- VivaReal Brazil Real Estate Scraper — Brazilian real-estate listings
- Lamudi Philippines Real Estate Scraper — Philippine property listings
- YallaMotor Scraper (GCC) — Gulf-region used-car marketplace for cross-region automotive intel
Comparison vs. Alternatives
| Approach | Setup time | Data freshness | Cost (1,000 listings) | Cloudflare/locale handling | Multi-platform (NL + BE) |
|---|---|---|---|---|---|
| This actor | < 1 minute | Live at run time | < $1 typical | Built-in | Built-in (NL/BE-NL/BE-FR) |
| Manual copy-paste | hours/day | Manual | Free + time | None | Each country manually |
Custom Python + requests | 1–2 weeks dev | Live | Free + infra + maintenance | DIY (often blocked) | DIY per platform |
| Custom Playwright + proxies | 2–4 weeks dev | Live | Free + infra + proxy bill | Manual fingerprinting | DIY per platform |
| Generic SaaS scraper | Hours to set up per template | Live | $100–500+/mo | Often weak on nl-NL headers | Each domain billed separately |
Why Pay-Per-Event Pricing?
Most data scrapers either charge a flat monthly subscription (you pay even when idle) or per-Compute-Unit (unpredictable). This actor uses pay-per-event pricing, which means:
- You only pay when the actor runs and only for the data you receive
- Charges scale linearly with how many listings you actually consume — no surprise CU bills
- Transparent, line-item billing inside Apify
- No monthly minimums, no annual contracts, no seat fees
- Free to evaluate — sample with
maxListings: 20for pennies before committing to a larger sweep - Per-event metering aligns the cost model with the value (
one extra listing = one extra event)
Changelog
| Version | Date | Notes |
|---|---|---|
| 1.0.0 | 2026-05 | Initial public release — internal JSON API engine, NL + BE-NL + BE-FR multi-platform support, price/condition/seller-type normalization, optional detail-page enrichment with __NEXT_DATA__ parser, Apify Proxy integration, pay-per-event pricing |
Keywords
Marktplaats scraper · Marktplaats.nl data · Marktplaats API · Dutch classifieds API · Netherlands marketplace extractor · NL used items data · Marktplaats price scraper · Marktplaats lead generation · Marktplaats car house scraper · Marktplaats listing scraper · marktplaats.nl JSON API · marktplaats car scraper · marktplaats real estate scraper · 2dehands scraper · 2dehands.be data · 2ememain scraper · 2ememain.be Belgium classifieds · Benelux marketplace data · Dutch used car data · Netherlands second hand data · Marktplaats fietsen scraper · Marktplaats huizen kamers data · Marktplaats wonen inrichting scraper · Marktplaats telecom iphone data · Amsterdam classifieds data · Rotterdam classifieds data · Den Haag marketplace data · Utrecht marketplace scraper · Eindhoven classifieds data · Groningen marketplace data · Tilburg marketplace data · Almere classifieds data · Brussels 2dehands data · Antwerp 2dehands scraper · Liège 2ememain scraper · particulier zakelijk seller scraper · Marktplaats verzendservice data · Marktplaats price benchmarking · used car arbitrage Netherlands · NL rental comps scraper · dropshipping research Netherlands · reseller market intel Benelux · Marktplaats brand monitoring · Apify Marktplaats actor · Netherlands C2C marketplace API · Dutch second hand market data · Benelux classifieds extraction · Marktplaats demand trend data
Support
- Bug reports: Use the Issues tab on the Apify Store actor page
- Feature requests: Same place — please include your use case and ideally a sample query
- Direct contact: Through the Apify developer profile
If this actor saves you engineering time, a 5-star rating on the Apify Store helps other Benelux marketplace, e-commerce and analytics teams discover it. Dank je wel! / Merci beaucoup!