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

One clean, de-duplicated feed of UK public-sector tenders and contract awards from the official Contracts Finder and Find a Tender OCDS APIs. Filter by keyword, CPV code, value, region and date; 'new since last run' mode for alerts. OGL v3.0 data, no personal contact data.

- **URL**: https://apify.com/plainsourcedata/uk-public-tenders-feed.md
- **Developed by:** [Ihtisham Mian](https://apify.com/plainsourcedata) (community)
- **Categories:** Lead generation, Business, 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 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 (Contracts Finder + Find a Tender, unofficial)

**Get UK public-sector tenders and contract awards as clean, structured data.** This actor reads the official APIs of the two UK government procurement services, **Contracts Finder** and **Find a Tender**. It merges notices that appear on both and returns one tidy row per notice. Filter by keyword, CPV code, value, region and date. You can also run it daily so you only see notices you haven't seen before.

- Both services in one feed, with cross-service duplicates merged.
- Around **600 new notices a day** across the UK; the default run returns the 100 newest.
- Organisation data only: personal contact details are removed (see *Privacy* below).
- Unofficial and independent (see *Data source, licence and attribution*).

### What data can I get from UK tenders?

Each row is one notice (one procurement process). Fields include:

| Field | What it holds |
|---|---|
| `title`, `description` | What is being bought (contact lines redacted) |
| `stage`, `status` | planning, tender, award (and updates); active, complete… |
| `buyer` | Buying organisation: name, registry ID, town, region |
| `cpvCodes`, `cpvDescriptions` | Common Procurement Vocabulary codes and names |
| `valueAmount`, `valueAmountGross`, `currency` | Estimated or awarded value (GBP) |
| `tenderDeadline`, `enquiryDeadline` | When bids and questions are due |
| `contractStart`, `contractEnd`, `lotCount` | Contract period and number of lots |
| `suitableForSme`, `suitableForVcse`, `procurementMethod`, `legalBasis` | Procedure details |
| `awardDate`, `awardValueTotal`, `suppliers[]` | Who won (organisation name, ID, size; individuals' names withheld) |
| `noticeUrl`, `submissionUrl` | Links to the official notice and the bid portal |
| `alsoPublishedOn` | Set when the same notice is on both services |
| `licence`, `attribution` | Open Government Licence v3.0 statement |

#### Sample output

A real notice from a test run on 20 October 2026, shortened:

```json
{
  "source": "Find a Tender",
  "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/099215-2026",
  "stage": "tender",
  "releaseDate": "2026-10-20T17:41:15+01:00",
  "title": "TENDER FOR THE COLLECTION AND RECYCLING OF WASTE TIMBER Ref: 2627 TNDR EP 004A",
  "mainProcurementCategory": "services",
  "procurementMethodDetails": "Open procedure",
  "cpvCodes": ["90000000", "90500000", "90514000", "03416000"],
  "valueAmount": 780000,
  "valueAmountGross": 936000,
  "currency": "GBP",
  "tenderDeadline": "2026-11-17T12:00:00+00:00",
  "lotCount": 2,
  "buyer": { "name": "Fermanagh and Omagh District Council", "locality": "Enniskillen", "region": "UKN0G" },
  "suppliers": [],
  "licence": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
}
```

### How do I get UK tenders in 5 steps?

1. Click **Try for free** (or **Start**) on this page and sign in to Apify. A free account is enough to try it.
2. Type a few **keywords** (e.g. `software`) and/or **CPV codes** (e.g. `72` for IT services, `45` for construction).
3. Choose a date window under **From / To**: `2 days`, `7 days` or an ISO date such as `2026-10-01`.
4. Click **Start** and wait about a minute. Results appear in the **Output** tab.
5. Download as Excel, CSV or JSON, or open **Schedules** to run it every morning with **Only new since last run** switched on.

### Who is it for?

- **Bid writers and sales teams:** a morning list of new opportunities in their sector, sent to Slack, email or a CRM.
- **Market researchers:** who buys what, how often and at what value.
- **Competitor tracking:** which suppliers are winning awards, and from which buyers.

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

You pay only for the notices returned: **$4.00 per 1,000 notices** ($0.004 each) on the base tier. Higher Apify plans pay $3.50 or $3.00 per 1,000.

- There is no separate platform-usage charge, and no charge when nothing matches.
- **Apify's free plan includes $5 of monthly credit**, which covers about **1,250 notices a month** at the base price.
- Example: a daily alert that returns about 50 matching notices costs about $0.20 a day.
- Set **Maximum cost per run** in Apify, and the actor stops cleanly when it reaches it.

### Input options

- **Keywords:** a notice matches if any keyword appears in its title or description.
- **CPV codes:** prefix match. `72000000` matches every IT-services code; `48` matches software packages.
- **Stages:** planning, tender, award.
- **From / To:** an ISO date or time, or relative (`12 hours`, `7 days`). The default is the last 3 days.
- **Max results:** default 100 (newest first), so a default run costs at most $0.40.
- **Fast mode:** at most 20 notices from the last day, typically in under 30 seconds (see *AI agents* below).
- **More filters:** value range (GBP), delivery regions, SME-suitable only, and which services to search.
- **Daily alerts:** *Only new since last run* remembers what you've already received. Use a different *state key* for each saved search.
- **Advanced:** merging and de-duplication, politeness delay, and the rate-limit wait budget.

### Integrations: Google Sheets, Slack, Zapier, Make, n8n

Like every Apify actor, this one works with Apify's built-in integrations:

- **Schedules:** run it daily or hourly.
- **Google Sheets, Slack and email:** add an integration on the actor or task so new results are sent automatically after each run.
- **Zapier, Make and n8n:** use the Apify app or node to start runs and pick up the dataset.
- **Webhooks and API:** start runs and fetch results from your own code (Python, JavaScript or plain HTTP).

### Can AI agents use it (MCP)?

Yes. AI assistants can find and run this actor through **Apify's MCP server** and the Apify API.

- For quick answers, use **fast mode**. It returns up to 20 newest notices from the last day and typically finishes in **under 30 seconds**: `{"fastMode": true, "keywords": ["software"]}`
- Set a **maximum cost per run** (`maxTotalChargeUsd`) so an agent can never spend more than you intend.
- The input fields and output schema describe every option and field, so agents can build their own queries.

### FAQ

**Is this an official government service?**
No. It is an independent tool that reads the services' public APIs. Always check the official notice (`noticeUrl`) before you bid.

**Does it include contact names, e-mails or phone numbers?**
No. Contact points and street addresses are dropped, and contact lines inside descriptions are redacted.

**How fresh is the data?**
As fresh as the services themselves: each run reads the live APIs.

**Why did I get "partial results"?**
Both services sometimes ask busy clients to pause. The actor always waits as asked, up to the run's wait budget. If a service is still limiting after that, you get what was collected, clearly flagged in the status message and in `RUN_SUMMARY` (`partial: true`). The *Only new since last run* bookmark is not moved forward, so the next run fills the gap.

**Can I backfill months of data?**
Yes. Set *From* to an earlier date and raise *Max results*. Long windows take longer because of the services' rate limits. The actor searches them in 3-day parts, newest first, and saves results as it goes. If the run gets close to its timeout, it stops, keeps what it found and marks the run as partial (`RUN_SUMMARY.timedOut`). You only pay for results you get. For 30–90 day backfills, filter by keyword or CPV, or give the run a longer timeout.

**Are Scottish and Welsh tenders included?**
Notices that appear on Contracts Finder or Find a Tender are included. Tenders published only on regional portals are not.

**Something isn't working?**
Open an issue on the **Issues** tab and include the run link; we aim to reply within a few days.

### Speed and reliability

- Requests go one at a time, at least 1 second apart, and the actor honours `429`/`503` `Retry-After`. It uses no proxy rotation.
- Contracts Finder signals "too many requests" with HTTP 403 and asks clients to wait 5 minutes. The actor then stops reading that service for the run and keeps the other one.
- If both services are unavailable and nothing was found, the run fails with a clear message and **nothing is charged**.

### Data source, licence and attribution

**Contains public sector information licensed under the Open Government Licence v3.0.**
https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/

- Data comes from the official OCDS APIs of Contracts Finder and Find a Tender (Crown Commercial Service / Cabinet Office). It is not scraped from web pages.
- Each record includes the attribution and licence link. If you republish the data, keep that attribution, as the OGL requires.

**Unofficial:** this actor is not affiliated with or endorsed by the UK Government, Crown Commercial Service, the Cabinet Office or GOV.UK.

- Data is provided "as is". Always check the official notice (the `noticeUrl` field) before bidding.

### Privacy

This actor is built to output **organisation information only**:

- Named contact persons, contact e-mails, phone numbers and street addresses are removed.
- E-mail addresses, phone numbers and contact-instruction lines inside notice descriptions are redacted.
- **Supplier names are shown only when the supplier is clearly an organisation** (a registry ID such as a Companies House number, a legal form such as "Ltd", "LLP", "PLC" or "CIC", a public-body word such as "Council" or "NHS", or a supplier declared "large" on Find a Tender). Trade words such as "Taxis", "Transport", "Cleaning", "Services" or "Group" do not count. Every other supplier is shown as `[individual supplier - name withheld]`, with `nameWithheld: true` and no ID or town, and the name is also removed from the notice's title and description. When in doubt, the name is withheld.
- **Route-level passenger transport notices** (for example individual home-to-school taxi routes) get a generic title such as "Home-to-school transport contract (route details withheld)", and their description is replaced with a short note, because pick-up areas, destinations, times and seat details could relate to a child. Buyer, value, dates and CPV codes are kept, and `routeDetailsWithheld` is `true`. The full notice is still on the official site.
- House and flat numbers are removed from address-like text (e.g. "12 High Street" becomes "High Street"), and full postcodes are shortened to the outward code (e.g. `BN7`).
- These filters are automatic and can't be perfect: a notice may still mention a person in free text. You are the controller of any personal data you process, so handle it under UK GDPR.

# Actor input Schema

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

Case-insensitive; matches title or description. Leave empty for all notices.

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

E.g. 72000000 (IT services) matches all 72xxxxxx codes; 48 = software packages.

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

Stage filter applied to each release (tender = new and updated opportunities; award includes contract releases). Empty = all.

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

ISO date/time (e.g. 2026-10-01 or 2026-10-01T09:00:00) or relative like '12 hours', '7 days', '2 weeks'. Default: 3 days before 'To' (covers weekends). Ignored in 'new since last run' mode after the first run.

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

ISO date/time. Default: now (UTC).

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

Maximum notices returned (newest first). Default 100; raise it for a full feed.

## `fastMode` (type: `boolean`):

Returns at most 20 newest notices from the last day (unless you set 'From'), with a short rate-limit wait. Typically finishes in under 30 seconds, so AI agents get results without polling.

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

Uses tender value, or total award value if no tender value. Notices without a value are excluded when set.

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

Maximum value (GBP).

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

Matches delivery region names or NUTS/ITL codes, e.g. 'London', 'UKJ', 'Scotland'.

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

Only notices marked suitable for SMEs.

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

Which official services to query.

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

Remembers notices already returned (per state key) and resumes from where the last run ended. Ideal for scheduled daily alerts.

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

Use different keys for different saved searches in 'new since last run' mode.

## `latestReleasePerProcess` (type: `boolean`):

Collapse multiple updates of the same procurement (ocid) in the window into the newest one.

## `mergeCrossSourceDuplicates` (type: `boolean`):

Merge notices published on both services.

## `minSecondsBetweenRequests` (type: `integer`):

Politeness delay per request (minimum 1).

## `maxRateLimitWaitSecs` (type: `integer`):

If Contracts Finder or Find a Tender ask us to slow down, we wait as requested up to this total, then return what we have (partial results are flagged in the status message and RUN_SUMMARY). Default: 150 s for windows up to 3 days, 1800 s for longer backfills.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "dateFrom": "2 days",
  "maxResults": 100,
  "fastMode": false,
  "smeSuitableOnly": false,
  "sources": [
    "contractsFinder",
    "findATender"
  ],
  "onlyNew": false,
  "stateKey": "default",
  "latestReleasePerProcess": true,
  "mergeCrossSourceDuplicates": true,
  "minSecondsBetweenRequests": 1
}
```

# Actor output Schema

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

One item per notice from Contracts Finder or Find a Tender (OGL v3.0), de-duplicated, with no personal contact data.

## `runSummary` (type: `string`):

JSON summary of the run (counts, date window, items output).

# 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"
    ],
    "dateFrom": "2 days",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainsourcedata/uk-public-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"],
    "dateFrom": "2 days",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("plainsourcedata/uk-public-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"
  ],
  "dateFrom": "2 days",
  "maxResults": 100
}' |
apify call plainsourcedata/uk-public-tenders-feed --silent --output-dataset

```

## MCP server setup

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