# EU Tenders Scraper: TED, All 27 Member States (`deriverge/eu-tenders-scraper`) Actor

\[$2.00 / 1K] Public procurement notices from TED, the official EU journal, covering all 27 member states plus the EEA. Filter by country, CPV code, keyword, deadline and value. Title and description in the language you ask for. New notices only since your last run.

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

## Pricing

from $0.50 / 1,000 notice returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### What does Public Tenders Scraper do?

**EU Tenders Scraper** returns public procurement notices from **TED**, the European Union journal covering all 27 member states and the European Economic Area, and from **both UK services**, in one table. Every row carries the deadline, the value, the buyer, the CPV codes and a link to the notice.

No browser, no proxies, no API key. Every source is an official, public interface.

### One query instead of twenty-seven

There are more than a hundred tender actors on this store and almost all of them cover one country. A company bidding across Europe needs a dozen tools and a dozen different schemas, then has to merge them by hand.

This one takes a single query:

| Source | What it covers |
|---|---|
| `ted` | Every EU member state plus Iceland, Liechtenstein, Norway and Switzerland |
| `uk-fts` | Find a Tender, the UK service for contracts above the threshold |
| `uk-cf` | Contracts Finder, the UK service for contracts below it |

### The deadline is the product

A tender is worth reading only while you can still bid for it. Every row therefore carries `deadline` as a real timestamp and `daysToDeadline` as a number you can sort and filter on, even though the sources publish it in three different shapes and sometimes once per lot.

Turn on `onlyOpen` and the run drops two things: notices whose deadline has passed, and contract award notices, which announce a contract somebody else already won. Neither is charged.

### Filters that match how buyers think

- **`cpv`** takes Common Procurement Vocabulary codes, the official taxonomy of what is being bought. `72000000` is IT services, `45000000` is construction. A division code matches everything inside it.
- **`countries`** takes ordinary two-letter codes and translates them to whatever each source expects.
- **`keywords`** searches the full text of the notice.
- **`minValue`** keeps the contracts worth bidding for. Notices with no published value are kept, because an absent value is not a small one.
- **`deadlineAfter`** keeps only what you can still submit.

### Your language, and honest about it

The EU journal publishes each notice in the language of the buyer and usually in the other official languages too. A German notice arrives as a map of two dozen translations, and most tools hand you whichever one came first.

Set `language` to the code you want. Each row gets the title and description in that language, falls back to English, then to whatever exists, and records in `language` which one you actually got plus every language the notice was available in. You always know what you are reading.

### Only what is new

Turn on `newOnly`, give the run a watch name or save it as a task, and schedule it daily. Each run compares against the previous snapshot and returns only notices that are new or whose deadline or status moved. A tender has a short deadline, so a scheduled watch is worth more than a one-off export, and you pay for the new notices and nothing else.

### Input

```json
{
  "sources": ["ted", "uk-fts", "uk-cf"],
  "countries": ["DE", "NL", "PL"],
  "cpv": ["72000000"],
  "keywords": ["cloud"],
  "deadlineAfter": "2026-10-01",
  "onlyOpen": true,
  "minValue": 100000,
  "language": "en",
  "newOnly": true,
  "watchKey": "it-services-dach",
  "maxItems": 1000
}
```

### Output

```json
{
  "key": "ted:653878-2026",
  "source": "ted",
  "sourceName": "TED, the EU public procurement journal",
  "country": "DE",
  "noticeId": "653878-2026",
  "title": "Germany, IT services: consulting, software development, Internet and support, Backup Cloud to Cloud",
  "buyer": "Deutsche Gesetzliche Unfallversicherung e.V.",
  "publishedAt": "2026-09-22T22:00:00.000Z",
  "deadline": "2026-10-22T22:00:00.000Z",
  "daysToDeadline": 30,
  "valueAmount": null,
  "valueCurrency": null,
  "cpv": ["72000000"],
  "noticeType": "cn-standard",
  "procedureType": "open",
  "contractNature": "services",
  "language": "eng",
  "url": "https://ted.europa.eu/en/notice/-/detail/653878-2026",
  "documentsUrl": "https://ted.europa.eu/en/notice/653878-2026/pdf"
}
```

A value of `null` means the source did not publish one. It is never a guess.

### Pricing

| Event | Price |
|---|---|
| Notice returned | $0.004, falling to $0.002 on higher plans |
| Notices removed by a filter, notices unchanged in new-only mode | **free** |

No start fee. A run that returns nothing costs nothing.

### Frequently asked questions

**How far back can I search?** Give `publishedFrom` and `publishedTo`. With no dates at all the run covers the last seven days, which is what a daily or weekly watch needs.

**Why do some notices have no value?** Because the buyer did not publish one, which is common for open procedures in several countries. Award notices carry the real contract value; open notices carry an estimate when the buyer gives one.

**Do you cover contract awards as well as open tenders?** Yes, both. Leave `onlyOpen` off and you get award notices too, which is what you want for market intelligence rather than bidding.

