# EU Tenders Scraper (TED) - Public Contracts, Winners (`om_kh/eu-tenders-scraper`) Actor

Scrape EU public tenders from TED, the official EU journal: open calls with deadline, value, buyer email and documents, plus awards with winners. Filter by keyword, country, CPV, buyer, procedure, nature, value, date. Optional AI summary with your own key. $1.50 per 1,000 notices.

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

## Pricing

from $0.83 / 1,000 notices

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 (TED) — Public Contracts, Winners

> Scrape **EU public tenders** from **TED (Tenders Electronic Daily)**, the official journal
> of EU procurement: **open calls** with deadline, estimated value, **buyer email**, documents
> and submission links, and **contract awards** with the **winning companies**, their emails
> and the contract value. Filter by keyword, country, CPV code and date. Official API, no key.
> **$1.50 per 1,000 notices, no start fee.**

### Free tier — 20 results free on every run

**The first 20 results of every run are free**, on every run you ever make — not a one-off trial. One guard: the free allowance never covers more than half of a run, so the offer stays sustainable.

### What does this EU tenders scraper do?

It searches every public procurement notice published by the EU and EEA countries (France,
Germany, Italy, Spain, Poland, Netherlands, Ireland, Nordics…) above the EU thresholds —
hundreds of thousands per year — and returns clean rows: one per notice, with titles in
English when available.

### Compared with foxlabs/ted-tenders

Read on the Store on 2026-10-23 (EU TED Tenders Scraper — Public Procurement & RFP Data). Where it does better, this section says so.

- **Built on the site's own data**, not a resold scraper: no second Actor between you and the source.
- **Free results on every run** and a hard cost cap (`maxTotalChargeUsd`).
- **Price:** $1.5 per 1,000 here, $4 there.

### Why use it

1. **Open tenders to bid on:** title, description, deadline, estimated value, buyer contact,
   documents link and **submission link**.
2. **Winners of past contracts:** company names, countries, emails and the awarded value —
   a ready B2B lead list (who sells IT, cleaning, construction… to the public sector).
3. **Precise filters:** keywords in any language, buyer countries, CPV categories (a code
   includes its sub-codes), notice kind, publication dates, "still open" deadlines.
4. **Official source:** the EU's own TED API, stable and complete.
5. **Cheaper than the alternatives** ($0.0015 per notice, no start fee).
6. **Monitoring:** schedule it daily with `publishedAfter` to get each new tender once.

### How to use it in 3 steps

1. Click **Try for free** — keyword "software", France and Germany, open calls are prefilled.
2. Change the keywords, countries, CPV codes or notice kind.
3. Click **Start** and download JSON, CSV or Excel.

### Input

| Field | What it does |
|---|---|
| `keywords` | Words searched in the full notice text (any of them). |
| `countries` | Buyer countries as two-letter codes: `FR`, `DE`, `IT`, `ES`, `PL`, `NL`, `IE`… |
| `cpvCodes` | EU procurement categories: `72000000` = all IT services, `45000000` = construction, `79000000` = business services. |
| `noticeKind` | All, open calls, contract awards (winners), or planned procurements. |
| `onlyOpenDeadlines` | Keep only calls you can still answer. |
| `publishedAfter` / `publishedBefore` | Dates (default: last 30 days). |
| `language` | Preferred language for titles and texts (English by default). |
| `maxNotices` | Newest first, 1 to 15,000. Default 100. |
| `customQuery` | A TED expert query instead of the filters. |
| `buyerName` | Part of the buyer's name. |
| `procedureTypes` | `open`, `restricted`, `neg-w-call`, `neg-wo-call`, `comp-dial`, `innovation`... |
| `contractNatures` | `works`, `services`, `supplies`. |
| `minValue` | Minimum estimated or awarded value, in EUR. |
| `analyzeWithAi` + `anthropicApiKey` | Optional AI reading of each result with your own Anthropic key (summary, deliverables, 0-100 fit score and recommended action; describe your company in `businessProfile`). `aiModel` picks the Claude model, `maxAiRows` caps how many results are read. The model usage is billed by Anthropic to you. |
| `maxTotalChargeUsd` | Optional hard cost cap for the run. |

