# Tenderned Scraper (`nocodeventure/tenderned-scraper`) Actor

Scrape Dutch public procurement publications from TenderNed (tenderned.nl): search aankondigingen, export deadlines, CPV codes, contracting authority, and optional document download links via the public JSON API.

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

## Pricing

from $1.00 / 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.

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

## TenderNed Scraper

### What does TenderNed Scraper do?

**TenderNed Scraper** collects **public procurement announcements** from [TenderNed](https://www.tenderned.nl/) — the Dutch platform for European and national tenders. It returns structured JSON you can use in spreadsheets, CRMs, BI tools, or your own apps.

The Actor uses the **same public data** as the TenderNed website (official JSON endpoints behind the overview pages). **No TenderNed account or API key is required.**

You can:

- **Search** tenders by keyword and date range (e.g. last 30 days)
- **Browse** recent publications with an empty search and a date preset
- **Open specific tenders** by publication ID or overview URL
- Optionally load **full detail** (CPV codes, TED number, reference, keywords) and **document lists** with download links (metadata only — files are not downloaded into the dataset)

### Why use this Actor?

- **Monitor new opportunities** — schedule runs and get fresh tenders in your Apify dataset
- **Market research** — filter by keyword, procedure, or contracting authority fields in the output
- **Integrations** — export JSON, CSV, Excel, or call results via the [Apify API](https://docs.apify.com/api/v2)
- **Predictable limits** — cap pages and results so large searches stay under control

### What data can you extract?

| Field | Description |
| ----- | ----------- |
| `publicatieId` | TenderNed publication ID |
| `kenmerk` | Internal reference number |
| `aanbestedingNaam` | Tender / procurement title |
| `opdrachtgeverNaam` | Contracting authority |
| `publicatieDatum` | Publication date |
| `sluitingsDatum` | Submission / closing deadline (when applicable) |
| `procedure` / `typeOpdracht` | Procedure and contract type (services, supplies, works) |
| `europees` / `digitaal` | European scope and digital submission flags |
| `opdrachtBeschrijving` | Short description |
| `referentieNummer` / `pbNummerTed` | Reference and TED notice number (when present) |
| `cpvCodes` | CPV classification codes |
| `trefwoorden` | Keywords from the publication |
| `overviewUrl` | Link to the tender on tenderned.nl |
| `documents` | Optional list of document names, types, sizes, and download URLs |
| `scrapedAt` | When the row was collected |

See the **Input** and **Output** tabs in Apify Console for the full schema and optional raw JSON fields.

### Search mode vs direct lookup (read this first)

The Actor picks the mode automatically — there is no extra toggle.

| Your input | What happens |
| ---------- | ------------ |
| **Publication IDs** and/or **Start URLs** are filled in | **Direct lookup** — only those tenders are scraped. Search keywords and date filters are **ignored**. |
| Both are **empty** | **Search** — uses keywords if you entered them; if **Search keywords** is empty, it **browses** tenders in the **Publication date preset** (e.g. last 30 days). |

### How to scrape TenderNed

1. Open this Actor on Apify and click **Start**.
2. Pick a mode using the table above:
   - **Search / browse** — leave **Publication IDs** and **Start URLs** empty. Optionally fill **Search keywords**; set **Max search pages** and **Max publications from search**.
   - **Specific tenders** — add **Publication IDs** or **Start URLs** (e.g. `https://www.tenderned.nl/aankondigingen/overzicht/440107`). Do not rely on search fields in this case.
3. Turn on **Include full publication detail** for CPV, TED, and reference fields (recommended).
4. **Include document list** is on by default (file names and download links). Turn it off to save API calls.
5. Start the run and download the dataset from the **Output** tab (JSON, CSV, Excel, XML, and more).

#### Browse recent tenders (no keyword)

Leave **Search keywords** empty, set **Publication date preset** (e.g. last 30 days), and limits. Use **Sort order → Publication date** for newest first.

```json
{
  "search": "",
  "publicatieDatumPreset": "AF30",
  "sort": "publicatiedatum",
  "pageSize": 10,
  "maxPages": 1,
  "maxResults": 10,
  "includeDetail": true
}
```

#### Scrape one tender by ID

```json
{
  "publicatieIds": ["440107"],
  "includeDetail": true
}
```

### Input

Configure everything from the **Input** tab in Console. Main options:

| Option | Purpose |
| ------ | ------- |
| `search` | Keyword filter; empty = browse by date preset (when no IDs/URLs) |
| `publicatieIds` / `startUrls` | Direct lookups; **if set, search is not run** |
| `publicatieDatumPreset` | Limit by publication date (e.g. AF30) |
| `sort` | Relevance, publication date, or closing date |
| `maxPages` / `maxResults` / `pageSize` | Pagination and caps |
| `includeDetail` / `includeDocuments` | On by default; turn off to skip extra API calls |
| `maxRequestsPerMinute` | Throttling (default is suitable for most runs) |
| `proxyConfiguration` | Usually not needed; available if your network requires it |

### Output

Each run writes **one dataset row per publication**. You can download results as **JSON, CSV, Excel, HTML, XML, or RSS**, or fetch them with the Apify API.

By default, each row includes **full publication detail** and a **`documents`** array (file names, types, sizes, and download URLs). File bytes are not stored in Apify — only links.

Example dataset item (one tender; `documents` truncated to two files):

```json
{
  "publicatieId": "440107",
  "kenmerk": 550372,
  "aanbestedingNaam": "BHV-App ten behoeve van het Rijk",
  "opdrachtgeverNaam": "Inkoop Uitvoeringscentrum Dienst Justitiële Inrichtingen (IUC DJI)",
  "publicatieDatum": "2026-09-15T15:48:00.713826",
  "sluitingsDatum": "2026-12-01T11:00:00",
  "procedure": "Openbaar",
  "typeOpdracht": "Diensten",
  "europees": true,
  "digitaal": true,
  "opdrachtBeschrijving": "De scope van de aanbesteding bestaat uit het leveren, onderhouden en doorontwikkelen van een Rijksbrede BHV-App…",
  "referentieNummer": "IUCDJI/INKEA/JWLvH/2026-02",
  "pbNummerTed": "641736-2026",
  "trefwoorden": ["alarmering", "BHV-App", "BHV", "Applicatie", "alarmopvolging"],
  "cpvCodes": [
    {
      "isHoofdOpdracht": true,
      "code": "72000000-5",
      "omschrijving": "IT-diensten: adviezen, softwareontwikkeling, internet en ondersteuning"
    }
  ],
  "juridischKader": "Aanbestedingswet 2012",
  "opdrachtAard": "Raamovereenkomst",
  "overviewUrl": "https://www.tenderned.nl/aankondigingen/overzicht/440107",
  "pdfApiUrl": "https://www.tenderned.nl/papi/tenderned-rs-tns/v2/publicaties/440107/pdf",
  "documentsCount": 28,
  "downloadZipUrl": "https://www.tenderned.nl/papi/tenderned-rs-tns/v2/publicaties/440107/documenten/zip",
  "documents": [
    {
      "documentId": "4929449b2e36bcfd57ee3ad79e7122ed",
      "documentNaam": "TN550372 - EF16 Aankondiging van een opdracht - algemene richtlijn, standaardregeling 20260915154737",
      "typeCode": "pdf",
      "typeOmschrijving": "Portable Document Format",
      "datumPublicatie": "2026-09-15",
      "categorieCode": "ANK",
      "categorieOmschrijving": "Aankondiging",
      "grootteBytes": 231339,
      "downloadUrl": "https://www.tenderned.nl/papi/tenderned-rs-tns/v2/publicaties/440107/documenten/14851404/content"
    },
    {
      "documentId": "037d89a9d1cc8346a33aa1d7e47e2d5b",
      "documentNaam": "Aangepast formulier D Prijzenblad BHV-App 2026 NVI 2",
      "typeCode": "xlsx",
      "typeOmschrijving": "Excel 2007",
      "datumPublicatie": "2026-09-03",
      "categorieCode": "DOC",
      "categorieOmschrijving": "Aanbestedingsdocumenten",
      "grootteBytes": 23477,
      "downloadUrl": "https://www.tenderned.nl/papi/tenderned-rs-tns/v2/publicaties/440107/documenten/14780497/content"
    }
  ],
  "scrapedAt": "2026-09-26T12:00:00.000Z"
}
```

### Pricing

This Actor uses **Pay per event** on Apify (see the **Pricing** tab on the Store listing for current rates). Charges typically apply per **publication saved** and per **search results page** fetched. Set a **maximum cost** in the run options if you want a hard spending cap.

Exact pricing depends on your Apify plan and the Actor’s configured events in Console. For setup, see [docs/APIFY\_BILLING\_SETUP.md](docs/APIFY_BILLING_SETUP.md).

### Tips

- Use **`maxResults`** and **`maxPages`** on first runs to estimate volume before a large crawl.
- Turn off **`includeDocuments`** if you only need summary fields and want fewer API calls per tender.
- **Sort by publication date** when you care about the newest notices, not relevance ranking.
- **Schedule** the Actor in Apify to check for new tenders daily or weekly.

### Disclaimer

This Actor is **not affiliated with, endorsed by, or operated by** TenderNed, the **Rijksdienst voor Ondernemend Nederland (RVO)**, or the Dutch government. TenderNed and related names are trademarks of their respective owners. You use this tool at your own responsibility and must comply with [TenderNed’s terms of use](https://www.tenderned.nl/) and applicable law.

The Actor only collects **publicly published** procurement data and document **metadata/links** shown on TenderNed. It does **not** bypass access controls, log in on your behalf, or download tender files into Apify storage unless you add that in your own workflow using the provided URLs.

Our Actors are intended for **ethical, lawful** use. Results may include **personal data** (e.g. names in publication text). In the EU, personal data is protected by the **GDPR** and similar rules apply elsewhere. Do not process personal data unless you have a **lawful basis**; if unsure, seek legal advice.

We do not guarantee completeness, accuracy, or timeliness of data — always verify critical decisions against the official TenderNed publication.

### Support

Questions or bugs? Use the **Issues** tab on this Actor’s Apify page. For automation, see the **API** tab to start runs and fetch datasets programmatically.

# Actor input Schema

## `search` (type: `string`):

Free-text search (same as the TenderNed overview search box). Leave empty to browse publications in the date preset below. Ignored when **Publication IDs** or **Start URLs** are set — those always take precedence.

## `publicatieIds` (type: `array`):

Optional TenderNed publicatie IDs (e.g. 440107). If this or **Start URLs** has any value, only those tenders are scraped (search is not run).

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

TenderNed overview pages; the numeric ID is extracted from each URL. If set (with or without IDs), search is skipped.

## `publicatieDatumPreset` (type: `string`):

Limits search results by publication date (TenderNed `publicatieDatumPreset`). Use ALL for no date filter.

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

How search results are ordered: relevance (default), publication date (newest first), or closing deadline.

## `pageSize` (type: `integer`):

Results per API page (max 100).

## `maxPages` (type: `integer`):

Maximum number of search result pages to fetch.

## `maxResults` (type: `integer`):

Cap on new publications saved from search (IDs/start URLs are not counted toward this cap).

## `includeDetail` (type: `boolean`):

Calls `/publicaties/{id}` for CPV codes, TED number, reference, keywords, etc.

## `includeDocuments` (type: `boolean`):

Calls `/publicaties/{id}/documenten` and adds download URLs (does not download file bytes).

## `maxRequestsPerMinute` (type: `integer`):

Throttle between TenderNed API calls.

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

Usually not required; TenderNed JSON API is public. Enable if your network blocks outbound requests.

## Actor input object example

```json
{
  "search": "",
  "publicatieIds": [],
  "startUrls": [],
  "publicatieDatumPreset": "AF30",
  "sort": "relevantie",
  "pageSize": 10,
  "maxPages": 1,
  "maxResults": 10,
  "includeDetail": true,
  "includeDocuments": true,
  "maxRequestsPerMinute": 60,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset items with tender fields and optional documents

# 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 = {
    "search": "",
    "publicatieIds": [],
    "startUrls": [],
    "publicatieDatumPreset": "AF30",
    "sort": "relevantie",
    "pageSize": 10,
    "maxPages": 1,
    "maxResults": 10,
    "includeDocuments": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("nocodeventure/tenderned-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 = {
    "search": "",
    "publicatieIds": [],
    "startUrls": [],
    "publicatieDatumPreset": "AF30",
    "sort": "relevantie",
    "pageSize": 10,
    "maxPages": 1,
    "maxResults": 10,
    "includeDocuments": True,
}

# Run the Actor and wait for it to finish
run = client.actor("nocodeventure/tenderned-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 '{
  "search": "",
  "publicatieIds": [],
  "startUrls": [],
  "publicatieDatumPreset": "AF30",
  "sort": "relevantie",
  "pageSize": 10,
  "maxPages": 1,
  "maxResults": 10,
  "includeDocuments": true
}' |
apify call nocodeventure/tenderned-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nocodeventure/tenderned-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/Mxyeru3b26kySanv9/builds/2tVjJb35KgPZaD9g9/openapi.json
