# EU Tenders Scraper - TED Tenders & Public Procurement API (`atlasdata/eu-tenders-ted-scraper-reliable`) Actor

EU tenders scraper for TED (Tenders Electronic Daily): EU public tenders and contract awards via the official TED API. Filter by keywords, countries, CPV codes, notice type, dates and open deadlines; get buyer, value, CPV, deadline and links. $1 per 1,000 notices.

- **URL**: https://apify.com/atlasdata/eu-tenders-ted-scraper-reliable.md
- **Developed by:** [Christian Machon](https://apify.com/atlasdata) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 tender notices

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 Tenders & Public Procurement API

**TED tenders scraper and EU tenders API: search every EU public tender, contract award and prior information notice published on TED (Tenders Electronic Daily) by keyword, country, CPV code, notice type and date. Clean JSON, one row per notice. $1 per 1,000 notices.**

TED is the official EU journal for public procurement: around 800,000 notices a year from 27 EU countries plus EEA, Switzerland, Ukraine, Moldova, the Western Balkans and EU institutions. This Actor uses the **official TED Search API v3** (api.ted.europa.eu) - no browser, no proxies, no scraping of HTML - so runs are fast (typically 1-4 seconds) and stable.

**Tested before release: 12/12 platform test runs behaved as expected** (10 data runs across 12 countries with keywords, phrases, CPV codes, notice types, open-deadline filter, date windows, 3-page pagination and an advanced expert query; 2 invalid inputs were correctly rejected with a clear error). Charged events matched dataset items on every run.

### Who it's for and use cases

- **Bid teams and sales** - find open calls for tenders in your CPV codes and countries every morning, with the submission deadline and the link to the tender documents.
- **Market intelligence** - see who won which contracts (award notices include winners and total value) and which buyers spend in your sector.
- **Consultants and lead generation** - build lists of public buyers planning purchases (prior information notices) before the tender is out.
- **Researchers and journalists** - analyse procurement by country, CPV sector, procedure type or value.
- **AI agents and automations** - call it from Make, Zapier, n8n, LangChain or Apify's MCP server and get flat JSON back in a few seconds.

### Why this TED tenders scraper?

| | This Actor |
|---|---|
| Source | Official TED Search API v3 of the EU Publications Office - free, open data |
| Filters | Keywords (full text, any language, phrases), buyer countries (ISO 2- or 3-letter), CPV codes (sub-codes included automatically), notice type, published since/until (dates or "7 days"), only tenders still open for bids |
| Notice types | Calls for tenders, contract awards (results), planning / prior information, contract modifications, direct-award pre-notices (VEAT), market consultations |
| Clean output | Title in your language (24 EU languages), original title, description, buyer name/city/website, country, CPV codes, estimated value + currency, total/awarded value, winners, deadline (tenders or requests to participate), publication date, documents and submission links, TED HTML/PDF/XML links |
| Power users | Add any TED expert-query clause (e.g. `procedure-type=open`, `place-of-performance IN (DK01)`) |
| Honest status | `OUTPUT` record with the exact TED query, total matching notices, status (`SUCCEEDED`, `NO_DATA`, `PARTIAL`, `INVALID_QUERY`, `FAILED`) and network stats |
| Polite | Sequential requests, max ~2.5 per second, honest User-Agent, retries with exponential backoff and `Retry-After` |

### How to use it

1. Type **keywords** (optional) - a notice matches any of them.
2. Pick **buyer countries** and/or **CPV codes** (e.g. 72000000 = IT services, 45000000 = construction, 33000000 = medical equipment).
3. Choose a **notice type** and a **published since** date (default: last 30 days). Tick **only tenders still open** to drop expired calls.
4. Set **max notices** (default 50, newest first) and click **Start**. Download JSON, CSV or Excel, or call it via the API.

### Input example

```json
{
  "keywords": [
    "software",
    "cloud hosting"
  ],
  "countries": [
    "DK",
    "SE",
    "DE"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "publishedSince": "30 days",
  "noticeType": "competition",
  "onlyOpen": true,
  "maxItems": 50,
  "language": "eng"
}
```

| Field | Type | Default | Notes |
|---|---|---|---|
| `keywords` | array of strings | - | Full-text, OR-combined; multi-word = phrase |
| `countries` | array of strings | all | Buyer country, ISO alpha-2 or alpha-3 (UK and EL accepted) |
| `cpvCodes` | array of strings | all | 8-digit CPV, check digit optional, or a 2-7 digit prefix; children included |
| `publishedSince` | string | `30 days` | `2026-10-01` or `7 days` / `4 weeks` / `3 months` |
| `publishedUntil` | string | - | Inclusive end date |
| `noticeType` | enum | `any` | `competition`, `result`, `planning`, `contract-modification`, `direct-award-prenotice`, `consultation` |
| `onlyOpen` | boolean | `false` | Deadline (tenders or requests to participate) today or later |
| `maxItems` | integer | `50` | 1-5,000, newest first |
| `language` | enum | `eng` | 3-letter EU language code for titles, buyer names and links |
| `expertQuery` | string | - | Extra TED expert-query clause, ANDed |

### Output example

One item per notice (real run, description shortened):

```json
{
  "noticeId": "751610-2026",
  "title": "Belgium – Networking, Internet and intranet software development services – Raamovereenkomst voor Digitale diensten en software (vervolg Project LB365)",
  "originalTitle": "Raamovereenkomst voor Digitale diensten en software (vervolg Project LB365)",
  "description": "De aanbestedende overheid wenst een raamovereenkomst te sluiten voor het leveren van digitale diensten, ICT-dienstverlening, consultancy, softwaregerelateerde diensten en softwarelicenties ten behoeve van de aanbestedende overheid en de organisaties die gerechtigd zijn om gebruik te maken van deze r...",
  "buyerName": "Gemeente Brasschaat",
  "buyerCity": "Brasschaat",
  "buyerWebsite": "http://www.brasschaat.be/",
  "country": "BE",
  "countryIso3": "BEL",
  "placeOfPerformance": [
    "BE100",
    "BEL"
  ],
  "noticeType": "cn-standard",
  "noticeTypeLabel": "Contract notice",
  "formType": "competition",
  "procedureType": "neg-w-call",
  "contractNature": "services",
  "mainCpv": "72212200",
  "cpvCodes": [
    "72212200"
  ],
  "estimatedValue": null,
  "estimatedValueCurrency": null,
  "totalValue": null,
  "totalValueCurrency": null,
  "winners": null,
  "deadline": null,
  "deadlineDate": null,
  "publicationDate": "2026-10-29",
  "officialLanguages": [
    "NLD"
  ],
  "documentsUrl": "https://cloud.3p.eu/Downloads/1/2908/AA/2026",
  "submissionUrl": "https://www.publicprocurement.be",
  "url": "https://ted.europa.eu/en/notice/-/detail/751610-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/751610-2026/pdf",
  "xmlUrl": "https://ted.europa.eu/en/notice/751610-2026/xml",
  "scrapedAt": "2026-10-29T19:32:47.030Z"
}
```

Award notices additionally carry `winners` and `totalValue` / `totalValueCurrency`. Fields TED does not publish for a notice are `null`. Values are as published by the buyer (estimated values are often missing on calls for tenders).

### Pricing

Pay per event - you only pay for notices you get:

| Event | Price |
|---|---|
| Actor start | $0.00005 per run (256 MB) |
| Tender notice | $0.001 per notice ($1 per 1,000) |

Examples: 25 notices = $0.02505; 100 notices = $0.10005; a search with no matches = $0.00005. Set a maximum charge per run and the Actor stops exactly there.

### FAQ

**Is this legal / can I reuse the data?** Yes. TED data is published by the Publications Office of the European Union as open data and may be reused free of charge, including commercially, under Commission Decision 2011/833/EU, with attribution: "© European Union, https://ted.europa.eu". The Actor only calls the official public API.

**How fresh is it?** TED publishes new notices every working day (Monday-Friday); results are live from the API at run time.

**Which countries?** All countries that publish on TED: EU-27, Norway, Iceland, Liechtenstein, Switzerland, North Macedonia, Serbia, Montenegro, Albania, Moldova, Ukraine, Georgia and others, plus EU institutions.

**Why is the estimated value empty?** Many buyers do not publish an estimate. Award notices usually have `totalValue` (the awarded amount).

**How many notices can I get?** Up to 5,000 per run (newest first). For larger extracts, split by date window or country.

**Does it get the full tender documents?** It returns the links (`documentsUrl`, `submissionUrl`, `pdfUrl`, `xmlUrl`). The documents themselves live on national e-procurement portals.

**Something wrong?** Open an issue on the Actor page - the `OUTPUT` record shows the exact TED query that was run, which makes problems easy to reproduce.

# Actor input Schema

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

Full-text search terms (any language TED indexes). A notice matches if it contains ANY of the keywords; multi-word keywords are searched as phrases. Leave empty to filter only by country/CPV/date.

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

ISO country codes of the buying organisation, 2- or 3-letter (DK, DE, FR, SE or DNK, DEU...). UK and EL are accepted. Empty = all ~30 countries publishing on TED.

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

Common Procurement Vocabulary codes, e.g. 72000000 (IT services), 45000000 (construction works), 33000000 (medical equipment). Sub-codes are included automatically (72000000 also matches 72222300). Check digit (-5) optional.

## `publishedSince` (type: `string`):

A date (2026-10-01) or relative period (7 days, 4 weeks, 3 months). Default: 30 days.

## `publishedUntil` (type: `string`):

Optional end date (inclusive).

## `noticeType` (type: `string`):

Calls for tenders (open competitions), award results, planning (prior information) notices, contract modifications, direct-award pre-notices or market consultations.

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

Keep only notices whose deadline for tenders (or for requests to participate, in restricted/negotiated procedures) is today or later.

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

Newest first. Each notice saved is one charged event.

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

Language for titles, buyer names and TED links where TED has a translation (notice titles exist in all 24 EU languages; descriptions are in the original language).

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

Optional TED expert-search clause ANDed with the filters above, e.g. procedure-type=open or place-of-performance IN (DK01). See docs.ted.europa.eu.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "countries": [
    "DK",
    "SE"
  ],
  "publishedSince": "30 days",
  "noticeType": "any",
  "onlyOpen": false,
  "maxItems": 50,
  "language": "eng"
}
```

# Actor output Schema

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

No description

## `table` (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": [
        "software"
    ],
    "countries": [
        "DK",
        "SE"
    ],
    "publishedSince": "30 days",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("atlasdata/eu-tenders-ted-scraper-reliable").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": ["software"],
    "countries": [
        "DK",
        "SE",
    ],
    "publishedSince": "30 days",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("atlasdata/eu-tenders-ted-scraper-reliable").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": [
    "software"
  ],
  "countries": [
    "DK",
    "SE"
  ],
  "publishedSince": "30 days",
  "maxItems": 50
}' |
apify call atlasdata/eu-tenders-ted-scraper-reliable --silent --output-dataset

```

## MCP server setup

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

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/x4DmJy7EHoo8BlI0d/builds/gKxuefOrNdQFVDdI5/openapi.json