```json
{
  "cpvCodes": ["72000000"],
  "countries": ["FR", "BE", "LU"],
  "noticeKind": "awarded",
  "publishedAfter": "2026-09-01",
  "maxNotices": 500
}
```

### Output

Real example — a contract award (emails masked here):

A real row from this Actor's latest run on Apify (2026-10-23; long texts are cut and people's names hidden here, your dataset has them in full):

```json
{
  "status": "ok",
  "noticeId": "735326-2026",
  "title": "Germany – IT services: consulting, software development, Internet and support – KI-Prototypenentwicklung",
  "description": "Das Jobcenter Neue Wege Kreis Bergstraße ist Eigenbetrieb des Kreis Bergstraße. Es führt für den Kreis das Förderprojekt KI_Hub Kommunal...",
  "noticeType": "cn-standard",
  "procedureType": "open",
  "contractNature": "services",
  "publicationDate": "2026-10-23",
  "deadline": "2026-11-23",
  "buyerName": "Neue Wege Kreis Bergstraße - Kommunales Jobcenter -",
  "buyerCountry": "DEU",
  "buyerCity": "Heppenheim",
  "buyerEmail": "(hidden here)",
  "buyerWebsite": "https://www.neue-wege.org",
  "estimatedValue": 88235.29,
  "estimatedValueCurrency": "EUR",
  "totalValue": 88235.29,
  "totalValueCurrency": "EUR",
  "cpvCodes": [
    "72000000"
  ],
  "placeOfPerformance": [
    "DE715",
    "DEU"
  ],
  "documentsUrl": "https://www.had.de/NetServer/TenderingProcedureDetails?function=_Details&TenderOID=54321-Tender-1a163043be1-4c0979b5cbac8ea1",
  "submissionUrl": "https://www.had.de",
  "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/735326-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/735326-2026/pdf",
  "query": "(FT~\"software\") AND buyer-country IN (FRA DEU) AND notice-type IN (cn-standard cn-social cn-desg qu-sy subco) AND publication-date>=20260923",
  "totalMatching": 919
}
```

Open calls also carry `deadline`, `documentsUrl` and `submissionUrl`.

### How much does it cost?

| Event | Price |
|---|---|
| Notice | **$0.0015** ($1.50 per 1,000) |
| Start fee | none |

Up to 20 notices of every run are free (at most half of the run). A query TED rejects is
reported and never charged. Paid Apify plans get lower tier prices.

### Use cases

- **Bid teams and consultants** — every new open tender in your sector and countries, daily.
- **B2B sales** — companies that win public contracts in your field, with contacts and values.
- **Market intelligence** — who buys what, for how much, and who wins.
- **Journalism and research** — public spending by buyer, sector and country.

### Use it from code (API)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("om_kh/eu-tenders-scraper").call(run_input={
    "keywords": ["cybersecurity"],
    "noticeKind": "open",
    "onlyOpenDeadlines": True,
})
for t in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(t["deadline"], t["buyerCountry"], t["title"], t["submissionUrl"])
```

```bash
curl -X POST "https://api.apify.com/v2/acts/om_kh~eu-tenders-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["software"], "countries": ["IE"], "maxNotices": 20}'
```

### Integrations and MCP

Schedule it every morning and send new tenders to Slack, Teams, Google Sheets or a CRM with
n8n, Make or Zapier. AI agents can call it through `https://mcp.apify.com` as
`om_kh/eu-tenders-scraper`.

### Tips and limits

- TED covers tenders above the EU thresholds; smaller national-only tenders are on each
  country's own portal.
- Some notices give values per lot only, or none; empty fields mean the buyer did not publish
  them.
- One query returns at most 15,000 notices — narrow by dates or countries for more.

### FAQ

**Do I need a TED account or API key?** No.

**Is it legal?** TED is the EU's open data publication of public procurement. Use contact data
in line with the GDPR and anti-spam rules that apply to you.

### Related Actors

