# EU Public Tenders Scraper (TED API) (`rod_analytics/ted-tenders`) Actor

Search and export EU public procurement notices from TED (Tenders Electronic Daily) by keyword, CPV code, country, notice type, date, value and buyer. Official TED API, no browser, fast and cheap.

- **URL**: https://apify.com/rod\_analytics/ted-tenders.md
- **Developed by:** [Rod Services](https://apify.com/rod_analytics) (community)
- **Categories:** Lead generation, Business
- **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

### What does EU Public Tenders Scraper (TED API) do?

**EU Public Tenders Scraper** searches **TED (Tenders Electronic Daily)**, the official journal of **EU public procurement**, and exports clean, flat tender data. Filter by **keywords, CPV codes, buyer country, notice type, publication date, contract value, buyer name and language**. Get contract notices, award notices with **winners and awarded values**, and prior information notices from all EU and EEA countries.

It uses the **official TED Search API v3** from the Publications Office of the European Union. No browser, no scraping of HTML, no login. A typical run returns **hundreds of notices in a few seconds** on 256 MB of memory.

Run it on the Apify platform and you get API access, scheduling, webhooks, integrations (Google Sheets, Slack, Make, Zapier, n8n) and monitoring out of the box. Try it now: the prefilled input returns IT tenders from Lithuania, Latvia and Estonia published in the last 30 days.

### Why use this TED tenders scraper?

- **Tender monitoring and bid alerts.** Schedule a daily run for your CPV codes and countries. Send new tenders to Slack, e-mail or your CRM.
- **B2B sales and lead generation.** Find public buyers that are procuring what you sell, with budgets and deadlines.
- **Bid and tender consultants.** Track open procedures for clients across all 27 EU member states from one dataset.
- **Competitor and market research.** Award notices show who won, for how much, and under which procedure. Build win-rate and pricing benchmarks.
- **AI agents and LLM pipelines.** Structured JSON with English titles, CPV codes and direct links is ready for RAG, classification and summarisation. Works as a tool via the Apify MCP server.
- **Cheaper than alternatives.** About **$1 per 1,000 notices**, with no monthly rental. That is a quarter of the $4 per 1,000 charged by the category leader.

### How to scrape EU public tenders from TED

1. Open the Actor and go to the **Input** tab.
2. Pick **CPV codes** (for example `72000000` for IT services) and/or **keywords**.
3. Select **buyer countries** and **notice types** (contract notice, contract award, prior information).
4. Set a date window, for example **Published in the last N days = 7**.
5. Set **Max notices** and click **Start**.
6. Download results as JSON, CSV, Excel or HTML, or read them via the Apify API.

To monitor tenders, save the input as a **Task** and add a **Schedule** (for example every weekday at 07:00) with `publishedWithinDays = 1`.

### Input

All filters are optional and are combined with AND. Leave a filter empty to skip it. At least one filter is required. The default 30-day window alone does not count, so an empty input returns one free help row instead of notices. To get all notices of a period, set `publicationDateFrom`.

| Field                                       | Description                                                                                                       |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `keywords`                                  | Full-text search. Any keyword can match. Phrases like `cloud services` match exactly.                             |
| `cpvCodes`                                  | CPV codes. Parent codes include children, so `72000000` covers all IT services.                                   |
| `countries`                                 | Buyer country, ISO alpha-2 (`LT`) or alpha-3 (`LTU`).                                                             |
| `noticeTypes`                               | `contract-notice`, `contract-award`, `prior-information`, `direct-award`, `contract-modification`, `corrigendum`. |
| `publishedWithinDays`                       | Relative date window. Default 30. Also applies to `expertQuery`. Use 0 to search all dates.                       |
| `publicationDateFrom` / `publicationDateTo` | Absolute dates, YYYY-MM-DD. `From` overrides the relative window.                                                 |
| `minValue` / `maxValue`                     | Total value (estimated or awarded) in the notice currency.                                                        |
| `buyerName`                                 | Phrase inside the contracting authority name.                                                                     |
| `languages`                                 | Original notice language, e.g. `en`, `de`, `lt`.                                                                  |
| `scope`                                     | `ALL`, `ACTIVE` (only active notices) or `LATEST` (latest OJ S edition).                                          |
| `onlyLatestVersions`                        | Skip superseded versions of changed notices.                                                                      |
| `expertQuery`                               | Raw TED expert query, combined with the other filters via AND.                                                    |
| `maxItems`                                  | Maximum notices to save. You pay per saved notice.                                                                |

Example input:

```json
{
    "cpvCodes": ["72000000"],
    "countries": ["LT", "LV", "EE"],
    "noticeTypes": ["contract-notice", "contract-award"],
    "publishedWithinDays": 30,
    "maxItems": 50
}
```

Keyword search with value range. English and German terms, because German notices are indexed in German:

```json
{
    "keywords": ["cybersecurity", "Cybersicherheit", "Informationssicherheit", "security operations center"],
    "countries": ["DE", "AT", "NL"],
    "noticeTypes": ["contract-notice"],
    "minValue": 250000,
    "publishedWithinDays": 14,
    "maxItems": 500
}
```

Advanced expert query (place of performance instead of buyer country, wildcard on a Lithuanian term):

```json
{
    "expertQuery": "place-of-performance IN (LTU) AND FT ~ \"duomenų centr*\" SORT BY publication-date DESC",
    "publishedWithinDays": 90,
    "maxItems": 200
}
```

Build and test expert queries in the [TED Expert Search](https://ted.europa.eu/en/search/expert-search) page. The query the Actor actually sent is saved in the `SUMMARY` record of the key-value store.

### Output

Each notice is one flat record. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "noticeId": "c3c90c26-75a8-4d5f-afdf-dc834f409e82",
    "publicationNumber": "662851-2026",
    "publicationDate": "2026-09-25",
    "noticeType": "Contract award notice",
    "noticeTypeCode": "can-standard",
    "title": "Lithuania – Software support services – Finansų sistemos vystymo paslauga (atviras konkursas)",
    "titleOriginal": "Finansų sistemos vystymo paslauga (atviras konkursas)",
    "buyerName": "Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos (PV)",
    "buyerCountry": "LT",
    "buyerCountries": ["LT"],
    "buyerCity": "Kaunas",
    "cpvCodes": ["72261000"],
    "mainCpv": "72261000",
    "contractNature": "services",
    "estimatedValue": null,
    "currency": "EUR",
    "awardedValue": 78750,
    "awardedCurrency": "EUR",
    "winnerName": "DEVEHO LT UAB",
    "winners": ["DEVEHO LT UAB"],
    "winnerCountries": ["LT"],
    "deadline": null,
    "procedureType": "Open",
    "lots": 1,
    "language": "lt",
    "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/662851-2026",
    "pdfUrl": "https://ted.europa.eu/en/notice/662851-2026/pdf",
    "xmlUrl": "https://ted.europa.eu/en/notice/662851-2026/xml"
}
```

### Data fields

| Field                                      | Meaning                                                                                                   |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| `noticeId`                                 | eForms notice UUID. Publication number for pre-2023 notices.                                              |
| `publicationNumber`                        | TED number, e.g. `662851-2026`. Stable key for deduplication.                                             |
| `publicationDate`                          | Date published in the OJ S.                                                                               |
| `noticeType` / `noticeTypeCode`            | Readable type and raw TED code (`cn-standard`, `can-standard`, `pin-only` and others).                    |
| `title`                                    | English title when the notice has one, otherwise the TED English headline (country, CPV, original title). |
| `titleOriginal`                            | Title in the original language.                                                                           |
| `buyerName`, `buyerCountry`, `buyerCity`   | First contracting authority. Country as ISO alpha-2.                                                      |
| `buyerCountries`                           | All buyer countries. Joint procurements (e.g. EU institutions) list several.                              |
| `cpvCodes`, `mainCpv`                      | All CPV codes and the main one.                                                                           |
| `estimatedValue`, `currency`               | Estimated value of the procedure. Lot values are summed when no total is given.                           |
| `awardedValue`, `awardedCurrency`          | Total awarded value on award notices.                                                                     |
| `winnerName`, `winners`, `winnerCountries` | Winning organisations. Names only, no contact persons.                                                    |
| `deadline`                                 | Earliest tender (or request to participate) deadline.                                                     |
| `procedureType`                            | Open, restricted, negotiated and others.                                                                  |
| `lots`                                     | Number of lots.                                                                                           |
| `language`                                 | Original language, ISO 639-1.                                                                             |
| `noticeUrl`, `pdfUrl`, `xmlUrl`            | TED notice page, PDF and eForms XML.                                                                      |

### How much does it cost to scrape TED tenders?

The Actor uses **pay per event** pricing: **$1.00 per 1,000 notices** ($0.001 per notice), plus a $0.001 start fee per run. There is no rental fee. Compute cost is included.

- 50 notices (prefilled run): about $0.05
- 1,000 notices: about $1.00
- Daily monitoring, 30 new notices per day: about $1 per month

With the Apify free plan ($5 monthly credit) you can export about **5,000 notices a month** for free.

Set **Maximum cost per run** in the run options to cap spend. The Actor saves only as many notices as that budget covers, then stops. The `SUMMARY` record shows the reason in `stopReason`.

### Tips for faster and cheaper runs

- Use **CPV codes** instead of broad keywords. CPV filters are precise and language independent.
- Keywords search the original notice text. Add local-language terms, e.g. `programinė įranga` for Lithuania.
- Avoid short acronyms such as `SOC` or `ERP` as keywords. Full-text search also matches codes inside notices, so they return unrelated tenders. Use full phrases or CPV codes instead.
- A country filter matches a notice when **any** buyer is in that country. Joint procurements led from another country can appear. Check `buyerCountries`.
- Use `publishedWithinDays = 1` in a daily schedule and deduplicate on `publicationNumber`.
- Set `scope = ACTIVE` to skip closed and historic notices.
- Values are in the notice currency. Filter by `currency` after export if you mix EUR and non-EUR countries.
- Up to 250 notices are fetched per API call. 10,000 notices take about 40 calls and under two minutes.

### FAQ, disclaimers and support

#### Is it legal to scrape TED?

Yes. This Actor uses the official, public TED Search API, which is provided for data reuse. The TED legal notice states that procurement notices published in the Supplement to the Official Journal of the EU **can be freely reused for commercial or non-commercial purposes**, under the Commission reuse policy (Commission Decision 2011/833/EU). The editorial content of the TED websites is licensed under **CC BY 4.0**.

**Attribution:** Source: TED (Tenders Electronic Daily), © European Union, https://ted.europa.eu. Data normalised by this Actor. Keep this credit when you republish the data, and indicate your own changes.

#### Does it collect personal data?

The Actor exports organisation names, not contact persons, e-mails or phone numbers. Some winners can be sole traders whose business name is a personal name. Handle such records under GDPR if you process them further.

#### Which notices are covered?

All notices on TED since 1993, including eForms notices (from late 2023) and older TED-schema notices. Older notices have fewer structured fields, so values such as `lots` or `winnerName` can be empty.

#### Why is a value empty?

Buyers do not always publish estimated values, and many award notices hide values for confidentiality. Some buyers enter 0 as a placeholder; the Actor exports that as empty. The Actor never guesses values.

#### What happens if my input is invalid?

The run still ends **SUCCEEDED** and you pay only the small start fee. No notice is charged. The dataset gets one help row instead of notices:

```json
{
    "error": true,
    "errorCode": "EMPTY_INPUT",
    "message": "No search filter given.",
    "howToFix": "Add at least one filter: ..."
}
```

The same text is shown as the run status message. Codes: `EMPTY_INPUT` (no filter; `publishedWithinDays` alone does not count), `INVALID_INPUT` (a wrong CPV, country, language, notice type, date or value), `QUERY_REJECTED` (TED rejected the expert query) and `NO_RESULTS` (the search ran but matched nothing). Fix the input as `howToFix` says and run again. Network or TED server outages still fail the run, so you can tell them apart.

#### Rate limits

TED does not publish an exact quota and returns HTTP 429 when called too fast. The Actor makes one call at a time, at most 30 per minute, and retries with exponential backoff.

#### Support

Found a bug or need a field? Open an issue in the **Issues** tab. Custom solutions, such as daily tender feeds into your CRM or national procurement portals, are available on request.

This Actor is not affiliated with or endorsed by the Publications Office of the European Union.

# Actor input Schema

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

Full-text search in notices. Any keyword may match (OR). Phrases are matched exactly, e.g. "cloud services". Notices are indexed in their original language, so add local-language terms for better recall. Avoid short acronyms such as SOC: they also match codes inside notices and return unrelated tenders.

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

Common Procurement Vocabulary codes (8 digits). Parent codes include all child codes, e.g. 72000000 covers all IT services. The check digit (72000000-5) is optional.

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

Country of the contracting authority. ISO 3166 alpha-2 codes. Alpha-3 codes (LTU) also work via API. Joint procurements match when any buyer is in these countries, so the first buyer (buyerCountry) can be elsewhere; see buyerCountries.

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

Leave empty for all notice types.

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

Relative date filter. Also applied to the expert query. Ignored when 'Published from' is set. Use 0 to search all dates.

## `publicationDateFrom` (type: `string`):

Publication date from (YYYY-MM-DD). Overrides 'last N days'.

## `publicationDateTo` (type: `string`):

Publication date to (YYYY-MM-DD), inclusive.

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

Minimum total value (estimated or awarded) in the notice currency. Values are not converted between currencies.

## `maxValue` (type: `integer`):

Maximum total value in the notice currency.

## `buyerName` (type: `string`):

Contracting authority name, matched as a phrase. Buyer names are usually in the local language, e.g. "Vilniaus".

## `languages` (type: `array`):

Only notices whose original (official) language is one of these.

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

Maximum number of notices to save. You are charged per saved notice.

## `scope` (type: `string`):

ALL = every notice since 1993. ACTIVE = only active notices (open procedures). LATEST = only the latest daily OJ S edition.

## `onlyLatestVersions` (type: `boolean`):

Skip older versions of notices that were changed later.

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

Raw TED expert search query, e.g. place-of-performance IN (LTU) AND FT ~ "cyber". It is combined with the filters above using AND. You may end it with SORT BY <field> ASC|DESC. Build and test queries at https://ted.europa.eu/en/search/expert-search

## Actor input object example

```json
{
  "keywords": [],
  "cpvCodes": [
    "72000000"
  ],
  "countries": [
    "LT",
    "LV",
    "EE"
  ],
  "noticeTypes": [
    "contract-notice",
    "contract-award"
  ],
  "publishedWithinDays": 30,
  "maxItems": 50,
  "scope": "ALL",
  "onlyLatestVersions": false
}
```

# Actor output Schema

## `notices` (type: `string`):

All saved notices

## `awards` (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 = {
    "keywords": [],
    "cpvCodes": [
        "72000000"
    ],
    "countries": [
        "LT",
        "LV",
        "EE"
    ],
    "noticeTypes": [
        "contract-notice",
        "contract-award"
    ],
    "publishedWithinDays": 30,
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("rod_analytics/ted-tenders").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 = {
    "keywords": [],
    "cpvCodes": ["72000000"],
    "countries": [
        "LT",
        "LV",
        "EE",
    ],
    "noticeTypes": [
        "contract-notice",
        "contract-award",
    ],
    "publishedWithinDays": 30,
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("rod_analytics/ted-tenders").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 '{
  "keywords": [],
  "cpvCodes": [
    "72000000"
  ],
  "countries": [
    "LT",
    "LV",
    "EE"
  ],
  "noticeTypes": [
    "contract-notice",
    "contract-award"
  ],
  "publishedWithinDays": 30,
  "maxItems": 50
}' |
apify call rod_analytics/ted-tenders --silent --output-dataset

```

## MCP server setup

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

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/HoLowJZjqp6B31otL/builds/q3svzdtYbasjEs4NJ/openapi.json
