2dehands & 2ememain Scraper (GDPR-safe)
Pricing
from $1.99 / 1,000 results
2dehands & 2ememain Scraper (GDPR-safe)
Scrape 2dehands.be and 2ememain.be listings as clean JSON: prices, descriptions, categories, locations, images and posting dates. GDPR-safe by design: no seller names or other personal data. Splits large searches automatically to fetch every result. Pay per result.
Pricing
from $1.99 / 1,000 results
Rating
0.0
(0)
Developer
Lowland Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
13 minutes ago
Last modified
Categories
Share
2dehands & 2ememain Scraper — GDPR-safe listings data
Extract listings from 2dehands.be and 2ememain.be — Belgium's largest second-hand marketplaces — as clean, structured JSON. Prices, descriptions, categories, locations, images and posting dates, ready for price monitoring, market research and data pipelines.
No seller personal data, ever. This scraper is built GDPR-first: seller names, IDs, phone numbers and profile links never appear in the output — not as an option you have to remember to switch off, but by design. The only seller information included is whether the listing comes from a business or a private seller.
What you get
Each listing is one dataset item:
{"listingId": "m2419606891","title": "Jongensfiets Gazelle Esprit zwart","description": "Nieuw aangekocht in oktober 2024...","priceCents": 40000,"priceType": "MIN_BID","city": "Balen","country": "België","latitude": 51.166343,"longitude": 5.189532,"postedAt": "Vandaag","imageUrls": ["//images.2dehands.com/api/v1/..."],"categoryId": 455,"url": "https://www.2dehands.be/v/fietsen-en-brommers/...","attributes": { "condition": "Zo goed als nieuw", "delivery": "Ophalen" },"sellerType": "private"}
Field notes, so you know exactly what you are buying:
priceCentsis the asking price in euro cents; listings without a price omit it.priceTypetells you how to read it:FIXED(asking price) orMIN_BID(minimum bid), plus the marketplace's other kinds when they occur.postedAtis the posting date exactly as the marketplace displays it — a date, or a relative label likeVandaag(today) for recent listings.latitude/longitudeare the marketplace's own municipality-level coordinates, not a seller address.descriptionis the snippet the marketplace search returns, not the full listing page text.imageUrlsare protocol-relative (//images...); prependhttps:to use them.attributescontains the whitelisted set:conditionanddelivery, when the listing has them.
Use cases
- Price monitoring — track asking prices for a product or category over time
- Market research — supply, pricing and location analysis for the Belgian second-hand market
- Resale arbitrage — find underpriced listings the moment they appear (sort by date)
- Data feeds — clean, compliance-friendly input for dashboards, ML models and AI agents
Input
| Field | Description |
|---|---|
searchQuery | Free-text search, e.g. gazelle. Provide this, a category, or both. |
domain | 2dehands.be (Dutch, default) or 2ememain.be (French). Same listings, different language. |
categoryId | Numeric category ID to scope the crawl. See below for finding IDs. |
priceMinEur / priceMaxEur | Only listings within this price range, in EUR. |
sortBy | date (newest first, default), price_asc, price_desc, or relevance. |
maxItems | Stop after this many listings. Default 1,000. |
A run needs at least a search query or a category — the marketplace has no "everything" feed, and the actor tells you so up front instead of returning an empty dataset.
Finding a category ID
Every result includes its categoryId. The quickest way to discover IDs is to run a broad search once and read the category IDs off the results you care about, then use them as input for scoped crawls.
Use it from your code
Run the actor and get items straight back with one HTTP call (fine for scoped runs up to ~5 minutes):
curl "https://api.apify.com/v2/acts/lowlanddata~tweedehands-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \-X POST -H "Content-Type: application/json" \-d '{"searchQuery": "gazelle", "maxItems": 100}'
Node.js:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const run = await client.actor('lowlanddata/tweedehands-scraper').call({searchQuery: 'gazelle',maxItems: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("lowlanddata/tweedehands-scraper").call(run_input={"searchQuery": "gazelle", "maxItems": 100})items = client.dataset(run["defaultDatasetId"]).list_items().items
For large split crawls, start the run asynchronously and fetch the dataset when the finished-run webhook fires. Schedules (e.g. a daily price snapshot), webhooks and the Make/Zapier/n8n integrations all work out of the box — this is a standard Apify actor.
Beyond the 5,000-result window
The marketplace API returns at most 5,000 results per query. This scraper automatically splits large queries by category and price band and deduplicates across the shards, so broad crawls are not silently truncated at 5,000 items — a common limitation of similar scrapers. A 60,000-result crawl has been verified end-to-end.
Pricing
Pay per result: you pay for listings actually delivered to your dataset, plus your own platform usage — no subscription, no charge for empty or failed runs. Platform usage is small: a scoped few-hundred-item run costs well under a cent on top of the per-result fee; very large split crawls add roughly $0.10 per 1,000 items. Datacenter proxies are sufficient — no residential proxy surcharge needed.
Free-plan runs are limited to a sample of 25 items, enough to evaluate the output format against your real query.
Compliance
The output contains only public, non-personal commercial data: listing content, prices, categories and municipality-level locations. Seller-identifying fields are removed structurally before anything reaches your dataset — the mapper whitelists fields in, it does not filter fields out, so new marketplace fields can never leak through. Requests are rate-limited to keep load on the marketplace negligible.
Troubleshooting
The actor fails fast with the reason in the run's status message:
- "Provide a search query, a category, or both." — the input was empty; fill in
searchQueryand/orcategoryId. - "priceMinEur must not be higher than priceMaxEur." — inverted price range.
- Unknown category errors — the marketplace rejected the
categoryId; re-check it against a recent result. - Fewer items than requested on a free plan — the 25-item free sample cap; run on a paid Apify plan for full results.
Support
Found an issue or missing a field you need? Open an issue on the actor's Issues tab — reports get fixed, this actor is actively maintained.