- [Hiring Signals API - Companies Hiring Now by Role](https://apify.com/om_kh/company-hiring-signals) — which of these companies are growing.
- [LinkedIn Company Scraper - Size, Industry, Employee Count](https://apify.com/om_kh/linkedin-company-scraper) — company size of the winners.
- [France Company Registry Scraper - Name, SIREN, Status](https://apify.com/om_kh/france-company-registry-scraper) — legal data of French buyers and winners.

### Your feedback

Did this Actor save you time? A short review on the **Reviews** tab helps other people find it, and every review is read. Something missing or broken? Open an issue on the **Issues** tab: it is answered and fixed fast.

# Actor input Schema

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

Words searched in the full notice text (any language), e.g. software, cleaning, construction. Several keywords = any of them.

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

Two-letter codes of the buying country, e.g. FR, DE, IT, ES, NL, PL, IE. Empty = all EU/EEA.

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

EU procurement categories. A code covers its sub-codes: 72000000 = all IT services, 45000000 = construction, 79000000 = business services.

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

Part of the buyer's name, e.g. Ministère, Bundesamt, Comune di.

## `procedureTypes` (type: `array`):

Keep only these procedures.

## `contractNatures` (type: `array`):

Keep only these kinds of contract.

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

Keep only notices whose estimated or awarded value is at least this amount.

## `noticeKind` (type: `string`):

Open calls for tenders, contract awards (with winners), planned (prior information), or all.

## `onlyOpenDeadlines` (type: `boolean`):

Keep only calls whose submission deadline is today or later.

## `publishedAfter` (type: `string`):

YYYY-MM-DD. Default: last 30 days.

## `publishedBefore` (type: `string`):

YYYY-MM-DD.

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

Preferred language for titles and descriptions when available (otherwise the original language).

## `maxNotices` (type: `integer`):

Newest first, 1 to 15,000. Default 100.

## `customQuery` (type: `string`):

A TED expert query that replaces the filters above, e.g. FT~"cloud" AND buyer-country IN (FRA) AND publication-date>=20260901.

## `analyzeWithAi` (type: `boolean`):

Add an ai object to each notice: plain summary, deliverables, and a 0-100 fit score with a recommended action when you describe your company below. Uses your own Anthropic API key; the model usage is billed by Anthropic to you, not by this Actor.

## `anthropicApiKey` (type: `string`):

Needed only for the AI analysis. Create one at platform.claude.com. It is used for this run only and never stored.

## `aiModel` (type: `string`):

Claude model ID, e.g. claude-opus-5-5 (default), claude-sonnet-5-5 or claude-haiku-4-5 for a lower cost.

## `maxAiRows` (type: `integer`):

The AI reads at most this many results per run (1 to 500), to keep your model bill predictable.

## `businessProfile` (type: `string`):

What your company sells or does, e.g. 'Cloud infrastructure and DevOps consulting for public bodies, 40 people, France and Belgium'. Used to score how well each tender fits.

## `maxTotalChargeUsd` (type: `number`):

Optional hard cost cap for this run.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "countries": [
    "FR",
    "DE"
  ],
  "noticeKind": "open",
  "onlyOpenDeadlines": false,
  "language": "en",
  "maxNotices": 50,
  "analyzeWithAi": false,
  "aiModel": "claude-opus-5-5",
  "maxAiRows": 100
}
```

# Actor output Schema

## `report` (type: `string`):

A visual summary of delivery, charges, and source issues.

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

Tenders in a sortable table. No JSON knowledge required.

## `csv` (type: `string`):

Results ready for spreadsheets, CRMs, and analytics tools.

## `excel` (type: `string`):

Results as an Excel workbook for non-technical teams.

## `runSummary` (type: `string`):

Machine-readable delivery, billing, and source diagnostics.

# 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": [
        "FR",
        "DE"
    ],
    "noticeKind": "open",
    "maxNotices": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("om_kh/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 = {
    "keywords": ["software"],
    "countries": [
        "FR",
        "DE",
    ],
    "noticeKind": "open",
    "maxNotices": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("om_kh/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 '{
  "keywords": [
    "software"
  ],
  "countries": [
    "FR",
    "DE"
  ],
  "noticeKind": "open",
  "maxNotices": 50
}' |
apify call om_kh/eu-tenders-scraper --silent --output-dataset

```

## MCP server setup

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