# EU TED Procurement Notices Scraper (`automation-lab/eu-ted-procurement-notices`) Actor

Search official EU TED procurement notices and export buyers, CPV codes, values, locations, deadlines, award winners, and source links.

- **URL**: https://apify.com/automation-lab/eu-ted-procurement-notices.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 procurement 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## EU TED Procurement Notices Scraper

Search and export official **EU TED procurement notices** for tender monitoring, bid research, and public-spending analysis.

The Actor queries the European Union's public TED Search API and produces one clean dataset row per notice.
It covers publication identity, buyers, CPV classifications, performance locations, deadlines, estimated values, award values, winners, and official source links when those fields are present in TED.

Use it for one-time research or schedule the same filtered run to identify newly published opportunities and awards.
No TED account, API key, browser, or proxy is required.

### What can you do with this Actor?

- Find public procurement opportunities by keyword, country, CPV code, buyer, publication date, or deadline.
- Export notices to JSON, CSV, Excel, XML, RSS, or another Apify dataset integration.
- Track a category such as software, renewable energy, construction, or medical equipment.
- Monitor contracting authorities and recurring buyers.
- Separate tender opportunities from award/result notices.
- Capture named winners and awarded values when TED publishes them.
- Keep official HTML, PDF, and XML links beside every record.
- Use a native TED expert query for advanced source-specific searches.

The Actor does not scrape search-result HTML.
It uses `POST https://api.ted.europa.eu/v3/notices/search`, TED's official anonymous data-reuse endpoint.

### Who is it for?

**Government sales teams** can discover suitable tenders and feed qualified notices into a CRM.

**Bid managers** can schedule country, CPV, buyer, and deadline searches instead of repeating them manually.

**Procurement analysts** can compare buyers, categories, estimated values, awarded values, and named winners.

**Market-intelligence teams** can monitor contract awards and supplier activity in selected countries.

**Data engineers** can obtain a stable normalized row while optionally retaining the selected raw TED fields.

**Researchers and journalists** can trace each row back to official TED HTML, PDF, and XML documents.

### Why use the official Search API route?

The structured route is faster and cheaper than browser automation.
It also avoids brittle selectors and exposes multilingual notice fields directly.

This Actor adds practical automation around that source:

1. safe query generation for common filters;
2. bounded pagination and deduplication by publication number;
3. localized text selection with English fallback;
4. normalized tender and award fields;
5. client-side value and result-type filters;
6. transient retry handling;
7. Apify datasets, schedules, webhooks, API clients, and integrations.

### What data does it extract?

| Field | Meaning |
| --- | --- |
| `publicationNumber` | Official TED publication identifier. |
| `noticeTitle` | Preferred localized notice title, or English/source fallback. |
| `publicationDate` | TED publication date and source timezone. |
| `noticeType` | TED notice-type code when present. |
| `formType` | TED form category, useful for result/award analysis. |
| `procedureType` | Procurement procedure type when present. |
| `contractNature` | Main contract nature, such as works, services, or supplies. |
| `buyerName` | First normalized contracting authority name. |
| `buyerNames` | All buyer names returned for the notice. |
| `buyerCountryCodes` | Buyer-country codes. |
| `cpvCodes` | Common Procurement Vocabulary classifications. |
| `countryCodes` | Place-of-performance country codes. |
| `cities` | Place-of-performance cities when published. |
| `deadlineDate` | First published submission deadline. |
| `deadlineDates` | All returned lot deadlines. |
| `estimatedValues` | Numeric estimated lot values. |
| `estimatedValueCurrencies` | Currencies associated with estimates. |
| `maximumEstimatedValue` | Largest numeric estimate in the notice. |
| `awardTotalValue` | Published total awarded value, if available. |
| `awardCurrency` | Award-value currency. |
| `winnerNames` | Named successful tenderers or winners. |
| `winnerCountryCodes` | Winner-country codes. |
| `isAwardNotice` | Normalized award/result indicator. |
| `tedUrl` | Official TED HTML notice. |
| `pdfUrl` | Official PDF document when available. |
| `xmlUrl` | Official XML document when available. |
| `sourceApiUrl` | Official TED Search API endpoint. |
| `scrapedAt` | UTC extraction timestamp. |
| `rawNotice` | Optional selected raw TED response fields. |

TED notices vary by form and procedure.
Missing source fields are represented by `null` or an empty array; they are not guessed.

### How to run EU TED procurement searches

