# 2dehands & 2ememain Scraper (GDPR-safe) (`lowlanddata/tweedehands-scraper`) Actor

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.

- **URL**: https://apify.com/lowlanddata/tweedehands-scraper.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## 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:

```json
{
  "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:

- `priceCents` is the asking price in euro cents; listings without a price omit it. `priceType` tells you how to read it: `FIXED` (asking price) or `MIN_BID` (minimum bid), plus the marketplace's other kinds when they occur.
- `postedAt` is the posting date exactly as the marketplace displays it — a date, or a relative label like `Vandaag` (today) for recent listings.
- `latitude`/`longitude` are the marketplace's own municipality-level coordinates, not a seller address.
- `description` is the snippet the marketplace search returns, not the full listing page text.
- `imageUrls` are protocol-relative (`//images...`); prepend `https:` to use them.
- `attributes` contains the whitelisted set: `condition` and `delivery`, 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):

```bash
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:

```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:

```python
from apify_client import ApifyClient

client = 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.

One honest limit: titles and descriptions are the seller's own words, delivered as-is. If a seller chooses to type contact details into their listing text, that text is not rewritten — the guarantee covers the marketplace's data fields, not the content sellers publish about themselves.

### 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 `searchQuery` and/or `categoryId`.
- **"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.

# Actor input Schema

## `searchQuery` (type: `string`):

Free-text search. Provide this, a category, or both.

## `domain` (type: `string`):

Which marketplace to scrape.

## `categoryId` (type: `integer`):

Numeric marketplace category ID to scope the crawl. Every result includes its <code>categoryId</code>, so run a broad search first to discover the IDs you need. Optional.

## `priceMinEur` (type: `integer`):

Only return listings priced at or above this amount. Optional.

## `priceMaxEur` (type: `integer`):

Only return listings priced at or below this amount. Optional.

## `sortBy` (type: `string`):

Order of the results. Newest first is the default and the right choice for monitoring.

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

Stop after this many listings.

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

Proxy settings. Keep Apify proxy enabled.

## Actor input object example

```json
{
  "searchQuery": "gazelle",
  "domain": "2dehands.be",
  "sortBy": "date",
  "maxItems": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Scraped marketplace listings, one JSON object per listing.

# 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 = {
    "searchQuery": "gazelle",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/tweedehands-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 = {
    "searchQuery": "gazelle",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/tweedehands-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQuery": "gazelle",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/tweedehands-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=lowlanddata/tweedehands-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "2dehands & 2ememain Scraper (GDPR-safe)",
        "description": "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.",
        "version": "0.1",
        "x-build-id": "QxgOkaWM1Sm1ldpk1"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/lowlanddata~tweedehands-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-lowlanddata-tweedehands-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/lowlanddata~tweedehands-scraper/runs": {
            "post": {
                "operationId": "runs-sync-lowlanddata-tweedehands-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/lowlanddata~tweedehands-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-lowlanddata-tweedehands-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQuery": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Free-text search. Provide this, a category, or both."
                    },
                    "domain": {
                        "title": "Marketplace",
                        "enum": [
                            "2dehands.be",
                            "2ememain.be"
                        ],
                        "type": "string",
                        "description": "Which marketplace to scrape.",
                        "default": "2dehands.be"
                    },
                    "categoryId": {
                        "title": "Category ID",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Numeric marketplace category ID to scope the crawl. Every result includes its <code>categoryId</code>, so run a broad search first to discover the IDs you need. Optional."
                    },
                    "priceMinEur": {
                        "title": "Minimum price (EUR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only return listings priced at or above this amount. Optional."
                    },
                    "priceMaxEur": {
                        "title": "Maximum price (EUR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only return listings priced at or below this amount. Optional."
                    },
                    "sortBy": {
                        "title": "Sort order",
                        "enum": [
                            "date",
                            "price_asc",
                            "price_desc",
                            "relevance"
                        ],
                        "type": "string",
                        "description": "Order of the results. Newest first is the default and the right choice for monitoring.",
                        "default": "date"
                    },
                    "maxItems": {
                        "title": "Max items",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Stop after this many listings.",
                        "default": 1000
                    },
                    "proxyConfiguration": {
                        "title": "Proxy",
                        "type": "object",
                        "description": "Proxy settings. Keep Apify proxy enabled.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