**Which notice types exist?** The EU journal uses codes like `cn-standard` for a contract notice, `can-standard` for an award, `pin-only` for prior information and `qu-sy` for a qualification system. Pass them in `noticeTypes` to narrow the run.

**Is this the same data as the official portals?** Yes, read from the official interfaces at run time. Nothing is cached and nothing is enriched by a third party.

### How to use EU Tenders Scraper

1. Open the actor and fill in `countries` and `cpv` in the input form, or paste the JSON input from the example above.
2. Click **Start**. The first rows appear in the **Output** tab within seconds; the run summary is in the **Storage** tab under the key `SUMMARY`.
3. Download the results as JSON, CSV or Excel from the Output tab, or read them through the API link shown there.
4. To run it on a schedule, click **Save as a task**, set the input once and add a schedule. Scheduled tasks keep their own change snapshot, so the new-only mode works without any extra setup.

### Integrations

The actor is available in the Apify apps for **Make**, **Zapier**, **n8n** and **Keboola**, where you pick it by name and map the input fields. It is also exposed to AI agents through the Apify MCP server, and callable from any language through the Apify API; the API tab on this page has ready-made snippets for Node.js, Python and curl. Every run can post its results to a webhook when it finishes.

### Support

Questions and problems go into the **Issues** tab of this actor. Each issue is answered by the maintainer, and fixes ship as new builds without any change on your side.

Built and operated by deriverge s.r.o. Same rules as our other actors: unified schema, honest billing, no charge for what you did not get.

Every other source we cover is in **Public Tenders Scraper**, the multi-source actor this one is built from.

# Actor input Schema

## `sources` (type: `array`):

This actor covers the European Union journal TED (ted). Leave empty to read all of them. Sources outside this actor are skipped and listed in the run summary; the multi-source actor covers those.

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

Two-letter country codes of the contracting authority, for example DE, FR, PL, NL. Leave empty for every country the sources cover.

## `cpv` (type: `array`):

Common Procurement Vocabulary codes, the official taxonomy of what is being bought. Use the eight-digit code, for example 72000000 for IT services or 45000000 for construction. A division code matches everything inside it.

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

Full text search over the notice. Any of the words is enough to keep a notice. Leave empty to rely on the CPV codes instead.

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

First publication date to include. Leave both dates empty and the run covers the last seven days.

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

Last publication date to include, inclusive.

## `deadlineAfter` (type: `string`):

Keep only notices whose deadline for receipt of tenders falls on or after this date. This is the filter that separates contracts you can still bid for from the archive.

## `onlyOpen` (type: `boolean`):

Drops every notice whose deadline has already passed. Notices removed by this filter are never charged.

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

Keep only notices whose published value is at least this much, in the currency the source publishes. Notices with no published value are kept, because an absent value is not a small one.

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

Restrict the EU journal to certain notice types, for example cn-standard for a contract notice or can-standard for a contract award notice. Leave empty for all of them.

## `language` (type: `string`):

Two-letter code of the language you want the title and description in, for example en, de, fr. The EU journal publishes each notice in the language of the buyer and often in others; the actor picks your language, falls back to English, then to whatever exists, and writes which one it used into every row.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only notices that were not there before or whose deadline or status moved. A tender has a short deadline, so a scheduled watch is worth more than a one-off export.

## `watchKey` (type: `string`):

Name of the snapshot used by the new-only mode, for example "it-services-germany". Runs from a saved task get a snapshot automatically even without a name.

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

Hard cap on returned notices across all sources in the run.

## Actor input object example

```json
{
  "sources": [
    "ted"
  ],
  "countries": [
    "DE",
    "NL"
  ],
  "cpv": [
    "72000000"
  ],
  "onlyOpen": false,
  "language": "en",
  "newOnly": false,
  "maxItems": 1000
}
```

# Actor output Schema

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

One row per notice with the deadline, the value, the buyer, the CPV codes and a link, in one schema across every source.

## `changes` (type: `string`):

Notices that appeared, disappeared or whose deadline or status moved compared with the previous snapshot.

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

Per-source counts, how many notices each filter dropped, and totals.

# 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 = {
    "sources": [
        "ted"
    ],
    "countries": [
        "DE",
        "NL"
    ],
    "cpv": [
        "72000000"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/eu-tenders-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 = {
    "sources": ["ted"],
    "countries": [
        "DE",
        "NL",
    ],
    "cpv": ["72000000"],
}

# Run the Actor and wait for it to finish
run = client.actor("deriverge/eu-tenders-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 '{
  "sources": [
    "ted"
  ],
  "countries": [
    "DE",
    "NL"
  ],
  "cpv": [
    "72000000"
  ]
}' |
apify call deriverge/eu-tenders-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deriverge/eu-tenders-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/uYCQyYuHIJgMgc8Z2/builds/RYAAegiB75fAmgtWg/openapi.json