1. Open the Actor input page.
2. Enter at least one keyword, country, CPV code, buyer, publication date, deadline, or expert query.
3. Choose `all`, `tenders`, or `awards` under **Result type**.
4. Set `maxItems` to the maximum unique notices you need.
5. For selective value or award filters, increase `maxNoticesScanned` if necessary.
6. Click **Start**.
7. Open the default dataset and export or integrate the resulting rows.

A useful first run is:

```json
{
  "keywords": ["renewable energy"],
  "countries": ["DEU"],
  "sortBy": "publication-date-desc",
  "maxItems": 20
}
```

### Input reference

#### Search filters

- `keywords` — full-text phrases combined with OR.
- `countries` — three-letter TED/ISO country codes such as `DEU`, `FRA`, `ESP`, or `PRT`.
- `cpvCodes` — exact eight-digit CPV codes such as `48000000`.
- `buyerName` — contracting authority name text.
- `publicationDateFrom` and `publicationDateTo` — inclusive publication window in `YYYY-MM-DD` format.
- `deadlineDateFrom` and `deadlineDateTo` — inclusive deadline window in `YYYY-MM-DD` format.

#### Value and award filters

- `minimumValue` — keep rows with at least one estimate or award value at or above this number.
- `maximumValue` — keep rows with at least one estimate or award value at or below this number.
- `resultType` — `all`, `tenders`, or `awards`.

Value filters do not convert currencies.
For example, `1000000 EUR` and `1000000 CZK` are both numeric values of 1,000,000 in their source currency.
Filter or convert by the accompanying currency fields downstream when comparing totals.

#### Advanced and limit options

- `expertQuery` — a raw TED expert query that replaces generated search clauses.
- `sortBy` — relevance, newest/oldest publication, or earliest deadline.
- `language` — preferred three-letter TED language code; default `eng`.
- `maxItems` — 1 to 5,000 saved notices.
- `pageSize` — 1 to 100 records requested per source page.
- `maxNoticesScanned` — client-side scan ceiling, up to TED's 15,000 page-number result limit.
- `includeRawNotice` — include selected source fields in `rawNotice`.

Even with `expertQuery`, `resultType`, `minimumValue`, and `maximumValue` remain active post-filters.

### Real output example

This abbreviated record came from a current run against the official API:

```json
{
  "publicationNumber": "610518-2026",
  "noticeTitle": "Portugal – Construction work – Contrato de empreitada de construção do novo edifício administrativo da EDA...",
  "publicationDate": "2026-09-04+02:00",
  "buyerName": "EDA - Electricidade dos Açores, S. A.",
  "buyerCountryCodes": ["PRT"],
  "cpvCodes": ["45000000"],
  "countryCodes": ["PRT"],
  "awardTotalValue": 4821485.33,
  "awardCurrency": "EUR",
  "winnerNames": ["CEATANO & MEDEIROS, SOCIEDADE DE CONSTRUÇÃO E IMOBILIÁRIA LDA.,"],
  "isAwardNotice": true,
  "tedUrl": "https://ted.europa.eu/en/notice/610518-2026/html",
  "pdfUrl": "https://ted.europa.eu/en/notice/610518-2026/pdf"
}
```

The complete dataset row includes all fields listed above.

### Monitor tenders and awards on a schedule

Create an Apify Schedule for daily or weekly monitoring.
Keep the search scope stable and use a rolling publication window or a TED expert query appropriate to your workflow.

For change detection:

1. use `publicationNumber` as the stable notice identity;
2. save the prior run in your database or spreadsheet;
3. compare new publication numbers and changed business fields;
4. route new opportunities to the responsible owner;
5. route result notices to supplier and spending analysis.

The Actor returns snapshots; it does not maintain a hidden cross-run history or send alerts by itself.
Apify Schedules, webhooks, Zapier, Make, Slack, email, or your own pipeline can provide those actions.

### Export and integration patterns

**Spreadsheet review:** export the default dataset as CSV or Excel and filter by buyer, CPV, deadline, or country.

**CRM enrichment:** send new tender rows through a webhook and map `publicationNumber` as an external ID.

**Bid pipeline:** select opportunity notices, reject expired deadlines downstream, and attach `tedUrl` for source review.

**Award intelligence:** run with `resultType: "awards"` and analyze `winnerNames`, `awardTotalValue`, and `awardCurrency`.

**Data warehouse:** ingest JSON rows, preserve arrays, and partition on `publicationDate`.

