# EU Public Tenders (TED) Search & Monitor (`mersetti/eu-tenders-ted`) Actor

Search EU public procurement notices from TED (Tenders Electronic Daily) by keyword, CPV code, country, notice type, date and value. Get buyer, deadline, estimated value, CPV, lots and links, and daily alerts for new tenders.

- **URL**: https://apify.com/mersetti/eu-tenders-ted.md
- **Developed by:** [Max Prozapas](https://apify.com/mersetti) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Tenders Scraper — TED Public Procurement Search & Alerts

Search **EU public procurement notices** from **TED (Tenders Electronic Daily)**, the official journal of
European public tenders, and get clean, structured data: title, buyer, country, CPV codes, deadline, estimated
value, lots, winners and direct links to the notice and its PDF. Filter by **keywords, CPV codes, countries,
notice type, publication date and contract value**, with no API key, login or browser needed.

**Monitor mode** remembers which notices you already received and outputs **only new tenders**. Schedule it daily
and get **tender alerts** by email, Slack, Google Sheets or webhook. You pay only for new notices.

TED publishes over **3,000 notices every working day** from the 27 EU member states, the EEA, Switzerland,
EU institutions and many other countries: calls for tender, prior information notices, contract awards and more.

### Why this TED scraper

- **Official data source**: uses the public TED Search API v3 of the Publications Office of the EU. No scraping of
  HTML pages, no blocking, stable output.
- **Business-friendly filters**: type CPV codes, ISO country codes (`DE`, `FR`, `PL`) and keywords. The Actor
  builds the TED expert query for you. Power users can paste their own expert query.
- **CPV hierarchy built in**: `72000000` (IT services) also finds every sub-code such as `72260000` (software
  services). Short prefixes like `45` (construction) work too.
- **Clean, flat records**: English title where available (falls back to the original language), buyer name and
  city, place of performance (countries and NUTS regions), main CPV with label, deadline as ISO date-time,
  `isOpen` and `daysToDeadline`, estimated/awarded value with currency plus an approximate EUR value, lots, winners.
- **Tender alerts**: monitor mode outputs only notices not seen in previous runs. Several watchlists with
  different monitor IDs.
- **Value filter across currencies**: `minValueEur` also matches notices in PLN, SEK, CZK, HUF, DKK, RON, CHF, ...
- **Cheap**: pay per notice, no monthly rental.

### Use cases

- **Bid / tender alerts for agencies & SMEs**: get every new call for tender in your sector and countries each
  morning, with the deadline and a link to the tender documents.
- **Sales leads**: find public buyers that buy what you sell, and contract award notices with the winning
  companies (your competitors or partners).
- **Market research**: analyse public spending by CPV sector, country, procedure type and contract value.
- **Consultants & bid writers**: monitor opportunities for several clients with separate watchlists.
- **Competitive intelligence**: track which companies win contracts (`winners`) and at what price (`awardedValue`).
- **Data pipelines**: export EU tenders to CSV, Excel, JSON, Google Sheets, Airtable, a CRM or your database.

### CPV code tips

CPV (Common Procurement Vocabulary) codes classify what is being bought. Some popular ones:

| CPV | Sector |
|---|---|
| `72000000` | IT services: consulting, software development, Internet and support |
| `48000000` | Software packages and information systems |
| `30200000` | Computer equipment and supplies |
| `79400000` | Business and management consultancy |
| `79340000` | Advertising and marketing services |
| `80500000` | Training services |
| `71000000` | Architectural, construction, engineering and inspection services |
| `45000000` | Construction work |
| `33100000` | Medical equipment |
| `90900000` | Cleaning and sanitation services |
| `09310000` | Electricity |
| `60100000` | Road transport services |

- A code matches all its sub-codes, so broad codes (`72000000`) give more results than specific ones (`72212000`).
- Prefixes work: `72` = division 72, `7222` = all codes starting with 7222.
- Check digits (`72000000-5`) are ignored.
- Look up codes in the official
  [CPV list on EU Vocabularies](https://op.europa.eu/en/web/eu-vocabularies/cpv).

### Input

| Field | Description |
|---|---|
| `keywords` | Full-text words or phrases; a notice matches if it contains any of them. Add translations for multilingual coverage. |
| `cpvCodes` | CPV codes or prefixes, e.g. `72000000`, `45`. Sub-codes are included automatically. |
| `countries` | ISO codes (`DE`, `FR`, `PL`, `EL`/`GR`, `UK`/`GB`, ...) or NUTS region codes (`DE21`, `FR10`). |
| `countryFilter` | `placeOrBuyer` (default), `placeOfPerformance` or `buyer`. |
| `noticeTypes` | `competition` (calls for tender), `planning` (prior information), `result` (contract awards), `directAward` (VEAT), `modification`. Empty = all. |
| `publishedWithinDays` | Notices published in the last N days (default 7, 0 = no limit). |
| `publishedFrom`, `publishedTo` | Exact publication date range (YYYY-MM-DD). `publishedFrom` overrides `publishedWithinDays`. |
| `onlyOpenForBidding` | Only notices whose submission deadline is in the future. |
| `minValueEur` | Minimum total value in EUR (other currencies converted approximately). Notices without a value are excluded. |
| `maxItems` | Maximum notices to output, newest first (default 100). In monitor mode: max new notices per run. |
| `expertQuery` | Raw TED expert query. Replaces all filters above. |
| `monitorMode` | Output only notices not delivered in previous runs. |
| `monitorId` | Separate saved state per watchlist (default `default`). |
| `baselineOnFirstRun` | First monitor run only remembers current notices (no output, no cost). |

#### Example input: IT tenders in Germany and France (last 7 days)

```json
{
  "cpvCodes": ["72000000"],
  "countries": ["DE", "FR"],
  "noticeTypes": ["competition"],
  "publishedWithinDays": 7,
  "maxItems": 50
}
```

#### Example input: daily tender alert, open tenders over €500k

```json
{
  "keywords": ["cybersecurity", "cloud computing"],
  "countries": ["DE", "AT", "NL", "BE"],
  "noticeTypes": ["competition"],
  "onlyOpenForBidding": true,
  "minValueEur": 500000,
  "publishedWithinDays": 3,
  "maxItems": 200,
  "monitorMode": true,
  "monitorId": "security-dach-benelux"
}
```

#### Example input: expert query

```json
{
  "expertQuery": "classification-cpv IN (72000000) AND place-of-performance IN (DEU) AND publication-date>=20261001",
  "maxItems": 500
}
```

Build and test expert queries at [TED expert search](https://ted.europa.eu/en/search/expert-search).
Country codes in expert queries are 3-letter (`DEU`, `FRA`), dates are `YYYYMMDD`.

### Output

One record per notice. Real example from a test run (contract notice, Germany, CPV 72000000):

```json
{
  "noticeId": "705091-2026",
  "publicationNumber": "705091-2026",
  "title": "Beratungsleistungen für das Format Digi-Expert-kommunal für das Hessische Ministerium für Digitalisierung und Innovation in zwei Losen",
  "titleLanguage": "deu",
  "tedTitle": "Germany – IT services: consulting, software development, Internet and support – Beratungsleistungen für das Format Digi-Expert-kommunal für das Hessische Ministerium für Digitalisierung und Innovation in zwei Losen",
  "buyerName": "Land Hessen, vertreten durch die Hessische Zentrale für Datenverarbeitung",
  "buyerCountry": "DE",
  "buyerCity": "Wiesbaden",
  "buyerWebsite": "https://vergabe.hessen.de",
  "placeOfPerformanceCountries": ["DE"],
  "placeOfPerformanceNuts": ["DE714"],
  "mainCpvCode": "72000000",
  "mainCpvLabel": "IT services: consulting, software development, Internet and support",
  "cpvDivision": "IT services: consulting, software development, Internet and support",
  "cpvCodes": ["72000000"],
  "contractNature": ["services"],
  "formType": "competition",
  "noticeType": "cn-standard",
  "noticeTypeLabel": "Contract notice",
  "procedureType": "open",
  "procedureTypeLabel": "Open procedure",
  "frameworkAgreement": true,
  "publicationDate": "2026-10-13",
  "dispatchDate": "2026-10-12",
  "deadline": "2026-10-22T10:00:00+02:00",
  "daysToDeadline": 7,
  "isOpen": true,
  "estimatedValue": 2258000,
  "estimatedValueCurrency": "EUR",
  "awardedValue": null,
  "awardedValueCurrency": null,
  "value": 2258000,
  "currency": "EUR",
  "valueEur": 2258000,
  "lotsCount": 2,
  "lotTitles": ["Grundlagen der digitalen Transformation", "Technische Umsetzung/konkrete Anwendungen"],
  "winners": [],
  "descriptionSummary": "Beratungsleistungen für das Format \"Digi-Expert-kommunal\" für das Hessische Ministerium für Digitalisierung und Innovation in zwei Losen",
  "url": "https://ted.europa.eu/en/notice/-/detail/705091-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/705091-2026/pdf",
  "xmlUrl": "https://ted.europa.eu/en/notice/705091-2026/xml",
  "documentsUrl": "https://vergabe.hessen.de/NetServer/TenderingProcedureDetails?function=_Details&TenderOID=54321-Tender-1a05b7e4ea4-db4b01198de1e31",
  "submissionUrl": "https://vergabe.hessen.de",
  "scrapedAt": "2026-10-14T09:54:13.135Z"
}
```

Field notes:

- `title` is the procedure title in English if the buyer provided one, otherwise in the original language
  (`titleLanguage`). `tedTitle` is TED's English headline: country, CPV label and title.
- `deadline` is the earliest tender submission deadline across lots, with the buyer's time zone offset.
- `value` / `currency` is TED's total value of the notice (estimated value for calls for tender, awarded value for
  award notices). `valueEur` is an indicative conversion using fixed approximate rates.
- Award notices (`result`) include `winners` and `awardedValue`.
- `null` means the buyer did not publish that information (values are often omitted, especially in some countries).

The run's `SUMMARY` record (key-value store) contains the exact TED query used, the number of matching notices,
notices read and output, monitor statistics and any warnings about ignored input values.

### How monitoring works

- Delivered notice IDs are saved in the named key-value store `ted-monitor` under `seen-<monitorId>`.
- Each run outputs only matching notices that were not delivered before, newest first, up to `maxItems`.
  Notices cut off by `maxItems` or by the run's cost limit are delivered in the next run.
- With `baselineOnFirstRun`, the first run only remembers the current matches, so you get alerts only for
  notices published later.
- Keep `publishedWithinDays` at a few days (e.g. 3-7) for daily schedules: TED notices never change their
  publication date, so a short window is enough and keeps runs fast.

### Pricing

**Pay per notice**: you pay a small fee for each notice in the dataset (event `notice`), nothing for the search
itself. In monitor mode you pay only for new notices, so a daily alert for one sector typically costs cents per day.
Set a maximum cost per run, and the Actor stops cleanly when it is reached.

### FAQ

**Do I need a TED account or API key?**
No. The TED Search API is public and free. The Actor uses it anonymously.

**Which countries are covered?**
All notices published on TED: the 27 EU member states, EEA countries (Norway, Iceland, Liechtenstein),
Switzerland, EU institutions and agencies, and tenders from other countries financed by EU programmes.

**Why does a search in English miss some tenders?**
Notices are written in the buyer's language. Full-text keywords are matched as written, so add translations
(e.g. `software`, `logiciel`, `oprogramowanie`) or, better, use CPV codes, which are language-independent.

**Can I get older notices?**
Yes. Use `publishedFrom` / `publishedTo` (TED data goes back many years) and raise `maxItems`. One run reads
up to 50,000 notices; split very large exports into several date ranges.

**How do I get only tenders I can still bid on?**
Set `noticeTypes` to `competition` and enable `onlyOpenForBidding`.

**How do I receive alerts by email or Slack?**
Enable `monitorMode`, create a Schedule (e.g. every weekday at 08:00) and add an integration (email, Slack,
Google Sheets, Zapier, Make or a webhook) that runs when the Actor succeeds.

**Why are some values missing?**
Publishing the estimated value is optional for buyers. `minValueEur` excludes notices without a value.

### Limitations

- Data is as published on TED; quality and completeness depend on the buyer. Some notices have no value,
  deadline or English title.
- Only notices above EU thresholds (and voluntary publications) are on TED. National below-threshold tenders are
  published on national portals.
- CPV labels come from TED's English notice headline (main CPV) plus a built-in table of CPV divisions; labels of
  all additional CPV codes are not included.
- Currency conversion for `minValueEur` and `valueEur` uses fixed approximate exchange rates.

### Legal

The Actor uses the official public TED Search API of the Publications Office of the European Union. TED notices
are official open data; reuse is authorised under the EU open data policy (Commission Decision 2011/833/EU), with
attribution of the source (© European Union, https://ted.europa.eu). The Actor does not log in or bypass any
protection. Notices may contain names and contact details of contact persons; process such personal data in line
with the GDPR.

### Related tools

- [Career Sites Jobs Feed (11 ATS)](https://apify.com/mersetti/ats-jobs-feed)
- [Substack to Markdown for AI & RAG](https://apify.com/mersetti/substack-to-markdown)
- [Shopify Store Products & Price Change Monitor](https://apify.com/mersetti/shopify-products-monitor)

# Actor input Schema

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

Full-text search in the notice (title, description, buyer...). A notice matches if it contains ANY of these words or phrases. Phrases like "cloud computing" are matched exactly. Notices are multilingual, so add translations for better coverage (e.g. "software", "logiciel", "Software").

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

Common Procurement Vocabulary codes. A code also matches all its sub-codes: 72000000 (IT services) finds 72260000 (software services) too. Short prefixes work as well: "72", "4521". Check digits like "-5" are ignored.

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

ISO country codes (DE, FR, PL, ES, IT, NL, ... EL and UK are accepted too) or NUTS region codes (e.g. DE21 for Oberbayern, FR10 for Île-de-France). Empty = all countries.

## `countryFilter` (type: `string`):

Which country to match: the place of performance, the buyer's country, or either of them. NUTS region codes always filter the place of performance.

## `noticeTypes` (type: `array`):

Kinds of notices to return. Allowed values: "competition" (contract notices / calls for tender, open for bids), "planning" (prior information notices), "result" (contract award notices), "directAward" (voluntary ex-ante transparency notices), "modification" (contract modification notices). Empty = all types.

## `publishedWithinDays` (type: `integer`):

Only notices published in the last N days. 0 = no limit. Ignored when "Published from" is set. TED publishes new notices every working day (Monday to Friday).

## `publishedFrom` (type: `string`):

Only notices published on or after this date (YYYY-MM-DD). Overrides "Published within the last N days".

## `publishedTo` (type: `string`):

Only notices published on or before this date (YYYY-MM-DD).

## `onlyOpenForBidding` (type: `boolean`):

Only notices whose tender submission deadline has not passed yet. Notices without a deadline (e.g. prior information or award notices) are excluded.

## `minValueEur` (type: `integer`):

Only notices with a total (estimated or awarded) value of at least this amount. Values in other currencies (PLN, SEK, CZK, ...) are compared using approximate exchange rates. Notices without a published value are excluded. 0 = no value filter.

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

Maximum number of notices to output (newest first). In monitor mode: maximum number of new notices per run.

## `expertQuery` (type: `string`):

Raw TED expert search query, e.g. classification-cpv IN (72000000) AND place-of-performance IN (DEU) AND publication-date>=20261001. When set, it replaces the filters above (keywords, CPV, countries, notice types, dates, value). Build and test queries at https://ted.europa.eu/en/search/expert-search. Results are sorted newest first unless the query has its own SORT BY.

## `monitorMode` (type: `boolean`):

Remembers which notices were already delivered and outputs only notices not seen in previous runs. Schedule the Actor daily to get tender alerts by email, Slack, Google Sheets or webhook. You pay only for new notices.

## `monitorId` (type: `string`):

Name of the saved state. Use different IDs for different searches (e.g. "it-germany", "construction-poland").

## `baselineOnFirstRun` (type: `boolean`):

On the first run of a new monitor, only remember the currently matching notices (no output, no cost), so later runs report only notices published afterwards. Off = the first run delivers the current matches.

## Actor input object example

```json
{
  "cpvCodes": [
    "72000000"
  ],
  "countries": [
    "DE",
    "FR"
  ],
  "countryFilter": "placeOrBuyer",
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 7,
  "onlyOpenForBidding": false,
  "minValueEur": 0,
  "maxItems": 50,
  "monitorMode": false,
  "monitorId": "default",
  "baselineOnFirstRun": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "cpvCodes": [
        "72000000"
    ],
    "countries": [
        "DE",
        "FR"
    ],
    "noticeTypes": [
        "competition"
    ],
    "publishedWithinDays": 7,
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("mersetti/eu-tenders-ted").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 = {
    "cpvCodes": ["72000000"],
    "countries": [
        "DE",
        "FR",
    ],
    "noticeTypes": ["competition"],
    "publishedWithinDays": 7,
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("mersetti/eu-tenders-ted").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 '{
  "cpvCodes": [
    "72000000"
  ],
  "countries": [
    "DE",
    "FR"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 7,
  "maxItems": 50
}' |
apify call mersetti/eu-tenders-ted --silent --output-dataset

```

## MCP server setup

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

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/btWrtGdO4HmVdkZso/builds/dYGpYcpsN7KaupJin/openapi.json
