# EU Procurement Award Radar — Who Won Which Tender (`studio-amba/eu-procurement-award-radar`) Actor

Track who wins EU public tenders. Aggregates AWARD notices (not open calls) from TED across all EU/EEA states, normalizes buyer, winner, award value and CPV code into one schema, and registry-enriches the winner (registration number, status) where available.

- **URL**: https://apify.com/studio-amba/eu-procurement-award-radar.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (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 $20.00 / 1,000 award leads

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/platform/actors/running/actors-in-store#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 Procurement Award Radar — Who Won Which Tender

Most procurement scrapers show you open calls — tenders you could still bid on. This one shows you the opposite: **who already won**. Give it a country, a sector (CPV code or keyword), and a lookback window, and it returns real AWARD notices from TED (Tenders Electronic Daily) — buyer, winner, award value, currency, CPV code — and, where the winner's country has a matching registry in our fleet, its official registration number and status.

This is a lead-generation feed, not a bidding tool. If you sell to companies that just won public contracts (subcontractors, insurers, financiers, competitors doing market intelligence), this is the list of who just got the money.

### What it does

- **Only award notices, never open calls.** The actor queries TED for eForms notice types `can-standard` and `can-social` — genuine "Contract Award Notice" documents — not `cn-standard` (open call for tenders) or `pin-standard` (prior information). A tender that's still open never shows up here.
- **Real winner identity, not a buyer-only feed.** TED's search API exposes `winner-name`, `winner-country`, `winner-city`, and `winner-decision-date` fields for award notices, but none of our five existing procurement scraper actors (TED, Belgian, Dutch, Norwegian, EU Funding & Tenders) request or output them — verified by reading their source before building this. This actor queries TED directly for the fields that actually carry the winner's name.
- **Registry-enriched where cheap.** For each award lead, the actor optionally calls our own `eu-dealer-counterparty-check` meta-actor with the winner's name and country, and attaches the winner's official registration number, registry status (active/dissolved/insolvent/unknown), and match confidence. Covers winners in DE, FR, GB, PL, IT, ES, CH, NO, SE, CZ, NL — the countries our registry fleet supports.
- **Pan-EU/EEA coverage from one source.** TED covers every EU/EEA member state plus the UK for above-threshold public contracts, so this actor doesn't need a separate scraper per country.
- **Multi-lot notices handled honestly.** When a notice has more than one winner (common for framework agreements split into lots), the first winner becomes `winner` and the rest land in `additionalWinners` — nothing is silently dropped, nothing is faked into a false 1:1 alignment TED's own flat API doesn't actually guarantee.

### How to scrape EU procurement award data