**Document workflow:** use `pdfUrl` or `xmlUrl` as inputs to a separate document extraction process when notice-level fields are insufficient.

### How much does it cost to export EU TED procurement notices?

Pricing uses one start event plus one `item` event for each unique notice saved.
There is no separate charge for award fields, source links, pagination, or an included raw notice.

The current source configuration declares a **$0.005 start fee** and tiered item pricing.
At the BRONZE rate of **$0.002 per notice**, a run saving 10 notices costs **$0.025**, 100 notices costs **$0.205**, and 1,000 notices costs **$2.005**.
The item rates are FREE $0.0023, BRONZE $0.002, SILVER $0.00156, and GOLD/PLATINUM/DIAMOND $0.0012 per saved notice.

Only saved, accepted notices generate item events.
Rows rejected by value/result-type filters, duplicates, failed requests, and scanned-but-unsaved notices do not generate item charges.
Always check the live pricing tab before a large run because the applicable platform tier is authoritative.

### Use the Actor through the Apify API

Replace `APIFY_TOKEN` with your token.
The Actor ID is `automation-lab/eu-ted-procurement-notices`.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~eu-ted-procurement-notices/runs?token=APIFY_TOKEN&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{"cpvCodes":["48000000"],"publicationDateFrom":"2026-01-01","resultType":"tenders","maxItems":25}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/eu-ted-procurement-notices').call({
  countries: ['PRT'],
  publicationDateFrom: '2026-01-01',
  resultType: 'awards',
  maxItems: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/eu-ted-procurement-notices').call(run_input={
    'keywords': ['medical equipment'],
    'countries': ['FRA'],
    'maxItems': 50,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Apify MCP endpoint to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/eu-ted-procurement-notices"
```

#### Claude Desktop, Cursor, and VS Code

Claude Desktop, Cursor, and VS Code can use this equivalent HTTP MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/eu-ted-procurement-notices"
    }
  }
}
```

Example prompts:

- “Find the 20 newest TED renewable-energy notices for Germany and summarize buyers and deadlines.”
- “Export recent software tenders under CPV 48000000 to a dataset.”
- “Collect Portuguese award notices and group winners by awarded value.”

An agent should still follow the official links before making a bid or compliance decision.

### Reliability, retries, and limits

The Actor retries network errors, HTTP 429, and temporary 5xx responses up to three times with bounded backoff.
Stable invalid-query and other 4xx responses fail immediately so input mistakes are visible.

`maxItems` limits accepted saved rows.
`maxNoticesScanned` limits source rows examined for client-side value and award filtering.
A selective filter can therefore return fewer than `maxItems` even when the broader TED query has more records.

TED page-number search exposes at most 15,000 matches for a query.
Narrow broad searches with publication dates, countries, CPV codes, or expert-query clauses.

The Actor does not download or parse every linked PDF/XML attachment.
Fields absent from TED's search response remain empty rather than being inferred from document prose.

### Troubleshooting

**The run says no search filter was provided.**
Add a keyword, country, CPV code, buyer, publication/deadline date, or `expertQuery`.

**TED returns HTTP 400.**
Check the expert-query syntax, three-letter country codes, eight-digit CPV codes, and date format.
The error log includes a bounded source message.

**An award run returns fewer rows than expected.**
Increase `maxNoticesScanned`, broaden the publication window, or remove another restrictive filter.
Award status is determined from TED form/result fields, winner names, and awarded totals.

**A value looks incomparable.**
Read `estimatedValueCurrencies` or `awardCurrency`.
The Actor preserves source currencies and does not perform foreign-exchange conversion.

**A title is not in the requested language.**
TED may not publish that field in the selected language.
The Actor falls back to English and then another available source value.

### Legality and responsible use

TED is the official EU publication surface for public procurement notices.
This Actor accesses the public anonymous Search API and keeps official source links in each row.

Follow TED reuse conditions, Apify terms, applicable database rights, and local law.
Do not treat a normalized row as legal advice or as a substitute for the complete official notice and procurement documents.
Verify deadlines, eligibility, amendments, values, currencies, and award decisions at `tedUrl` before acting.

Buyer and winner names may identify sole traders or other individuals in some notices.
Process personal data only with an appropriate lawful purpose, minimize retention, and honor applicable rights.

### FAQ

#### Does it require a TED account or API key?

No. The official TED Search API route used here is public and unauthenticated.

#### Does it cover all EU countries?

