# UK Public Tenders Feed (Contracts Finder + Find a Tender) (`owenryland/uk-public-tenders`) Actor

Every new UK public-sector tender in one clean, de-duplicated feed from the official Contracts Finder and Find a Tender APIs. Filter by keyword, CPV, value, region, SME suitability and deadline; 'only new' mode for daily alerts. No scraping, no personal contact data.

- **URL**: https://apify.com/owenryland/uk-public-tenders.md
- **Developed by:** [Owen Ryland](https://apify.com/owenryland) (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

## UK Public Tenders Feed (Contracts Finder + Find a Tender)

Every new **UK public-sector tender** in one clean, de-duplicated feed, straight from the two **official Cabinet Office OCDS APIs**: Find a Tender and Contracts Finder. Filter by keyword, CPV code, value, region, buyer postcode, SME suitability and deadline. Schedule it daily with **Only new** switched on, and you get (and pay for) just the fresh opportunities.

**No scraping, no login, no proxies, no personal contact data.**

### Who it's for

- Small and mid-size suppliers who bid for council, NHS, school and government work
- Bid writers and consultants watching several sectors for clients
- Sales teams and agencies building a public-sector pipeline
- AI agents and automations (Make, Zapier, n8n, Slack or email alerts)

### Why this one

- **Both sources, one row per tender.** The same procurement often appears on both sites. Duplicates are merged (Find a Tender version kept), so you never pay twice.
- **Handles the new Procurement Act 2023 notice format.** CPV codes on items, VAT-inclusive values and per-lot SME flags are read correctly.
- **Only new since last run.** The Actor remembers what it has delivered.
- **Clean fields.** Value in £, deadline, days left, CPV, buyer town and postcode, SME/VCSE suitability, framework flag, lots, link to the official notice.
- **Privacy by design.** Named contact people, emails and phone numbers are never output, and are removed from free-text descriptions.

### Input

| Field | Example | Notes |
|---|---|---|
| `keywords` | `["software", "cleaning"]` | Any match in title, description or CPV description. Whole words. |
| `excludeKeywords` | `["framework"]` | |
| `cpvPrefixes` | `["72", "90910000"]` | Main or additional CPV codes. |
| `minValueGbp` / `maxValueGbp` | `10000` | Notices with no stated value are dropped when set. |
| `regions` | `["UKD", "UKI"]` | ITL/NUTS code prefixes. |
| `buyerPostcodePrefixes` | `["M", "BB11"]` | Buyer's address postcode. |
| `stages` | `["tender"]` | `tender`, `planning` (pipeline), `award`. |
| `publishedWithinDays` | `7` | 1 to 90. |
| `openOnly` | `true` | Drop tenders past their deadline or cancelled. |
| `smeSuitableOnly` | `false` | |
| `onlyNew` | `false` | Turn on for scheduled runs. |
| `maxResults` | `200` | |

### Output (one row per notice)

```json
{
  "title": "SHWD Cleaning",
  "buyerName": "South Hams District Council",
  "buyerPostcode": "TQ9 5NE",
  "valueGbp": 150000,
  "deadline": "2026-11-20T12:00:00Z",
  "daysToDeadline": 28,
  "cpvCode": "90910000",
  "cpvDescription": "Cleaning services",
  "smeSuitable": true,
  "procurementMethod": "Below threshold - open competition",
  "sourceName": "Find a Tender",
  "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/099577-2026"
}
```

*(Real row from a test run on 23 Oct 2026; `daysToDeadline` is relative to the run.)*

See `test-output-sample.json` for a full real run (23 Oct 2026, keywords "software" and "cleaning", last 7 days: 50 open tenders, median stated value £299,200).

### Pricing

Pay per event: **$0.003 per tender notice delivered**. Filtered-out notices, merged duplicates and (in Only new mode) notices you already have are **not charged**. Example: a daily schedule that finds 10 new matches costs about $0.90 a month.

### Notes and limits

- Covers notices published on Find a Tender (UK-wide, including Scotland and Wales above threshold) and Contracts Finder (mainly England). It does not read Public Contracts Scotland, Sell2Wales or eTendersNI directly.
- Values are as the buyer stated them. `valueIncludesVat` is `true` where only the VAT-inclusive figure was given. Some notices give no value.
- Notices can be updated or cancelled after publication. Always check the official notice before bidding.
- Not legal or bidding advice.

### Data source and licence

Contains public sector information licensed under the Open Government Licence v3.0 (Contracts Finder and Find a Tender, Cabinet Office). Not affiliated with or endorsed by the Cabinet Office. Personal data is excluded, because the OGL does not cover personal data.

### Support

Found a problem or want a feature (e.g. Public Contracts Scotland, Slack alerts, award analytics)? Open an issue on the Actor's **Issues** tab. Issues are answered within 2 working days.

# Actor input Schema

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

Keep notices whose title or description contains any of these words or phrases (whole-word, case-insensitive). Leave empty for all.

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

Drop notices containing any of these words or phrases.

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

Keep notices whose main or additional CPV code starts with any of these, e.g. 72 (IT services), 90910000 (cleaning), 45 (construction).

## `minValueGbp` (type: `integer`):

Notices without a stated value are dropped when a minimum or maximum is set.

## `maxValueGbp` (type: `integer`):

Only include notices whose estimated value is at or below this amount in pounds. Leave empty for no upper limit.

## `regions` (type: `array`):

Prefix match on delivery or buyer region codes, e.g. UKD (North West), UKI (London), UKM (Scotland), UKL (Wales). Many Contracts Finder notices give no region, so they are dropped when this is set.

## `buyerPostcodePrefixes` (type: `array`):

Keep notices whose buyer's address postcode starts with these, e.g. M, BB11, LS.

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

Find a Tender (all above-threshold and, since the Procurement Act 2023, many below-threshold notices) and Contracts Finder (England below-threshold).

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

Which notice types to return: open tenders you can bid on, pipeline/planning notices, or contract awards.

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

Only include notices published or updated in the last N days (1 to 90).

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

For the tender stage, drop notices whose deadline has passed or that are cancelled.

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

Only return notices the buyer has marked as suitable for small and medium-sized enterprises.

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

Remembers delivered notices in a named key-value store, so a daily schedule gives you just the fresh ones (and you only pay for those).

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

The maximum number of notices to output in one run (each output notice is one billable event).

## `descriptionMaxChars` (type: `integer`):

0 = full text.

## Actor input object example

```json
{
  "keywords": [
    "software",
    "cleaning"
  ],
  "sources": [
    "find-a-tender",
    "contracts-finder"
  ],
  "stages": [
    "tender"
  ],
  "publishedWithinDays": 7,
  "openOnly": true,
  "smeSuitableOnly": false,
  "onlyNew": false,
  "maxResults": 200,
  "descriptionMaxChars": 1000
}
```

# Actor output Schema

## `overview` (type: `string`):

One dataset item per de-duplicated tender or award notice from Contracts Finder and Find a Tender. Named contacts, emails and phone numbers are removed.

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

// Run the Actor and wait for it to finish
const run = await client.actor("owenryland/uk-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",
        "cleaning",
    ] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,owenryland/uk-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/iaA2LH5PU8ZdwSrCH/builds/oBcbhSccJMqjowbHg/openapi.json