1. Leave every filter empty to get the broadest feed: all EU/EEA + UK award notices published in the last 21 days, most recent first.
2. Narrow by **countries** (buyer's country — the contracting authority, not the winner) to focus on one or a few markets.
3. Narrow by **CPV code** (e.g. `72000000` for IT services, `45000000` for construction) to focus on a sector, or by **searchQuery** for a free-text keyword match on the notice title/description.
4. Set **daysBack** — TED publishes thousands of award notices a week across the EU, so 14–21 days is usually plenty of volume even for a narrow filter.
5. Leave **enrichWinners** on (default) to get the winner's registration number and status where available. Turn it off for a faster, cheaper run if you only need the raw TED data.
6. Run it. Each row is one award lead: who won, from whom, for how much, and (where enriched) their registry status.

### Input options

| Field | Type | Description |
|---|---|---|
| `searchQuery` | string | Free-text filter on notice title/description. Empty = all sectors. |
| `countries` | array | Buyer (contracting authority) country filter, ISO2 codes. Empty = all EU/EEA + UK. |
| `cpvCode` | string | CPV sector code filter, e.g. `72000000`. Empty = all sectors. |
| `daysBack` | integer | Award-notice publication lookback window. Default `21`. |
| `maxResults` | integer | Max award leads to return. Default `20`. |
| `enrichWinners` | boolean | Registry-enrich each winner via `eu-dealer-counterparty-check`. Default `true`. |
| `maxEnrichments` | integer | Cap on how many winners get enriched per run (bounds cost/runtime). Default `3`. |
| `timeoutPerEnrichmentSecs` | integer | Timeout per registry-enrichment call. Default `60`. |
| `proxyConfiguration` | proxy | Only needed as a fallback — TED's v3 API is a public, open endpoint queried directly by default. |

### Output fields

| Field | Example | Description |
|---|---|---|
| `noticeId` | `"503731-2026"` | TED publication number |
| `tenderTitle` | `"Italy – Business and management consultancy services – ..."` | |
| `buyer` | `"Giunta Regionale"` | Contracting authority |
| `country` | `"IT"` | Buyer's country (ISO2) |
| `winner` | `"KPMG Advisory S.p.A."` | Primary winning company |
| `additionalWinners` | `["BAGGER BS s.r.o."]` | Other winners on the same notice (multi-lot awards), if any |
| `winnerCountry` | `"IT"` | Winner's country, where TED reports it |
| `winnerCity` | `"Milano"` | |
| `winnerRegId` | `null` or a registry number | From registry enrichment, when available |
| `winnerRegStatus` | `"active"` | From registry enrichment |
| `winnerConfidence` | `"medium"` | Registry match confidence — see `eu-dealer-counterparty-check` for the scale |
| `awardValue` | `1328850` | |
| `currency` | `"EUR"` | |
| `awardDate` | `"2026-07-16"` | Winner decision date, or notice publication date as fallback |
| `cpvCode` | `"79410000"` | Primary CPV code |
| `cpvCodes` | `["79410000"]` | Full CPV code list on the notice |
| `url` | `"https://ted.europa.eu/en/notice/-/detail/503731-2026"` | |
| `source` | `"TED"` | |
| `scrapedAt` | ISO timestamp | |

### Example output

```json
{
  "recordType": "award_lead",
  "noticeId": "503731-2026",
  "tenderTitle": "Italy – Business and management consultancy services – Servizio di assistenza professionale per attività concernenti il piano di sviluppo strategico della Zona Logistica Semplificata della Regione Lazio",
  "buyer": "Giunta Regionale",
  "country": "IT",
  "winner": "KPMG Advisory S.p.A.",
  "additionalWinners": [],
  "winnerCountry": "IT",
  "winnerCity": "Milano",
  "winnerRegId": null,
  "winnerRegStatus": "active",
  "winnerConfidence": "medium",
  "awardValue": 1328850,
  "currency": "EUR",
  "awardDate": "2026-07-16",
  "cpvCode": "79410000",
  "cpvCodes": ["79410000"],
  "url": "https://ted.europa.eu/en/notice/-/detail/503731-2026",
  "source": "TED",
  "scrapedAt": "2026-07-21T13:15:49.330Z"
}
```

### Cost estimate

Priced at $0.02 per award lead (pay-per-event, plus a small actor-start fee). Registry enrichment is included in that price where it succeeds — there is no separate enrichment charge.

### Zero results is sometimes correct

If your filter (a rare country + narrow CPV + a keyword) genuinely matches zero award notices in the lookback window, the actor does not fail. It pushes a single `run_status` row documenting the filter and the fact that TED was reachable and scanned successfully. A run only fails when TED itself couldn't be reached — that's the real "something is broken" signal, not a narrow query returning nothing.

### Limitations

- **Winner identity depends on what TED itself received from the buyer.** A small share of award notices are published without a machine-readable winner name (direct-award justifications, redacted notices) — those are skipped, they never appear as a lead. Roughly a handful in every hundred scanned, based on live testing.
- **Registry enrichment only covers 11 countries** (DE, FR, GB, PL, IT, ES, CH, NO, SE, CZ, NL) — the same set `eu-dealer-counterparty-check` supports. Winners elsewhere (e.g. Croatia, Poland's neighbors outside that list) come back with `winnerRegId: null`.
- **Multi-lot notices are not perfectly lot-aligned.** TED's search API returns winner-name/winner-country/winner-city as flat arrays per notice, not grouped per lot — when a notice has multiple winners, only the first is guaranteed correctly paired with its country/city; the rest are listed in `additionalWinners` by name only. Getting exact lot-level pairing would require parsing each notice's full XML, out of scope for this feed.
- **Award value can be missing** for notices where TED's `result-value-notice` field wasn't published (falls back to `total-value`, the pre-award estimate, when available — otherwise `null`).
- **This actor calls a child actor** (`eu-dealer-counterparty-check`) for enrichment — a Store account restriction on that actor would degrade enrichment coverage but never breaks the core award feed, which is 100% TED-direct.

### Related scrapers

`ted-eu-procurement-scraper` (open calls + general notices, all EU/EEA), `belgian-procurement-scraper`, `doffin-scraper` (Norway), `tenderned-scraper` (Netherlands), `eu-funding-tenders-scraper` (EU grants + tenders portal), `eu-dealer-counterparty-check` (the registry enrichment engine behind this actor's `winnerRegId`/`winnerRegStatus`), `eu-fresh-company-radar` (newly registered EU companies).

# Actor input Schema

## `searchQuery` (type: `string`):

Free-text filter on the notice title/description (e.g. 'software', 'construction', 'catering'). Leave empty to get all recent award notices unfiltered — the broadest and safest default.

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

Only return awards where the CONTRACTING AUTHORITY (buyer) is in one of these countries. Leave empty for all EU/EEA + UK member states.

## `cpvCode` (type: `string`):

Restrict to one CPV (Common Procurement Vocabulary) code, e.g. 72000000 for IT services or 45000000 for construction. Leave empty for all sectors.

## `daysBack` (type: `integer`):

How many days of award-notice publication history to scan. TED publishes thousands of award notices per week across the EU, so 14-21 days is usually plenty.

## `maxResults` (type: `integer`):

Maximum number of award leads (one per notice with an identified winner) to return.

## `enrichWinners` (type: `boolean`):

For each award lead, call our EU Dealer Counterparty Check actor to look up the winning company's registration number and status in its national registry. Supported winner countries: DE, FR, GB, PL, IT, ES, CH, NO, SE, CZ, NL. Adds one extra child-actor call per enriched lead.

## `maxEnrichments` (type: `integer`):

Caps how many winners get a registry lookup in one run (bounds runtime and child-actor cost). Leads beyond this cap are still returned, just without winnerRegId/winnerRegStatus.

## `timeoutPerEnrichmentSecs` (type: `integer`):

How long to wait for each registry-enrichment child-actor call before giving up on that winner.

## `proxyConfiguration` (type: `object`):

TED's v3 search API is a public, open data endpoint that does not block direct traffic, so this actor queries it directly without a proxy by default. This is only used as a fallback if TED's direct API becomes unreachable from Apify's infrastructure.

## Actor input object example

```json
{
  "countries": [],
  "daysBack": 21,
  "maxResults": 20,
  "enrichWinners": true,
  "maxEnrichments": 3,
  "timeoutPerEnrichmentSecs": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "searchQuery": "",
    "daysBack": 21,
    "maxResults": 20,
    "maxEnrichments": 3,
    "timeoutPerEnrichmentSecs": 60,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/eu-procurement-award-radar").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 = {
    "searchQuery": "",
    "daysBack": 21,
    "maxResults": 20,
    "maxEnrichments": 3,
    "timeoutPerEnrichmentSecs": 60,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/eu-procurement-award-radar").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQuery": "",
  "daysBack": 21,
  "maxResults": 20,
  "maxEnrichments": 3,
  "timeoutPerEnrichmentSecs": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/eu-procurement-award-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=studio-amba/eu-procurement-award-radar",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/11bIYfSQhKjV5wc9J/builds/rTEKaIEAwzvaFvNMb/openapi.json
