# UK Public Tenders Scraper — Contracts Finder & Find a Tender (`publicdata/uk-contracts-finder-find-a-tender`) Actor

Export UK public procurement notices from both official OCDS APIs: Contracts Finder and Find a Tender. Tenders you can bid on with deadlines and values, and award notices with the winning suppliers and amounts. Filter by keyword, CPV, value and date. No API key.

- **URL**: https://apify.com/publicdata/uk-contracts-finder-find-a-tender.md
- **Developed by:** [PublicData](https://apify.com/publicdata) (community)
- **Categories:** Lead generation, Other
- **Stats:** 1 total users, 0 monthly users, 87.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.25 / 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?

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

**UK public contracts you can bid on, with their deadline and value — and contracts already awarded, with the supplier who won and for how much.**

This Actor reads **both** official UK procurement services through their own Open Contracting (OCDS) APIs and returns one flat row per notice:

- **Contracts Finder** — general and below-threshold notices from central government, councils, the NHS and the wider public sector
- **Find a Tender** — above-threshold procurements under the Procurement Act

No API key, no login, no proxies.

### What you get

**The two fields that decide whether you bid**

- **`tenderDeadline`** — when bids close. Measured 2026-08-21 on 315 live tender-stage notices: present on 37 of 37 Contracts Finder and 225 of 278 Find a Tender ones
- `enquiryDeadline` — the cut-off for questions to the buyer. Find a Tender only (186 of those 278); Contracts Finder does not publish it
- **`value`** with `currency` — on 30 of the 37 CF and 202 of the 278 FTS tender-stage notices

**Who is buying**

- `buyerName`, `buyerId`, and **`buyerContact`** — name, email, phone and location where the buyer publishes them

**What is being bought**

- `title`, `description`, **`cpvCode`** and `cpvDescription`, plus `cpvCodes` with every code on the notice — most notices carry one, but Find a Tender puts several on 27% of them (measured 2026-08-21 over 1,290 live FTS notices: 30 with no code, 906 with one, 354 with two or more, one with 154), `status`, `procurementMethod` and the buyer's own `procurementMethodDetails`, `deliveryRegions`

**Who won — on award notices**

- **`suppliers`**: name, identifier, awarded value and an **`isSME`** flag per supplier — on 1,245 of the 1,254 live award notices measured 2026-08-21
- **`awardValue`** and `awardDate` — the amount is on 416 of 426 Contracts Finder awards but only 180 of 828 Find a Tender ones

**Contract timing**

- `contractStart` and **`contractEnd`** — when an incumbent's contract expires and a re-tender is coming, with `contractEndFrom` / `contractEndTo` inputs to filter on it

**Provenance**

- `ocid` (stable across every notice about the same procurement), `noticeId` (unique per notice — one procurement can publish several, e.g. one award notice per lot), `stage`, `source`, `documents`, `noticeUrl`, `sourceApi`

### Who uses this

- **Bid managers** — a daily feed of open tenders filtered by CPV and value, read before competitors notice them.
- **Sales teams** — award notices show which rivals win which buyers, at what price, and whether SMEs get through.
- **Incumbent-watchers** — set `contractEndFrom` and `contractEndTo` to find contracts expiring in 6–12 months and approach the buyer before the re-tender.
- **Analysts and journalists** — spending by buyer, sector and supplier across both services.
- **Developers and AI agents** — one normalised schema over two APIs, callable from code or as an MCP tool.

### Example output

An open tender:

```json
{
  "ocid": "ocds-b5fd17-d887ef5b-824d-4870-93f9-ddeaab82be82",
  "stage": "tender",
  "source": "Contracts Finder",
  "publishedDate": "2026-08-18",
  "title": "BLD-3163 Store 54 Independent Heating Solution - Delivery",
  "buyerName": "KBS Maritime Ltd",
  "cpvCode": "45232141",
  "value": 1000000.0,
  "currency": "GBP",
  "tenderDeadline": "2026-09-15",
  "noticeUrl": "https://www.contractsfinder.service.gov.uk/notice/cf72a436-d6a7-4e7d-b33a-68751ab4c9d0"
}
```

An award, with the winner:

```json
{
  "stage": "award",
  "title": "ICT Managed Service Provider with Hardware Provision",
  "suppliers": [{ "name": "European Electronique Limited", "id": "GB-COH-01704440", "value": 4559570.55, "currency": "GBP", "isSME": true }],
  "awardValue": 4559570.55,
  "awardDate": "2026-08-18"
}
```

### Input

| Field | What it does |
|---|---|
| `services` | `contracts-finder`, `find-a-tender`, or both (default). |
| `stages` | `tender` = open to bid, `award` = winners, plus `planning`, `contract`, `implementation`. Read from the OCDS release tag, filtered here rather than upstream, so an update or amendment counts as its own stage. Find a Tender contract awards are exported as `award`, like Contracts Finder. Measured over 1,762 live releases on 2026-08-14..18: Contracts Finder published only `planning`, `tender` and `award`, while `contract` and `implementation` came from Find a Tender alone and are rare there (12 of 1,290). |
| `query` | Keyword matched against title and description. |
| `cpvCodes` | Classification filter: `45*` construction, `72*` IT, `79*` business services, `85*` health. Matches any CPV code on the notice. |
| `publishedFrom` / `publishedTo` | Date window, both ends inclusive. Default: the last 7 days, today included. |
| `minValue` | Drop notices whose published value is below this amount. Notices with no published value are dropped too — measured 2026-08-21, 809 of 1,761 live rows (46%) carry neither `value` nor `awardValue`: 11 of 471 Contracts Finder (2%) but 798 of 1,290 Find a Tender (62%), so any `minValue` removes most of Find a Tender. |
| `openOnly` | Keep only tenders whose deadline has not passed. |
| `contractEndFrom` / `contractEndTo` | Keep only notices whose contract ends inside this window. Notices with no published contract end are dropped. |
| `maxItems` | Cap on exported (and charged) notices, split evenly across the selected services. `0` = unlimited. It caps rows, not requests — see Pricing. |

Open IT tenders over £100k from the last month:

```json
{ "stages": ["tender"], "cpvCodes": ["72*"], "minValue": 100000, "publishedFrom": "2026-07-21", "openOnly": true }
```

Who won cleaning contracts this month:

```json
{ "stages": ["award"], "query": "cleaning", "publishedFrom": "2026-08-01" }
```

Contracts expiring in the next 6–12 months, so you can approach the buyer before the re-tender:

```json
{ "stages": ["award"], "contractEndFrom": "2027-02-21", "contractEndTo": "2027-08-21" }
```

### Run it on a schedule

Save your filters as a Task, leave the dates empty so each run covers the last 7 days, and schedule it daily. Attach an Apify integration to push results into **Google Sheets**, **Slack**, **e-mail**, a **webhook**, or **Make** and **Zapier**.

Deduplicate on `ocid` + `noticeId` + `stage` — the key the Actor itself uses. `ocid` alone is not enough: it stays constant across every notice about one procurement, so a single OCID routinely carries several distinct notices at the same stage (per-lot awards, or an award later corrected). Measured on 2026-08-21 over 1,761 live notices from both services (2026-08-14..18): 85 `ocid` + `stage` pairs carried 129 rows more than they had pairs, so deduplicating on `ocid` + `stage` alone would have silently thrown 129 real notices away — 7.3% of the run.

### Use it from code or from an AI agent

Start runs and read the dataset over the Apify API or CLI, as JSON, CSV, Excel or XML. The Actor is also exposed as an **MCP tool** via the Apify MCP server, so an agent can answer "which NHS cleaning contracts close next month?" in one call.

### Pricing

Pay per event: a small fee per notice exported. API calls only, no browser and no proxy, so platform usage on top is negligible. Use `maxItems` for a hard ceiling on how many notices you are charged for. It does not bound how many requests the run makes: every filter except the date window is applied to the rows after they arrive, so a selective `query`, `cpvCodes` or `minValue` over a wide window keeps reading pages until it hits the rate limit no matter how low `maxItems` is. Narrow the date window for that, not `maxItems`.

### Where the data comes from

Both endpoints are the UK government's own OCDS APIs: Contracts Finder (`contractsfinder.service.gov.uk`) and Find a Tender (`find-tender.service.gov.uk`). The data is published under the Open Government Licence, which permits commercial reuse with attribution; `sourceApi` and `noticeUrl` on every row point back to the original.

**Honest limits.**

- **Rate limit — the one real constraint.** Both services sit behind a single shared per-IP limiter, and it caps *requests per block*, not requests per minute, so slowing down does not buy you more of them. Measured live on 2026-08-21, each time starting from an unblocked state:

  - at one request per second, 27 requests went through and the 28th returned `Rate limit of 12 exceeded. Please retry after 120 seconds.` (34.5s in);
  - at one request every five seconds — the 12/minute the message names — only 19 went through before the same 429 (108s in);
  - the block cleared after 46s, 61s and 121s on three separate checks;
  - immediately after Contracts Finder returned that 429, the first Find a Tender request returned it too, so the limiter really is shared.

  One request returns up to 100 notices, so a run reads roughly **2,000-2,800 notices** before it is cut off. When that happens the Actor stops cleanly, exports everything it already collected and says so in the run status instead of failing. Split a large backfill into several runs over narrower date windows, spaced a couple of minutes apart.
- **Overlap between the two services.** It is rarer than you would expect: 5 shared titles in 1,761 live notices on 2026-08-14..18. When it does happen `ocid` will not spot it — the two services mint OCIDs from different prefixes (`ocds-b5fd17-` on Contracts Finder, `ocds-h6vhtk-` on Find a Tender), so the same procurement gets two different OCIDs. Every row carries `source`, so match on title and buyer if you need to collapse them.
- **What buyers publish.** Fields the buyer left out are empty rather than guessed. Measured 2026-08-21 over 1,761 live notices (471 Contracts Finder, 1,290 Find a Tender, published 2026-08-14..18): a CPV code on 100% of CF and 98% of FTS notices; a contract start and end on 98% of CF but only 53% of FTS; a tender `value` on 78% of CF and 23% of FTS. The SME flag appears only where the buyer classified the winner.
- **No bid count.** Neither service publishes the OCDS `numberOfTenderers` field — it was absent from all 1,762 of those releases — so this Actor does not return one. Find a Tender does publish bid counts on some award notices, but per lot and under a different OCDS extension (219 of the 1,761, one notice carrying nine lots with 2/2/2/5/2/3/3/4/3 bids), which cannot be collapsed into a single number without double-counting suppliers who bid on several lots.
- **Timing.** Notices appear on their publication day, so this is a daily feed, not real time. Contract documents themselves are linked, not downloaded.

This Actor is independent and not affiliated with the UK government.

### Frequently asked questions

**Why read both Contracts Finder and Find a Tender?**

They cover different thresholds: Contracts Finder carries general and below-threshold notices, Find a Tender the above-threshold procurements. The UK Public Tenders Scraper reads both and marks each row with its `source`.

**Is UK procurement data free to reuse?**

Yes, under the Open Government Licence, which permits commercial reuse with attribution. Each row carries `sourceApi` and `noticeUrl` pointing back to the original notice.

**How do I find contracts coming up for renewal?**

Filter on `contractEnd`. A contract expiring in six to twelve months is a re-tender being scoped now, which is earlier than any tender notice will tell you.

**Do the two services overlap?**

For some procurements, yes. Every row carries `ocid` and `source` so you can deduplicate deliberately rather than discovering duplicates later.

### Related Actors

Same engine, same official-source approach:

- [**AusTender (Australia)**](https://apify.com/publicdata/austender-australian-government-contracts) — federal contracts, winners and expiry dates
- [**EU Tenders (TED)**](https://apify.com/publicdata/ted-tenders-eu-procurement) — European procurement notices and contract awards
- [**Swiss Public Tenders (simap.ch)**](https://apify.com/publicdata/simap-swiss-public-tenders) — tenders and awards with prices, bid counts and weighted criteria
- [**Swiss Commercial Register (SHAB)**](https://apify.com/publicdata/shab-swiss-company-gazette) — new companies, changes, deletions and bankruptcies
- [**France Company Register**](https://apify.com/publicdata/sirene-siren-french-company-search) — SIREN/SIRET, executives, official labels
- [**US Business Registry**](https://apify.com/publicdata/us-business-registry-scraper) — newly registered companies by state
- [**GLEIF LEI**](https://apify.com/publicdata/gleif-lei-scraper) — LEI lookup, lapsed-LEI screening, parent companies

***

#### Italiano

Esporta gli **appalti pubblici britannici** dalle due API ufficiali OCDS (Contracts Finder e Find a Tender): gare aperte con **scadenza e importo**, e aggiudicazioni con **fornitore vincitore e cifra**. Filtri per parola chiave, CPV, valore minimo e data. Il campo di fine contratto permette di individuare le concessioni in scadenza prima della riassegnazione.

#### Deutsch

Exportiert **britische öffentliche Ausschreibungen** aus beiden offiziellen OCDS-APIs: laufende Ausschreibungen mit **Frist und Auftragswert** sowie Zuschläge mit **Gewinner und Betrag**. Filter nach Stichwort, CPV, Mindestwert und Datum; über das Vertragsende erkennen Sie auslaufende Verträge vor der Neuausschreibung.

#### Français

Exporte les **marchés publics britanniques** depuis les deux API officielles OCDS : appels d'offres ouverts avec **date limite et montant**, et attributions avec **titulaire et valeur**. Filtres par mot-clé, CPV, montant minimum et date ; la date de fin de contrat révèle les marchés arrivant à échéance.

# Actor input Schema

## `services` (type: `array`):

Contracts Finder covers general and below-threshold notices; Find a Tender covers above-threshold procurements. Default: both.

## `stages` (type: `array`):

tender = open opportunities you can bid on; award = who won and for how much; planning = early notices. Matched on the OCDS release tag, so updates and amendments count as their own stage (an award update is an award). Find a Tender tags a contract award both award and contract; those notices are exported as award, the same as on Contracts Finder.

## `query` (type: `string`):

Match against title and description, e.g. 'software', 'cleaning', 'consultancy'.

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

Filter by classification: 45\* construction, 72\* IT services, 79\* business services, 85\* health. A notice matches if any of its CPV codes starts with one of these. Notices published without a CPV code are dropped by this filter.

## `publishedFrom` (type: `string`):

Default: 7 days ago. Inclusive, from 00:00.

## `publishedTo` (type: `string`):

Default: today. Inclusive — notices published on this day are kept.

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

Drop notices whose published value is below this amount. Notices published without a value are dropped by this filter too: measured 2026-08-21 over 1,761 live notices, 809 (46%) carry neither a tender value nor an award value — 11 of 471 Contracts Finder (2%) but 798 of 1,290 Find a Tender (62%), so any minimum removes most of Find a Tender. Leave empty for all.

## `openOnly` (type: `boolean`):

Keep only notices whose bidding deadline has not passed.

## `contractEndFrom` (type: `string`):

Keep only notices whose contractEnd is on or after this date. Notices with no published contract end are dropped.

## `contractEndTo` (type: `string`):

Keep only notices whose contractEnd is on or before this date — how you find incumbents whose contract expires in the next 6-12 months.

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

Safety cap on exported notices, and on how many you are charged for (0 = unlimited). Split evenly across the selected services so one does not use up the whole budget. It does not limit how many requests the run makes: keyword, CPV and value filters are applied after the rows arrive, so narrow the date window to keep a run short. Both UK services share one per-IP rate limit, so a wide run is cut off part way; the Actor then stops cleanly and exports what it already has.

## Actor input object example

```json
{
  "services": [
    "contracts-finder",
    "find-a-tender"
  ],
  "stages": [
    "tender"
  ],
  "openOnly": false,
  "maxItems": 300
}
```

# Actor output Schema

## `dataset` (type: `string`):

Tenders and awards from Contracts Finder and Find a Tender. Every exported row is one dataset item.

# 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 = {
    "services": [
        "contracts-finder",
        "find-a-tender"
    ],
    "stages": [
        "tender"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicdata/uk-contracts-finder-find-a-tender").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 = {
    "services": [
        "contracts-finder",
        "find-a-tender",
    ],
    "stages": ["tender"],
}

# Run the Actor and wait for it to finish
run = client.actor("publicdata/uk-contracts-finder-find-a-tender").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 '{
  "services": [
    "contracts-finder",
    "find-a-tender"
  ],
  "stages": [
    "tender"
  ]
}' |
apify call publicdata/uk-contracts-finder-find-a-tender --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicdata/uk-contracts-finder-find-a-tender"
        }
    }
}

```

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/C8faAtef399vHejYP/builds/iI7fl9MFYin3hB2NN/openapi.json
