# UK Public Tenders Feed: Find a Tender + Contracts Finder (`opendata-tools/uk-tenders-feed`) Actor

UK public-sector tenders, pipeline notices and contract awards from the official Find a Tender and Contracts Finder OCDS APIs, flattened and de-duplicated. Filter by keyword, CPV prefix, GBP value, postcode, NUTS/ITL region, deadline and SME flag. No API key.

- **URL**: https://apify.com/opendata-tools/uk-tenders-feed.md
- **Developed by:** [Open Data Tools](https://apify.com/opendata-tools) (community)
- **Categories:** Lead generation, Automation
- **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 results

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?

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 Public Tenders Feed

This tool finds UK public sector contract opportunities and contract awards and gives them to you as one filterable list. It reads the two official UK notice sites, Find a Tender (higher-value notices, all UK) and Contracts Finder (lower-value notices, England), and removes duplicates between them. You get upcoming (pipeline) notices, open tenders and awards, each with a link to the official notice, and no API key or login is needed.

#### Who it's for

- Suppliers and small businesses looking for public contracts they can bid for.
- Bid writers and consultancies that run a daily tender search for their clients.
- Sales teams that want early notice of planned purchases through pipeline notices.
- Analysts who track who won which contracts, the award values and the suppliers.

#### Why use it

- **Two official sources in one list**: notices from Find a Tender and Contracts Finder are combined and de-duplicated.
- **Every stage**: planned (pipeline) notices, open tenders and contract awards, or just the stages you choose.
- **Only open opportunities if you want**: one setting keeps only tenders whose deadline is still in the future.
- **Filter the way you search**: by keywords, contract value in GBP, buyer or delivery postcode, region, and CPV codes (Common Procurement Vocabulary, the standard codes that describe what is being bought, such as `72` for IT services).
- **Small business friendly**: show only notices the buyer marked as suitable for SMEs (small and medium-sized enterprises).
- **Official data, no account needed**: it uses the sites' public OCDS feeds (Open Contracting Data Standard, a common format for publishing contract data). No API key or login is needed.
- **Built for daily alerts**: runs are short and can be scheduled daily, and notices removed by filters or de-duplication are not charged.

#### How to use it

1. Open the Actor in Apify Console and enter **Keywords** that describe the work you do, such as `software`, `IT` or `digital`. Add **Exclude keywords** to drop notices you never want.
2. Choose the **Notice stages** you want, and tick **Only tenders still open** if you only want opportunities you can still bid for.
3. Optionally narrow the results with **Minimum value (GBP)**, **Postcode prefixes** (for example `M` or `LS1`), **NUTS/ITL region codes** (standard UK region codes, for example `UKD` or `UKI`), **CPV code prefixes** or **SME-suitable only**. **Days back** sets how far back to look (7 days by default, up to 90).
4. Click **Start**. Open the **Output** tab to see the notices, newest first, each with a `noticeUrl` link to the official notice. Export them as JSON, CSV or Excel.
5. To get a daily tender alert, create a schedule under **Schedules** that runs once a day. Notices are de-duplicated within a run but not remembered between runs, so a short **Days back** (such as 1) keeps repeats down.
6. To send results somewhere, add an integration such as Google Sheets, Slack, Zapier or Make, or a webhook that fires when the run finishes.

#### Pricing

You pay for each notice saved to your results: $0.004 on the Apify Free plan, $0.0035 on Bronze and $0.003 on Silver and above. Each run also has a tiny Apify start fee of $0.00005. Notices removed by your filters or by de-duplication are not charged.

Example: a daily run that returns 50 notices costs about $0.20 on the Free plan, or $0.15 on Silver. Over 30 days that is about $6.00 on Free, or $4.50 on Silver.

### API and reference

This section is for developers and AI agents. It lists every input and output field, a sample record and code examples.

#### Summary

Queries the official OCDS APIs of Find a Tender (higher-value notices, all UK) and Contracts Finder (lower-value notices, England), flattens each release into one record, applies your filters, and de-duplicates across both sources. Output covers pipeline (planning) notices, open tenders and contract awards. No API key or login is needed. Runs are short and can be scheduled daily as a tender alert feed.

#### Input

All fields are optional.

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string\[] | `[]` | Whole-word match in `title`, `description` or `cpvDescription`. Case-insensitive, except all-caps terms of up to 5 characters (`IT`, `NHS`, `HR`), which match case-sensitively. |
| `keywordMode` | `any`, `all` | `any` | Whether any or all keywords must match. |
| `excludeKeywords` | string\[] | `[]` | Drop notices whose `title` or `description` contains any of these (same matching rules). |
| `daysBack` | integer | `7` | 1 to 90. Window queried: by update date on Find a Tender, by publication date on Contracts Finder. |
| `sources` | string\[] | both | `find_a_tender`, `contracts_finder`. |
| `stages` | string\[] | all | `pipeline`, `tender`, `award`, `other`. |
| `openOnly` | boolean | `false` | Keep only `tender`-stage notices with a deadline in the future. |
| `cpvPrefixes` | string\[] | `[]` | CPV code prefix match, e.g. `72` (IT services), `4521` (building works). |
| `minValue` / `maxValue` | integer | none | GBP. Uses `valueGBP`, falling back to `awardValueGBP`. Notices with no value are excluded when either is set. |
| `postcodePrefixes` | string\[] | `[]` | Prefix match on buyer or delivery postcodes, e.g. `M`, `LS1`, `SW1A`. |
| `nutsRegions` | string\[] | `[]` | Prefix match on NUTS/ITL codes, e.g. `UKD`, `UKI`. |
| `smeSuitableOnly` | boolean | `false` | Only notices the buyer marked as suitable for SMEs. |
| `maxItems` | integer | `500` | Max records returned. |
| `failIfEmpty` | boolean | `false` | Fail the run if nothing is returned. Useful for health checks. |

De-duplication key: stage + buyer name + title, within a run. Results are sorted by `publishedAt`, newest first.

#### Output

| Field | Type | Description |
|---|---|---|
| `source` | string | `Find a Tender` or `Contracts Finder` |
| `noticeId` | string | Notice ID on the source site |
| `ocid` | string | OCDS contracting process ID |
| `noticeUrl` | string | Link to the official notice |
| `stage` | string | `pipeline`, `tender`, `award` or `other` |
| `tags` | string\[] | Raw OCDS release tags |
| `publishedAt` | string | Release date (ISO 8601) |
| `title`, `description` | string | Notice title and description |
| `status` | string or null | OCDS tender status |
| `category` | string or null | Main procurement category (`goods`, `services`, `works`) |
| `procurementMethod` | string or null | Procurement method details |
| `cpvCodes` | string\[] | CPV codes from the tender and its items |
| `cpvDescription` | string or null | Description of the main CPV code |
| `valueGBP`, `minValueGBP` | number or null | Tender value (sum of lots if no total), minimum value |
| `awardValueGBP` | number or null | Sum of award values |
| `currency` | string or null | Currency of the values |
| `deadline` | string or null | Tender period end date |
| `contractStart`, `contractEnd` | string or null | Contract period |
| `buyerName`, `buyerLocality`, `buyerPostcode` | string or null | Buyer organisation and address |
| `regions`, `postcodes` | string\[] | Buyer and delivery regions/postcodes |
| `suitableForSME`, `suitableForVCSE` | boolean or null | Buyer's suitability flags |
| `suppliers` | string\[] | Supplier names (award notices) |
| `licence` | string | OGL v3.0 attribution |

Buyer contact emails and phone numbers are not included. A `SUMMARY` record in the run's key-value store has `scanned`, `delivered`, `from` and `sources`.

Sample record (from a test run; description shortened):

```json
{
  "source": "Find a Tender",
  "noticeId": "099003-2026",
  "ocid": "ocds-h6vhtk-06ea83",
  "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/099003-2026",
  "stage": "award",
  "tags": [
    "award",
    "contract"
  ],
  "publishedAt": "2026-10-20T13:19:01+01:00",
  "title": "NHP Health Care Planning Tool SaaS Licence",
  "description": "NHS England (NHSE) has entered into a 12-month Software-as-a-Service (SaaS) contract for an enterprise Healthcare Planning Tool to support Wave 1 schemes ...",
  "status": "complete",
  "category": null,
  "procurementMethod": "Direct award",
  "cpvCodes": [],
  "cpvDescription": null,
  "valueGBP": null,
  "minValueGBP": null,
  "awardValueGBP": null,
  "currency": null,
  "deadline": null,
  "contractStart": null,
  "contractEnd": null,
  "buyerName": "NHS England",
  "buyerLocality": "London",
  "buyerPostcode": "SE1 8UG",
  "regions": [
    "UKI45"
  ],
  "postcodes": [
    "SE1 8UG"
  ],
  "suitableForSME": null,
  "suitableForVCSE": null,
  "suppliers": [
    "dRofus AS"
  ],
  "licence": "Contains public sector information licensed under the Open Government Licence v3.0."
}
```

#### Pricing details

Pay per event, charged per record written to the dataset (`apify-default-dataset-item`): $0.004 on the Free plan, $0.0035 on Bronze, $0.003 on Silver and above. Plus the Apify Actor start event ($0.00005). Notices removed by filters or de-duplication are not charged.

#### Usage

Apify API (synchronous run, returns dataset items):

```bash
curl -X POST "https://api.apify.com/v2/acts/opendata-tools~uk-tenders-feed/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["software", "IT", "digital"],
    "stages": ["tender"],
    "openOnly": true,
    "minValue": 25000,
    "daysBack": 7,
    "maxItems": 200
  }'
```

Python (`pip install apify-client`):

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("opendata-tools/uk-tenders-feed").call(run_input={
    "cpvPrefixes": ["72"],
    "nutsRegions": ["UKD"],
    "stages": ["tender", "pipeline"],
    "daysBack": 14,
    "maxItems": 500,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["publishedAt"], item["buyerName"], item["title"], item["noticeUrl"])
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('opendata-tools/uk-tenders-feed').call({
    keywords: ['cyber security'],
    stages: ['award'],
    daysBack: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.buyerName, item.awardValueGBP, item.suppliers);
```

#### Data source and licence

Data comes from the public OCDS endpoints of Find a Tender and Contracts Finder and contains public sector information licensed under the Open Government Licence v3.0. Not affiliated with or endorsed by the UK Government. Values and dates are as published; some notices omit them. Check `noticeUrl` before bidding.

### FAQ

#### Do I need an API key or an account on the tender sites?

No. The Actor uses the public endpoints of Find a Tender and Contracts Finder, so no API key or login is needed.

#### Does it include buyer contact details?

No. Buyer contact emails and phone numbers are not included. You get the buyer's name, locality and postcode, and a link to the official notice.

#### Why are some values or deadlines empty?

Values and dates are passed on as published, and some notices omit them. Note that when you set a minimum or maximum value, notices with no value are left out. Always check `noticeUrl` before bidding.

#### Is this an official government service?

No. It is not affiliated with or endorsed by the UK Government. The data is public sector information published under the Open Government Licence v3.0.

Issues and feature requests: use the Issues tab.

# Actor input Schema

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

Whole-word match in title, description or CPV description. Case-insensitive, except all-caps terms up to 5 characters (IT, NHS, HR), which match case-sensitively. Leave empty for all.

## `keywordMode` (type: `string`):

Any keyword (default) or all keywords must match.

## `excludeKeywords` (type: `array`):

Drop notices containing any of these.

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

How many days of notices to scan.

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

Which official sources to query.

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

Leave empty for all stages.

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

Keep only tenders whose deadline is in the future.

## `cpvPrefixes` (type: `array`):

E.g. 72 (IT services), 4521 (building works).

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

Uses tender value, or award value if no tender value.

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

Uses tender value, or award value if no tender value.

## `postcodePrefixes` (type: `array`):

Buyer or delivery postcode prefix, e.g. M, LS1, SW1A.

## `nutsRegions` (type: `array`):

E.g. UKD (North West), UKI (London). Prefix match.

## `smeSuitableOnly` (type: `boolean`):

Only notices the buyer marked as suitable for SMEs.

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

Stop after this many results (you are charged per result).

## `failIfEmpty` (type: `boolean`):

Mark the run as failed when nothing is returned (useful for monitoring).

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "keywordMode": "any",
  "daysBack": 7,
  "sources": [
    "find_a_tender",
    "contracts_finder"
  ],
  "openOnly": false,
  "smeSuitableOnly": false,
  "maxItems": 500,
  "failIfEmpty": false
}
```

# Actor output Schema

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

All matching notices in the default dataset.

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

Counts of notices scanned and delivered.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("opendata-tools/uk-tenders-feed").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"] }

# Run the Actor and wait for it to finish
run = client.actor("opendata-tools/uk-tenders-feed").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"
  ]
}' |
apify call opendata-tools/uk-tenders-feed --silent --output-dataset

```

## MCP server setup

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

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/3YcJXxZGnsh4TUuaF/builds/mhYcuTURpTAYebby4/openapi.json
