# EU and Dutch Tender Monitor (TED and TenderNed) (`datasignalslab/eu-tender-monitor`) Actor

Monitor public tenders from TED (all EU countries) and TenderNed (Netherlands) in one feed: filter by country, CPV code, keyword, buyer and value. Clean JSON with deadline, buyer and link. Pay per tender found.

- **URL**: https://apify.com/datasignalslab/eu-tender-monitor.md
- **Developed by:** [DataSignals Lab](https://apify.com/datasignalslab) (community)
- **Categories:** Lead generation, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 tender-founds

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

## EU and Dutch Tender Monitor (TED and TenderNed)

**Know about a public tender the day it is published, not when a competitor has already bid.** Governments, municipalities, hospitals, universities and utilities across the EU must publish their contracts. In the Netherlands they go to TenderNed, above the EU threshold they also go to TED (Tenders Electronic Daily). Reading both portals every morning is a job in itself, and the alerting services that do it for you start at four figures per year. This Actor reads both sources through their public JSON APIs and returns one clean feed: title, buyer, country, CPV codes, procedure, deadline, estimated value and a link to the notice. Filter by country, sector (CPV), keyword, buyer and value, run it on a schedule, and pay only for the tenders it finds.

A real run example: three days back, country NL, no further filters, returned 295 TenderNed publications and hit the 300 TED cap in 16 seconds, from a hospital tender for hygiene boxes to a province looking for a flexible pool of IT professionals under a framework agreement. Narrowed to CPV 72 (IT services) and one day back, the same run returns 14 TenderNed publications and 28 TED notices.

### Who uses this

- **Bid and sales teams** at IT, construction, facility, consultancy and healthcare suppliers who need every relevant tender in their CPV range on the day it appears.
- **Bid consultants and tender writers** tracking several clients and sectors at once.
- **Market and competition analysts** following which authorities buy what, with award notices included.
- **Lead generation**: a public tender is a budget that has been approved. The buyer name and deadline tell you who to call and when.
- **AI agents and data teams** that want structured tender data without scraping two portals in two languages.

### What you get per tender

| Field | Example |
| --- | --- |
| source | `ted` or `tenderned` |
| noticeId | `723093-2026` (TED) or `445954` (TenderNed) |
| publishedAt | `2026-10-20` |
| deadline | `2026-11-27` (TED) or `2026-11-25T13:00:00` (TenderNed) |
| title | `Europese aanbesteding ICT-dienstverlening` |
| buyer | `Stichting voor Algemeen Toegankelijk Onderwijs Eindhoven e.o.` |
| buyerCountry | `NL` |
| cpvCodes | `["72315000"]` |
| procedureType | `open`, `restricted`, `negotiated-with-prior-call` |
| noticeType | `cn-standard`, `can-standard` (TED) or the Dutch publication type (TenderNed) |
| estimatedValue | `700000` (TED only, TenderNed does not publish values) |
| currency | `EUR` |
| description | Up to 1000 characters of the notice text |
| url | Link to the notice on ted.europa.eu or tenderned.nl |

```json
{
  "source": "ted",
  "noticeId": "723093-2026",
  "publishedAt": "2026-10-20",
  "deadline": "2026-11-27",
  "title": "Europese aanbesteding ICT-dienstverlening",
  "buyer": "Stichting voor Algemeen Toegankelijk Onderwijs Eindhoven e.o.",
  "buyerCountry": "NL",
  "cpvCodes": ["72315000"],
  "procedureType": "open",
  "noticeType": "cn-standard",
  "estimatedValue": 700000.0,
  "currency": "EUR",
  "description": "Middels deze aanbesteding wenst Aanbestedende dienst te komen tot ...",
  "url": "https://ted.europa.eu/en/notice/-/detail/723093-2026"
}
```

### Why two sources

TenderNed is the mandatory Dutch portal and carries every national tender, including the ones below the EU threshold that never reach TED. TED carries the EU-wide notices for all member states plus Norway, Iceland, Liechtenstein and Switzerland. Dutch tenders above the threshold appear on both. With `countries` set to `NL` you get the full Dutch picture, with `NL` plus `BE` and `DE` you get the Benelux and Germany in one run.

### Input

- **countries**: two-letter codes, default `["NL"]`. `NL` switches on TenderNed, every code is served from TED.
- **cpvCodes**: CPV codes or prefixes. `72` is all IT services, `7226` software services, `45` construction, `79` business services. Prefixes cover everything below them on both sources.
- **keywords**: at least one must appear in title or description (case-insensitive). Use the language of the notice.
- **daysBack**: publication window ending today, 1 to 30. `1` is yesterday and today.
- **buyerFilter**: substring on the contracting authority, for example `gemeente` or `Rijkswaterstaat`.
- **minValue**: minimum published estimated value in EUR. Notices without a value are dropped when set, which limits the feed to TED.
- **maxResults**: cap on returned tenders, newest first, up to 1000.

### How it works

TenderNed is read through its public publications API (list plus one detail call per tender for the CPV codes). TED is read through the official Search API v3 with an expert query that pushes country, CPV, keyword, buyer and value filters to the server. No HTML scraping, no login, no API key. Both sources are polled independently: if one is down, the other still delivers and the run log tells you which one was skipped. Results are deduplicated on notice ID and sorted newest first.

### Use with AI agents and automation

- **Schedule it** daily at 07:00 and push the dataset to Slack, Teams, Google Sheets or your CRM with an Apify integration or a webhook.
- **AI agents**: call it as a tool from LangChain, LlamaIndex or over MCP so an agent can answer "which Dutch municipalities published an IT tender this week and when do they close?" with source links.
- **Pipelines**: JSON output per run, filter on `noticeType` to split new competitions (`cn-*`) from award notices (`can-*`).

### Pricing

Pay per tender found: $0.005 per returned tender ($5 per 1,000), nothing for an empty run. A daily run for IT services (CPV 72) in the Netherlands returned 42 tenders on 23 October 2026, so a month of daily monitoring for one sector costs in the order of 6 dollars, and a run limited to new competitions or a narrower CPV range costs less. Compare that with commercial tender alert services at well over 1000 euros per year.

#### More from DataSignals Lab

This Actor is one of the pay-per-result data Actors of [DataSignals Lab](https://datasignalslab.com): job listings per ATS platform and job board, app and company reviews, YouTube comments and transcripts, website contacts and tech stacks. Every Actor returns the same clean JSON style and charges only for rows that land in the dataset, so you can combine feeds without remapping fields. All Actors and prices are listed on [datasignalslab.com](https://datasignalslab.com).

### Data source and compliance

Sources: TenderNed (PIANOo, Dutch Ministry of Economic Affairs) and TED (Publications Office of the European Union). Both are official, public and free to reuse. The data describes public bodies and procurement procedures. No personal data is collected or returned.

### FAQ

**Does a Dutch tender above the EU threshold appear twice?** No. It is published on TenderNed and on TED under different identifiers, and the actor merges the two on title and buyer so you pay for it once. The newest publication wins, so a TED record can carry an estimated value that TenderNed does not publish.
**Why is estimatedValue empty for TenderNed?** The TenderNed API does not expose the estimated value. TED does, when the buyer published it.
**Can I search in English?** TED notices carry the title in the language of the buyer. For Dutch, German or French tenders use keywords in that language, or filter on CPV instead, which is language independent.
**Are award notices included?** Yes. The `noticeType` field tells you whether a record is a new competition, a prior information notice, an award or a modification.
**Which countries work?** All EU member states plus NO, IS, LI, CH and GB on TED. TenderNed is Netherlands only.

More data products from the same maker: https://datasignalslab.com

*Keywords: EU tender monitor, TED API, TenderNed API, public procurement data, aanbestedingen, CPV code search, tender alerts, government contracts Netherlands, procurement notices Europe, tender feed for AI agents.*

# Actor input Schema

## `countries` (type: `array`):

Two-letter country codes of the contracting authority, for example NL, BE, DE, FR. NL also switches on TenderNed, the Dutch national portal. Every other code is served from TED only. Empty means NL.

## `cpvCodes` (type: `array`):

Leave empty for every sector. A prefix covers everything below it: 72 is all IT services, 7226 is software services, 45 is construction, 48 is software packages, 79 is business services. Full codes such as 72000000-5 work too.

## `keywords` (type: `array`):

Only tenders whose title or description contains at least one of these words, case-insensitive. Use the language of the notice: Dutch for TenderNed and most Dutch TED notices.

## `daysBack` (type: `integer`):

Publication window ending today. 1 = yesterday and today, 7 = the last week.

## `buyerFilter` (type: `string`):

Only tenders where the name of the contracting authority contains this text, for example gemeente, Rijkswaterstaat or Universiteit.

## `minValue` (type: `integer`):

Only tenders with a published estimated value at or above this amount. Notices without a value are dropped when a minimum is set. TenderNed does not publish values, so a minimum limits the feed to TED.

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

Upper bound on returned tenders, newest first. You pay per returned tender.

## Actor input object example

```json
{
  "countries": [
    "NL"
  ],
  "cpvCodes": [
    "72"
  ],
  "keywords": [],
  "daysBack": 1,
  "buyerFilter": "",
  "minValue": 0,
  "maxResults": 100
}
```

# Actor output Schema

## `tenders` (type: `string`):

All tenders from this run as JSON, one object per row.

## `tendersCsv` (type: `string`):

The same tenders as a CSV download.

# 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 = {
    "countries": [
        "NL"
    ],
    "cpvCodes": [
        "72"
    ],
    "keywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("datasignalslab/eu-tender-monitor").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 = {
    "countries": ["NL"],
    "cpvCodes": ["72"],
    "keywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("datasignalslab/eu-tender-monitor").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 '{
  "countries": [
    "NL"
  ],
  "cpvCodes": [
    "72"
  ],
  "keywords": []
}' |
apify call datasignalslab/eu-tender-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datasignalslab/eu-tender-monitor"
        }
    }
}
```

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/gvoPX3tZowmLVHcLI/builds/eojJZara35YOVKd4v/openapi.json
