# UK & EU Public Tenders: Find a Tender & TED (`oldjard/uk-eu-public-tenders`) Actor

UK and EU public tenders from the official Find a Tender, TED and Contracts Finder APIs in one table: buyer, value, CPV, deadline and UK award winners. Filter by keyword, CPV, country and value; schedule it daily with only-new mode for bid alerts. No login. $3 per 1,000 notices.

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

## Pricing

Pay per event

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

## UK & EU Public Tenders: Find a Tender & TED

Get **public sector tenders from the UK and Europe** in one clean table: open opportunities, early (pipeline)
notices and contract awards from **Find a Tender** (the UK's Central Digital Platform), **TED** (Tenders Electronic
Daily, the EU's official journal of public procurement) and, optionally, **Contracts Finder**. Filter by **keyword,
CPV code, buyer country, contract value and deadline**, and **schedule it daily with "only new"** to get a bid alert
list of just the notices published since yesterday.

The data comes straight from the official open APIs. No login, no proxies, no browser, no scraping of web pages, so
there is nothing to block and nothing to break when a website changes.

**Try it in one click:** the input is prefilled with a "software" search over the last 3 days, 50 notices at most
(15 cents). Apify's free plan covers about 1,600 notices a month.

### What you get

One row per notice, with the same fields whatever the source:

| Field | Example |
|---|---|
| `title` | Corporate Power Purchase Agreements |
| `buyer`, `buyerCountry`, `buyerCity` | Kent County Council t/a LASER, GB, West Malling |
| `value`, `currency` | 1500000000, GBP (estimated value; awarded value for awards) |
| `deadline` | 2026-11-09T15:00:00+00:00 (tender or request-to-participate deadline) |
| `publishedDate` | 2026-10-01T11:53:39+01:00 |
| `cpvCodes`, `mainCpvCode`, `mainCpvDescription` | \["09000000", "09300000", ...], 09000000, Petroleum products, fuel, electricity... |
| `locationCodes` | NUTS / ITL codes of the place of performance, e.g. \["UKF25"], \["FRK14"] |
| `procedure`, `contractType` | Open procedure, services |
| `noticeKind`, `noticeType` | tender / planning / award, and the source's own type (tender, tenderUpdate, cn-standard...) |
| `aboveThreshold`, `suitableForSme` | UK notices: above the procurement threshold; buyer says suitable for SMEs |
| `awardedSuppliers` | Award notices from the UK: the winning suppliers |
| `description` | The notice's description (up to 3,000 characters) |
| `url` | The notice on Find a Tender / TED / Contracts Finder |
| `documentsUrl` | Where the tender documents or the submission portal are, when the notice gives one |
| `apiUrl` | The machine-readable notice (OCDS JSON or TED XML) |
| `source`, `noticeId`, `procurementId`, `id` | Find a Tender, 092777-2026, ocds-h6vhtk-06b8f7, fts:ocds-h6vhtk-06b8f7:tender |
| `licence`, `attribution` | The licence of the row's data and the credit line it asks for (see below) |

TED notices keep their original language for the title and description (`titleLanguage` says which, e.g. `fra`);
English is used when the notice has it. `mainCpvDescription` is always in English.

The run also writes an **OUTPUT** record: per-source counts (pages read, notices read, matched, already delivered,
output), whether each source finished, why a run stopped early, and how many notices each filter dropped.

### How to search UK and EU public tenders in 4 steps

1. Add **keywords** (`cleaning`, `cyber security`) and/or **CPV codes** (`72000000` covers all IT services).
2. Pick **buyer countries** (`GB`, `IE`, `DE`...) or leave empty for the UK plus every country on TED.
3. Set the **date range** (default: the last 3 days) and, if you like, a **value range**.
4. Run. For alerts, turn on **Only new since the last run** and schedule the actor daily.

#### Example: UK and Irish cleaning contracts, open now

```json
{
    "keywords": ["cleaning"],
    "countries": ["GB", "IE"],
    "dateFrom": "7 days"
}
```

#### Example: daily alert for IT tenders over £/€100k anywhere

```json
{
    "cpvCodes": ["72000000", "48000000"],
    "minValue": 100000,
    "dateFrom": "3 days",
    "onlyNew": true
}
```

Schedule it once a day. Each run returns only notices it hasn't returned before, and you pay only for those. The
3-day window gives overlap, so a notice published late or a skipped day is still caught.

#### Example: who won what (contract awards) in the Netherlands this month

```json
{
    "countries": ["NL"],
    "noticeKinds": ["award"],
    "dateFrom": "1 month",
    "maxResults": 1000
}
```

A month of Dutch awards on TED is about 550 notices (measured 5 October 2026), so about $1.65. `maxResults` caps the
bill; set it to 0 for no limit.

### Good to know

- **Keywords.** UK notices are matched on title, description and buyer name. TED matches the whole notice text, in
  each notice's own language, so a German notice won't match `cleaning`. Add translations (`Reinigung`,
  `nettoyage`, `limpieza`) to cover more of Europe.
- **Value filters use the notice's own currency** (GBP in the UK, EUR for most TED notices, some in PLN, SEK, CZK...).
  No exchange rates are applied. When you set a value range, notices that don't state a value are left out.
- **Still open only** (on by default) drops opportunities whose deadline has passed. Notices without a deadline stay.
- **"Only new"** remembers up to 60,000 notice IDs per search in a key-value store named `public-tenders-state` in
  your account. Changing the filters starts a new memory, unless you give the search a **saved search name**. A UK
  tender and its later award are separate notices; updates to a tender you already have are not "new".
- **Coverage.** Find a Tender has every UK notice under the Procurement Act 2023 (above and below threshold) and
  above-threshold notices from before it. TED has every EU above-threshold notice plus the EEA and others; since
  2021 it has no UK notices. Contracts Finder is off by default: under the Procurement Act new UK notices go to Find
  a Tender, and on 5 October 2026 Contracts Finder's own search showed no notices at all. Turn it on if you need its
  older below-threshold notices once its search works again.
- **Speed.** TED returns 250 notices per request and is quick. Find a Tender allows each client only about a dozen
  requests a minute, so the actor reads it slowly and waits out its limit when hit (it never fails a run for that).
  Find a Tender publishes ~450 notices a working day at 100 per request: the default 3 days takes about 1–2 minutes,
  10 days about 7 minutes (measured), a month roughly 20–25 minutes. TED-only searches finish in seconds.
- **Maximum results is shared fairly between sources.** Each source gets an equal part, and what one source doesn't
  use goes to the others. With a limit of 100, one UK match and 242 TED matches give Find a Tender 1 + TED 99, not
  TED 100. When a source is cut, the status message says so, e.g. *Reached maxResults (100): Find a Tender 1 (all),
  TED 99 of 242*. Rows past a source's equal part are output when the slower source finishes.
- **Failures are free and isolated.** If one source is down, you still get the other's notices and the OUTPUT record
  says what failed (turn on *Fail the run if a source fails* to fail instead).

### How much does it cost to get public tender data?

**$3 per 1,000 notices** returned, so Apify's $5 monthly free credit covers about 1,600 notices. The default daily alert (3 days, one keyword) is typically 10–100 notices,
3–30 cents.

Pay per notice returned (`tender-found`). Notices filtered out, duplicates, notices already delivered in "only new"
mode, and sources that fail cost nothing. The run stops cleanly at your maximum cost per run.

### More tools from oldjard

- [Tech Stack Detector](https://apify.com/oldjard/tech-stack-detector): what any list of websites is built with.
- [Sitemap URL Extractor](https://apify.com/oldjard/sitemap-url-extractor): every URL on a website, for RAG and SEO.
- [Shopify Products Scraper & Price Monitor](https://apify.com/oldjard/shopify-products-price-monitor): catalogs and price changes from any Shopify store.
- [Workday, Greenhouse, Lever & Ashby Jobs Scraper](https://apify.com/oldjard/ats-career-site-jobs): every open job from company career sites.
- [Bulk Website Screenshot & URL to PDF](https://apify.com/oldjard/screenshot-pdf): screenshots and PDFs of any list of pages.
- [Website Change Monitor](https://apify.com/oldjard/website-change-monitor): a before/after diff by webhook, Slack or Discord when a page changes.
- [AI Web Scraper (your own key)](https://apify.com/oldjard/ai-web-scraper): describe fields in English, get JSON.
- [Company Registry Lookup](https://apify.com/oldjard/company-registry-lookup): UK Companies House, Spain, France, Finland and Norway in one schema.

### FAQ

**Is this the official Find a Tender or TED API?** It reads both official APIs for you and returns one table with
the same fields from each. It is not run by, or affiliated with, the UK Government or the EU Publications Office.

**How do I get daily tender alerts by email or Slack?** Turn on *Only new since the last run*, schedule the actor
daily, and add Apify's Slack or email integration to the schedule. Each run sends only notices it hasn't sent before.

**Does it cover Contracts Finder?** Yes, as an option. It is off by default because new UK notices under the
Procurement Act 2023 are published on Find a Tender.

**Which CPV code should I use?** Use the broad division to catch everything under it: `72000000` IT services,
`48000000` software, `45000000` construction work, `79400000` consulting, `90910000` cleaning, `85000000` health and
social work.

### Use it from an AI agent or the API

- **Minimal input:** `{"countries": ["GB", "IE"], "dateFrom": "7 days", "maxResults": 20}`. Set `maxResults` to cap
  the work and the cost (default 100).
- **Cost:** $0.003 per notice returned. Filtered-out and already-seen notices and failed sources are free. 20
  notices = $0.06.
- **Run time (our runs):** TED-only searches 2–17 s (20 to 1,000 notices). Searches that include Find a Tender (any
  search with `GB` or no country) read it slowly to stay within its rate limit: about 1 minute for 15 matches over 7
  days with a CPV filter, 2–6 minutes for 30, because Find a Tender has no server-side CPV or value filter.
- **Results:** the default dataset, one row per notice; the per-source report is the `OUTPUT` record in the
  key-value store.
- Works over the Apify MCP server (`search-actors`, then `call-actor`).

### Licences and attribution

- **Find a Tender and Contracts Finder:** "All content is available under the Open Government Licence v3.0, except
  where otherwise stated." Credit line: *Contains public sector information licensed under the Open Government
  Licence v3.0.*
- **TED:** the European Union's legal notice for TED says its data "can be freely reused, for commercial or
  non-commercial purposes", with the source acknowledged: *Source: Tenders Electronic Daily (TED), © European Union,
  https://ted.europa.eu*.

Every row carries its own `licence` and `attribution`, and the OUTPUT record lists the credit lines for the run.
This actor is not affiliated with the UK Government, the Cabinet Office or the Publications Office of the EU.

### Privacy

The actor reads only published procurement notices. It does not output the contact points in them (names, emails
and phone numbers of buyer staff).

### Integrations

Send results to Google Sheets, Slack or email with Apify integrations, or pull them from the API in JSON, CSV or
Excel. Pair "only new" with a daily schedule and a Slack or email integration for a no-code bid alert.

# Actor input Schema

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

A notice matches if it contains any of these words or phrases (case and accents ignored). UK notices are matched on title, description and buyer; TED searches the whole notice in every language, so add translations (e.g. "cleaning", "nettoyage", "Reinigung") for wider EU coverage. Leave empty for every notice.

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

Common Procurement Vocabulary codes. A code covers everything under it: 72000000 (IT services) also matches 72212000, 72400000 and so on. With or without the check digit (72000000-8).

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

Two-letter codes of the buyer's country, e.g. GB, IE, DE, FR, NL. GB (or UK) searches Find a Tender; any other country searches TED. Empty = the UK and every country on TED.

## `noticeKinds` (type: `array`):

Which notices to return. Default: open opportunities only.

## `dateFrom` (type: `string`):

First publication date: YYYY-MM-DD, or relative such as "yesterday", "3 days", "2 weeks", "1 month". Default: 3 days ago.

## `dateTo` (type: `string`):

Last publication date (inclusive). Default: today.

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

Estimated contract value (awarded value for awards), in the notice's own currency (GBP for the UK, mostly EUR on TED). Setting a value range leaves out notices that don't state a value.

## `maxValue` (type: `integer`):

Upper limit, same rules as the minimum.

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

Leave out opportunities whose deadline has passed. Notices without a deadline are kept.

## `onlyNew` (type: `boolean`):

Return only notices this search hasn't returned before (and charge only for those). Made for a daily schedule: each run gives you just what's new. The memory is kept per search (same keywords, CPV codes, countries, kinds and values) in a key-value store named public-tenders-state in your account.

## `savedSearchName` (type: `string`):

With "Only new", give the search a name to keep its memory when you change its filters, or to run two copies of one search separately.

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

Official APIs to search. Contracts Finder is off by default: since the Procurement Act 2023 new UK notices are published on Find a Tender, and on 5 October 2026 Contracts Finder's search returned no notices.

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

Stop after this many notices in total (0 = no limit). A run also stops at your maximum cost per run. Default 100 keeps a first run cheap; 0 = no limit.

## `failOnError` (type: `boolean`):

By default a run that gets results from one source succeeds even if another source is down (the run's OUTPUT record says which). Turn on to make the run fail instead.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "cpvCodes": [],
  "countries": [],
  "noticeKinds": [
    "tender"
  ],
  "dateFrom": "3 days",
  "onlyOpen": true,
  "onlyNew": false,
  "sources": [
    "fts",
    "ted"
  ],
  "maxResults": 50,
  "failOnError": false
}
```

# Actor output Schema

## `tenders` (type: `string`):

Dataset, one row per notice: id, source, noticeKind, noticeType, title, description, buyer, buyerCountry, buyerCity, cpvCodes, mainCpvCode, value, currency, publishedDate, deadline, procedure, contractType, suitableForSme, awardedSuppliers, url, documentsUrl, licence, attribution.

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

Run report (JSON): the filters used, and per source the pages read, notices read, matched, already seen and output, whether it is complete, and why it stopped.

# 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"
    ],
    "cpvCodes": [],
    "countries": [],
    "dateFrom": "3 days",
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("oldjard/uk-eu-public-tenders").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"],
    "cpvCodes": [],
    "countries": [],
    "dateFrom": "3 days",
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("oldjard/uk-eu-public-tenders").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"
  ],
  "cpvCodes": [],
  "countries": [],
  "dateFrom": "3 days",
  "maxResults": 50
}' |
apify call oldjard/uk-eu-public-tenders --silent --output-dataset

```

## MCP server setup

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

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/897k5nGJ265PpM5Sw/builds/dI1OgzSeKyoQhzx2J/openapi.json
