# EU & UK Tenders Scraper & Monitor (TED, Find a Tender) (`folt/eu-tenders-monitor`) Actor

Search and monitor EU and UK public tenders from TED, Find a Tender and Contracts Finder by keyword, CPV code, country and notice type. Daily bid alerts with only new notices, buyer, values, deadlines and award winners in one clean schema. Official APIs.

- **URL**: https://apify.com/folt/eu-tenders-monitor.md
- **Developed by:** [Folt Labs](https://apify.com/folt) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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 & UK Tenders Scraper & Monitor — TED, Find a Tender & Contracts Finder

Search and monitor **public procurement notices** (tenders, prior information notices and contract awards) from **TED — Tenders Electronic Daily**, the official EU journal where every above-threshold public tender in the EU/EEA is published, and — when you switch them on — from the UK government's official portals **Find a Tender** and **Contracts Finder**. Filter by keyword, CPV code, buyer country and notice type, and get **only the notices you haven't received yet** — perfect for daily bid alerts, CRMs and market research.

### Why use it

- 🇪🇺 **All EU/EEA tenders** from the official source (thousands of new notices every week)
- 🇬🇧 **UK tenders too** (opt-in): Find a Tender (Procurement Act 2023 notices, above and below threshold) and Contracts Finder (below-threshold and old-rules notices) — about 2,500 + 750 new notices a week
- 🔎 **Filters that matter:** keywords, CPV codes with sub-categories included, buyer countries, notice type (calls for tenders, prior information, contract awards), only-still-open deadlines
- 🔔 **Monitoring mode:** schedule daily and receive only notices you haven't seen — you pay only for new ones
- 🏆 **Award data:** winners and contract values from result notices
- 🌐 **Titles in your language:** TED translates titles into all EU languages
- 🧹 **One clean schema** for all sources with buyer, values + currency, deadline, CPV, place of performance, document and submission links
- 🛡️ **Privacy by design:** organisation-level data only — contact persons, emails and phone numbers are never collected, and contacts inside texts are redacted

### How to use

1. Pick **sources**: TED (default), and/or *UK — Find a Tender* and *UK — Contracts Finder*.
2. Add **keywords** (e.g. `software`, `"cloud services"`; for TED add translations like `logiciel`, `Software`) and/or **CPV codes** (e.g. `72000000` = all IT services).
3. Optionally pick **buyer countries** (`DE`, `FR`, `GB`…), **notice types**, and **only tenders still open for bids**.
4. For alerts, set **Change detection → Only new notices** and schedule the Actor daily.

#### Input example

```json
{
  "sources": ["ted", "uk-find-a-tender", "uk-contracts-finder"],
  "keywords": ["software", "cloud services", "logiciel"],
  "cpvCodes": ["72000000", "48000000"],
  "buyerCountries": ["DE", "FR", "NL", "GB"],
  "noticeTypes": ["competition"],
  "onlyOpenForBids": true,
  "publishedWithinDays": 7,
  "changeDetection": "new",
  "maxItems": 500
}
```

### Ready-made recipes

Save an input as a **Task**, add a **Schedule** and an **Integration** in Apify Console — no code.

| Goal | Input highlights | Schedule | Send results to |
| --- | --- | --- | --- |
| **Daily bid alerts** | your `keywords` and/or `cpvCodes`, `buyerCountries`, `onlyOpenForBids: true`, `changeDetection: "new"` | daily | email / Slack / CRM (Integrations tab or webhook) |
| **UK bid alerts** | `sources: ["uk-find-a-tender", "uk-contracts-finder"]`, your `keywords` / `cpvCodes`, `onlyOpenForBids: true`, `publishedWithinDays: 2`, `changeDetection: "new"` | daily | email / Slack |
| **EU + UK in one feed** | `sources: ["ted", "uk-find-a-tender", "uk-contracts-finder"]`, CPV codes, `changeDetection: "new"` | daily | Google Sheets / CRM |
| **Competitor & award tracking** — who wins what | `noticeTypes: ["result"]`, your CPV codes, `changeDetection: "new"` | weekly | Google Sheets |
| **Market research export** | CPV codes + countries, `publishedWithinDays: 365`, high `maxItems` (TED; UK scans are bounded, see below) | once | dataset export (CSV/Excel/JSON) |
| **One country's tenders** — e.g. Bulgaria | `buyerCountries: ["BG"]`, `titleLanguage: "bg"`, `onlyOpenForBids: true` | daily | email / Slack |

### Output example

```json
{
  "id": "688760-2026",
  "source": "TED",
  "title": "Germany – Software package and information systems – ITDZ Berlin: OV RV Datenschleuse",
  "formType": "competition",
  "noticeType": "cn-standard",
  "publishedAt": "2026-10-06",
  "deadline": "2026-11-09",
  "requestDeadline": null,
  "buyerName": "IT-Dienstleistungszentrum Berlin (AöR)",
  "buyerCountry": "DE",
  "buyerCountries": ["DE"],
  "buyerCity": "Berlin",
  "cpvCodes": ["48000000", "48732000", "72318000"],
  "procedureType": "open",
  "estimatedValue": { "amount": 723800, "currency": "EUR" },
  "totalValue": { "amount": 723800, "currency": "EUR" },
  "winners": [],
  "documentsUrl": "https://www.meinauftrag.rib.de/public/DetailsByPlatformIdAndTenderId/platformId/2/tenderId/209645",
  "url": "https://ted.europa.eu/en/notice/-/detail/688760-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/688760-2026/pdf",
  "attribution": "Source: TED – Tenders Electronic Daily (ted.europa.eu), © European Union"
}
```

A UK notice has the same fields:

```json
{
  "id": "FTS-094482-2026",
  "source": "UK-FTS",
  "noticeId": "ocds-h6vhtk-05e68e",
  "title": "The Essex Carers Hub",
  "noticeType": "UK4",
  "formType": "competition",
  "publishedAt": "2026-10-06",
  "deadline": "2026-11-10",
  "buyerName": "Essex County Council",
  "buyerCountry": "GB",
  "buyerCity": "Chelmsford",
  "cpvCodes": ["85312300"],
  "contractNature": ["services"],
  "procedureType": "Competitive flexible procedure",
  "placeOfPerformance": ["UKH3"],
  "submissionUrl": "https://open-uk.org/opportunities/overview/public/4b15a94c-42cf-4136-857c-de58c0dd1007",
  "url": "https://www.find-tender.service.gov.uk/Notice/094482-2026",
  "pdfUrl": "https://www.find-tender.service.gov.uk/Notice/094482-2026/PDF",
  "attribution": "Source: Find a Tender service (find-tender.service.gov.uk), © Crown copyright. Contains public sector information licensed under the Open Government Licence v3.0."
}
```

| Field | Notes |
| --- | --- |
| `id` / `source` | TED: publication number, `TED`. Find a Tender: `FTS-<notice id>`, `UK-FTS`. Contracts Finder: `CF-<notice id>`, `UK-CF` (a notice's later versions keep the id; you get the newest) |
| `formType` | `competition` (call for tenders), `planning` (prior information, pipeline, market engagement), `result` (award, contract details). UK: from the notice type UK1–3 / UK4 / UK5–7 or the stage; other UK notice types (e.g. contract changes) have `null` and are returned only when all three types are selected |
| `noticeType` | TED notice type; Find a Tender `UK1`…`UK17` (or the OCDS stage for old-rules notices); Contracts Finder OCDS stage (`tender`, `award`, …) |
| `deadline` | Earliest tender-submission deadline across lots (YYYY-MM-DD) |
| `requestDeadline` | TED restricted and negotiated procedures: deadline to request to participate (YYYY-MM-DD). Always `null` for UK notices |
| `estimatedValue` / `totalValue` | Amount (net of VAT) + currency as published; when only lots carry values, `estimatedValue` is the sum of all lot values. `null` if not published, mixed currencies, or (UK) only a VAT-inclusive value is published |
| `winners` | Company name + country, on result notices (`country` is `null` when the source doesn't say) |
| `placeOfPerformance` | TED: NUTS codes. Find a Tender: NUTS/ITL codes such as `UKH3`. Contracts Finder: region names such as `London` |
| `description` | Only with *Include description*; original language, contacts redacted |

A **SUMMARY** record in the run's key-value store shows the exact TED query used, how many notices matched and were returned per source, how many were skipped as already seen, how many pages of each UK source were scanned, and whether a UK scan stopped early (`truncated`, with the oldest date it reached).

### Pricing

| What | Price |
| --- | --- |
| Each notice returned (any source) | **$0.003** ($3.00 per 1,000) |
| Each run | **$0.002** |
| Platform usage | included — you pay nothing else |

In monitoring mode you pay only for notices you haven't received yet: a daily alert run with 30 new tenders costs about **$0.09**, roughly **$2.70 a month**. When the Actor recognises a notice published on both UK portals, it returns and charges it once. Cap any run with Apify's *maximum cost per run* — the Actor stops cleanly.

#### How UK scans are bounded

TED filters on its server, so the Actor downloads only matching notices. The UK APIs can't filter by keyword or CPV, so the Actor reads the newest UK notices page by page (100 per page) and filters them itself. Find a Tender publishes about 450–500 notices per working day (about 5 pages; a 7-day window is 25–30 pages), Contracts Finder about 150 (all stages; calls for tenders alone are about 40 a week, filtered on their server).

To keep the price per notice flat, each UK source reads **about one working day of notices (Find a Tender 6 pages, Contracts Finder 3 pages) plus 8 more pages for every notice it returns**, at most 5 minutes per source. Broad searches therefore cover the whole window; very narrow searches over long windows may stop early — SUMMARY then shows `truncated: true` and `oldestDateScanned`. A daily alert normally covers the last working day; SUMMARY shows when it didn't.

Both UK portals share a rate limit (bursts of about 25 requests, then about one request every 8–9 seconds; HTTP 429 with a 2-minute wait). The Actor paces its requests, waits when asked as long as the run's budget allows, and otherwise stops that source and says so in SUMMARY — TED and the other source carry on.

### Use cases

- **Bid alerts** for agencies, consultancies, IT and construction firms
- **Sales intelligence:** who is buying what, where, and for how much
- **Competitor tracking:** contract awards and winners by CPV and country
- **Market research & AI pipelines:** clean, structured procurement data

### FAQ

**Which countries are covered?** TED: all EU member states plus EEA and other countries that publish there. UK (opt-in sources): the United Kingdom via Find a Tender and Contracts Finder. National below-threshold tenders of other countries that aren't sent to TED aren't included.

**Which UK source do I need?** *Find a Tender* carries all notices under the Procurement Act 2023 (since 24 February 2025), including below-threshold calls for tenders, plus above-threshold notices still under the old rules. *Contracts Finder* carries below-threshold notices and procurements that started under the old rules. Select both for full UK coverage; a notice recognised on both is returned once (see *What's different for UK notices*).

**How do keywords work for UK notices?** A UK notice matches if its title, description, lot titles/descriptions or buyer name contain one of your keywords or phrases as a whole word, ignoring case. There is no stemming: `software` doesn't match `softwares`, so add the forms you need. TED's search is a full-text search with its own language analysis, so the same keyword can match slightly differently on TED.

**What does "only tenders still open" include?** Notices whose tender deadline is today or later, and (TED) restricted or negotiated procedures whose deadline to *request to participate* (`requestDeadline`) is still ahead.

**Why do keywords miss some notices?** TED notices are written in the buyer's language. Add translations of your keywords, or use CPV codes, which are language-independent.

**How does "Only new notices" work?** The Actor remembers the notice IDs it returned for your search (in a key-value store in your account, `eu-tenders-monitor-state`) and never returns them again. The first run returns everything in the date window. If a run stopped at *Max notices*, the next run continues with the remaining unseen notices in the window (newest first) before you're fully caught up — raise *Max notices* if you want everything at once. Searches with UK sources keep their own memory, so adding a UK source to an existing TED watchlist starts a new one.

**How is *Max notices* shared between sources?** Notices are taken newest first across all selected sources; on the same publication day the sources take turns. So a small *Max notices* gives you the newest notices of every source, not just TED's.

**Can I use TED's expert query syntax?** Yes — put it in *Advanced TED query*; it's combined with the other filters. It applies to TED only.

**What's different for UK notices compared with TED?** No translated titles (UK notices are in English); no `requestDeadline`; keywords match whole words without stemming; *Advanced TED query* doesn't apply; values are net of VAT and `null` when only a VAT-inclusive value is published; place of performance uses ITL/NUTS codes (Find a Tender) or region names (Contracts Finder); UK scans are bounded per run (see *How UK scans are bounded*); notices published on both UK portals are recognised only when the buyer's reference number matches and the titles are similar, so a few may still appear twice.

**Data source & licence.** TED data comes from TED's official public API; © European Union, reuse is authorised provided the source is acknowledged. UK data comes from the official OCDS APIs of Find a Tender and Contracts Finder: *Source: Find a Tender service (find-tender.service.gov.uk) / Contracts Finder (contractsfinder.service.gov.uk), © Crown copyright. Contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).* Every record carries the matching `attribution` field. The licence doesn't cover personal data, which the Actor doesn't collect.

# Changelog

This Actor's version history is a separate document: https://apify.com/folt/eu-tenders-monitor/changelog.md

# Actor input Schema

## `sources` (type: `array`):

Where to search. TED = EU/EEA tenders (default). Find a Tender = UK notices under the Procurement Act 2023 (above and below threshold) and above-threshold notices under the old rules. Contracts Finder = UK below-threshold notices and procurements still under the old rules. UK sources are filtered by the Actor itself: keywords match whole words (no stemming), and a run reads about one working day of UK notices plus 8 pages per notice found, so very narrow searches over long windows may stop early (shown in SUMMARY) — see the README.

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

A notice matches if it contains any of these words or phrases. TED: full-text search across the whole notice in its original language, so add translations (e.g. software, logiciel, Software, oprogramowanie). UK sources: case-insensitive whole word or phrase in the title, description, lots and buyer name (no stemming: add plural forms).

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

Common Procurement Vocabulary codes. Sub-categories are included automatically (72000000 = all IT services). Accepts 72000000, 72000000-5 or a prefix like 722. Works the same for TED and UK sources.

## `buyerCountries` (type: `array`):

ISO country codes of the contracting authority, e.g. DE, FR, BG (2- or 3-letter). If you select UK sources, include GB (UK also works then) or leave this empty — otherwise the UK sources are skipped.

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

Competition = open calls for tenders (default). Planning = prior information / pipeline and market-engagement notices. Result = contract awards with winners and values. UK notices are mapped from their notice type (UK1–3, UK4, UK5–7) or stage; other UK notice types (e.g. contract changes) are returned only when all three types are selected.

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

Only notices published in the last N days (1–365).

## `onlyOpenForBids` (type: `boolean`):

Keep only notices whose tender submission deadline, or deadline to request to participate (TED restricted and negotiated procedures), is today or later. UK sources use the tender deadline only.

## `changeDetection` (type: `string`):

'Only new' returns notices you haven't received in previous runs with the same search and sources. Schedule the Actor daily and pay only for new tenders.

## `stateKey` (type: `string`):

Optional name for the change-detection memory. Leave empty to derive it from the search.

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

Stop after this many notices are returned (1–10,000). Shared by all selected sources: notices are taken newest first across sources, alternating between sources on the same day.

## `titleLanguage` (type: `string`):

TED only: TED publishes notice titles in all EU languages. Other fields stay in the original language. UK notices are in English.

## `includeDescription` (type: `boolean`):

Adds the notice's description (original language; contact emails and phone numbers are redacted).

## `advancedQuery` (type: `string`):

TED only. Optional extra condition in TED expert-search syntax, combined with the filters above using AND. Example: procedure-type=open

## Actor input object example

```json
{
  "sources": [
    "ted"
  ],
  "keywords": [
    "software"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 3,
  "onlyOpenForBids": false,
  "changeDetection": "off",
  "maxItems": 20,
  "titleLanguage": "en",
  "includeDescription": false
}
```

# Actor output Schema

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

Notices from the selected sources (TED, Find a Tender, Contracts Finder) matching the search, or only notices not returned before in monitoring mode.

## `allFields` (type: `string`):

The same records with every field, as JSON.

## `summary` (type: `string`):

Query, per-source counts, pages scanned, scan limits reached and anything that could not be processed.

# 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"
    ],
    "publishedWithinDays": 3,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("folt/eu-tenders-monitor").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"],
    "publishedWithinDays": 3,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("folt/eu-tenders-monitor").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"
  ],
  "publishedWithinDays": 3,
  "maxItems": 20
}' |
apify call folt/eu-tenders-monitor --silent --output-dataset

```

## MCP server setup

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

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/wgYn7WcqzoobrhW3N/builds/Ifsa8S2HuirLWgehw/openapi.json