It searches the source's published scope.
Use TED three-letter country codes, and remember that a buyer country can differ from the contract's place of performance.

#### Can it return both tenders and awards?

Yes. Choose `all`, `tenders`, or `awards`.
Award fields are populated only when TED publishes them.

#### Can it search by contract value?

Yes. `minimumValue` and `maximumValue` filter returned estimated and awarded numeric values without currency conversion.

#### Can I use a native TED expert query?

Yes. `expertQuery` replaces generated search clauses and preserves an existing `SORT BY` expression.

#### Does it monitor changes automatically?

It produces a current run snapshot.
Use an Apify Schedule and compare `publicationNumber` plus relevant fields between runs.

#### Why are some fields null or empty?

Different TED forms publish different data.
The Actor does not invent missing deadlines, values, locations, or winners.

### Related Automation Lab Actors

For procurement research outside this source, consider:

- [Brazil PNCP Procurement Notices Scraper](https://apify.com/automation-lab/brazil-pncp-procurement-notices-scraper) for Brazil's official PNCP notices.
- [EBRD ECEPP Procurement Notices Scraper](https://apify.com/automation-lab/ebrd-ecepp-procurement-notices-scraper) for EBRD electronic procurement opportunities.
- [Spain Public Tenders Scraper](https://apify.com/automation-lab/spain-public-tenders-scraper) for Spain-specific public tender workflows.

Use this Actor when TED is the authoritative source and you need one normalized notice row with official EU links.

# Actor input Schema

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

Full-text phrases such as renewable energy, medical equipment, or cybersecurity. Multiple phrases are matched with OR.

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

ISO alpha-3 country codes used by TED's CY search alias (normally the buyer-country scope), for example DEU, FRA, ESP, or BEL. Performance countries are still exported separately.

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

Exact 8-digit Common Procurement Vocabulary codes, for example 48000000 for software packages and information systems.

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

Filter notices by contracting authority or buyer name.

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

Earliest publication date in YYYY-MM-DD format.

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

Latest publication date in YYYY-MM-DD format.

## `deadlineDateFrom` (type: `string`):

Only include notices whose submission deadline is on or after this YYYY-MM-DD date.

## `deadlineDateTo` (type: `string`):

Only include notices whose submission deadline is on or before this YYYY-MM-DD date.

## `minimumValue` (type: `number`):

Keep notices having an estimated or awarded numeric value at or above this amount. Currency is not converted.

## `maximumValue` (type: `number`):

Keep notices having an estimated or awarded numeric value at or below this amount. Currency is not converted.

## `resultType` (type: `string`):

Return all matching notices, tender opportunities only, or award/result notices only.

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

Optional raw TED expert-search query. It replaces generated keyword, country, CPV, buyer, and date clauses; value and result-type post-filters still apply.

## `sortBy` (type: `string`):

Sort generated queries by relevance, publication date, or deadline. Existing SORT BY in an expert query is preserved.

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

Three-letter TED language code for localized text and links, for example eng, deu, or fra.

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

Maximum unique matching procurement notices to save.

## `pageSize` (type: `integer`):

Number of notices requested from TED per API page.

## `maxNoticesScanned` (type: `integer`):

Safety bound for client-side award and value filtering. Must be at least maxItems and no more than TED's 15000-result page limit.

## `includeRawNotice` (type: `boolean`):

Attach the selected raw API fields for advanced analysis. This increases dataset size.

## Actor input object example

```json
{
  "keywords": [
    "renewable energy"
  ],
  "countries": [
    "DEU"
  ],
  "resultType": "all",
  "sortBy": "publication-date-desc",
  "language": "eng",
  "maxItems": 20,
  "pageSize": 100,
  "maxNoticesScanned": 1000,
  "includeRawNotice": false
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset view containing normalized tender and award notices, buyers, CPV codes, values, winners, and official source links.

# 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": [
        "renewable energy"
    ],
    "countries": [
        "DEU"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/eu-ted-procurement-notices").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": ["renewable energy"],
    "countries": ["DEU"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/eu-ted-procurement-notices").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": [
    "renewable energy"
  ],
  "countries": [
    "DEU"
  ],
  "maxItems": 20
}' |
apify call automation-lab/eu-ted-procurement-notices --silent --output-dataset

```

## MCP server setup

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

```

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/BRbiNlF00BnNEPN9P/builds/g1YGQBoz8VQeZeAeD/openapi.json
