# UK Tenders Scraper: Contract Winners and Open Tenders (`agents001/uk-public-contracts-feed`) Actor

Returns UK public contract awards with the winning supplier (Companies House number, location, SME flag), buyer, value, CPV codes and notice link, plus open tenders, from Find a Tender (Procurement Act 2023) and Contracts Finder.

- **URL**: https://apify.com/agents001/uk-public-contracts-feed.md
- **Developed by:** [Mike Ross](https://apify.com/agents001) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 contract awards

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 Government Contracts Scraper: Award Winners

Get a clean feed of **which companies just won UK public sector contracts**, plus the **open tenders** they can bid for next. Every award record names the winning supplier with its **Companies House number**, town, postcode, region and SME status, alongside the buyer, contract title, value, CPV codes, award date and a link to the official notice.

Data comes from the two official UK government procurement services, through their open APIs:

- **Find a Tender**, which carries every notice published under the **Procurement Act 2023** (in force since 24 February 2025) and above-threshold notices under the old regulations.
- **Contracts Finder**, which still carries lower-value notices for procurements run under the old regulations.

Records are company-level only. Buyer and supplier contact names, email addresses and phone numbers are never returned.

### What you get

**Contract award records** (`recordType: "award"`), one per winning supplier per notice:

| Field | Example |
|---|---|
| `supplierName` | `EDILTEX LTD` |
| `supplierCompaniesHouseNumber`, `supplierCompaniesHouseUrl` | `08020912`, link to the Companies House page |
| `supplierPpon`, `supplierCharityNumber` | Central Digital Platform supplier number, charity number where given |
| `supplierLocality`, `supplierPostcode`, `supplierRegion`, `supplierCountry` | `Newport`, `NP20 2AQ`, `Wales`, `United Kingdom` |
| `supplierSize`, `supplierIsSme`, `supplierIsVcse` | `sme`, `true`, `false` |
| `supplierWebsite` | The company website when the notice gives one |
| `buyerName`, `buyerType`, `buyerRegion` | `Devon County Council`, `Public authority - sub-central government`, `South West` |
| `title`, `description`, `lotTitles`, `lotsWon` | Contract title, first 300 characters of the description, lots won on this notice |
| `value`, `valueIncludingVat`, `currency`, `valueSource` | `250000`, `300000`, `GBP`, `contract` |
| `valueShared`, `suppliersOnAward` | `true` when a framework or shared award names several suppliers |
| `mainCpvCode`, `mainCpvDescription`, `cpvCodes`, `cpvDescriptions` | `19620000`, `Textile waste` |
| `awardDate`, `contractSignedDate`, `contractStartDate`, `contractEndDate` | Calendar dates as published |
| `awardStatus` | `pending` (standstill period, not yet signed) or `active` |
| `noticeType`, `noticeTypeName`, `legalFramework` | `UK7`, `Contract details notice`, `Procurement Act 2023` |
| `publishedAt`, `noticeUrl`, `source` | When the notice was published (UTC), the official notice page, `findATender` or `contractsFinder` |
| `isNew` | Whether the record is new since the previous run with the same filters |

**Tender records** (`recordType: "tender"`), one per open opportunity, with the buyer, title, description, estimated value, CPV codes, `tenderDeadline`, contract dates, `suitableForSme`, procedure and notice link.

The Output tab has three views: **Contract awards**, **Open tenders** and **Winning companies**.

### Who it is for

- **Sales and business development teams.** A company that has just won a public contract is about to hire, buy equipment, subcontract and spend. Get a daily list of winners in your sector and region, with the Companies House number ready to match against your CRM.
- **Bid teams and suppliers to government.** See who wins in your category, at what value, and which buyers are spending, then pick up the open tenders in the same feed.
- **Lenders, insurers and analysts.** Track contract wins by company, sector and region for credit, risk and market research.
- **Recruiters and staffing firms.** Contract winners often need to scale teams quickly.

### Quick start

1. Click **Start** with the default input. You get up to 500 of the newest contract award records published in the last 7 days.
2. Narrow it down: add CPV codes (for example `72000000` for IT services), keywords like `cleaning` or `cyber`, a minimum value, or regions.
3. For a daily feed, schedule the Actor every morning with **Only records not seen in previous runs** switched on, `daysBack` set to 2 and `maxItems` set to 0. Connect the dataset to Google Sheets, Slack, email or your CRM with an Apify integration or webhook.

### Input

| Field | What it does | Default |
|---|---|---|
| `mode` | `awards` (who won), `tenders` (open opportunities) or `both` | `awards` |
| `daysBack` | Notices published or updated in the last N days | 7 |
| `dateFrom`, `dateTo` | Exact publication window instead of `daysBack`, for example `2026-10-01` | not set |
| `cpvCodes` | CPV codes. Trailing zeros mean "everything below": `72000000` matches all IT services, `4521` matches `45210000` to `45219999` | all |
| `keywords` | Title, description, lot titles, CPV description or supplier name contains any of these | none |
| `buyerKeywords` | Buyer name contains any of these, for example `NHS`, `Council` | none |
| `minValue` | Minimum value in GBP. Notices without a value are dropped when this is above 0 | 0 |
| `regions` | UK regions, or `England` for all nine English regions | all |
| `regionAppliesTo` | Match regions against the buyer or place of delivery, or against the winning supplier | buyer or delivery |
| `supplierSize` | `any`, `sme` or `large` (awards only) | `any` |
| `onlyOpenTenders` | Drop tenders whose deadline has passed | true |
| `includeUpdates` | Include corrected or updated notices | true |
| `sources` | `findATender`, `contractsFinder` or both | both |
| `onlyNew` | Only records not returned by an earlier run with the same filters | false |
| `maxItems` | Stop after this many records, newest first. 0 means no limit | 500 |
| `timeBudgetSecs` | Stop reading after this many seconds and return what was found. 0 means no limit | 100 |

Example input for a daily sales feed of IT contract winners in London and the South East:

```json
{
  "mode": "awards",
  "daysBack": 2,
  "cpvCodes": ["72000000", "48000000", "30200000"],
  "regions": ["London", "South East"],
  "minValue": 50000,
  "onlyNew": true,
  "maxItems": 0
}
```

### Output example

```json
{
  "recordType": "award",
  "source": "findATender",
  "noticeId": "100218-2026",
  "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/100218-2026",
  "noticeType": "UK7",
  "noticeTypeName": "Contract details notice",
  "legalFramework": "Procurement Act 2023",
  "title": "Demolition Works at Pennethorne House, SW11",
  "description": "The contract entails demolition works at Pennethorne House, Winstanley and York Road, SW11. Please refer to tender documents for full information.",
  "awardStatus": "active",
  "supplierName": "J F Hunt Limited",
  "supplierPpon": "PVTT-8493-CPYM",
  "supplierLocality": "Essex",
  "supplierPostcode": "RM20 4DB",
  "supplierRegion": "East of England",
  "supplierSize": "large",
  "supplierIsSme": false,
  "supplierWebsite": "http://www.johnfhunt.co.uk",
  "suppliersOnAward": 1,
  "valueShared": false,
  "lotsWon": 1,
  "buyerName": "London Borough of Wandsworth",
  "buyerType": "Public authority - sub-central government",
  "buyerRegion": "London",
  "mainCpvCode": "45111000",
  "mainCpvDescription": "Demolition, site preparation and clearance work",
  "category": "works",
  "value": 951194.0,
  "valueIncludingVat": 1141432.8,
  "currency": "GBP",
  "valueSource": "contract",
  "awardDate": "2025-10-24",
  "contractStartDate": "2025-10-24",
  "contractEndDate": "2026-10-24",
  "publishedAt": "2026-10-22T21:34:26Z",
  "procedureDetails": "Below threshold - limited competition",
  "aboveThreshold": false,
  "isNew": true
}
```

A run report is saved in the key-value store as `RUN_SUMMARY`: records returned per type, notices read per source, suppliers removed as private individuals, and any source that could not be read.

### Pricing

This Actor uses **pay per event** pricing. Platform usage is included.

- **$2.50 per 1,000 contract award records** (`contract-award` event, $0.0025 each)
- **$2.00 per 1,000 tender records** (`tender-notice` event, $0.002 each)

You only pay for records saved to your dataset, so filters, `onlyNew` and `maxItems` keep costs down. A typical week has about 3,000 award records and 500 open tenders across the UK; a daily feed filtered to one sector and region is usually a few dozen records a day. Set a maximum cost per run in the run options and the Actor stops cleanly when it is reached.

### How "only new records" works

With `onlyNew` on, the Actor remembers which records it has already returned for your filters, in a key-value store in your account called `agents001-uk-public-contracts-feed-state`. Later runs skip those records. The date window and `maxItems` are not part of the memory, so a rolling `daysBack` window on a schedule keeps one history. Changing any filter starts a fresh history.

With `onlyNew` off, the Actor does not open or update this store, so every record has `isNew` set to true. If a run stops with a message that it cannot open the store (for example because another Actor in your account already uses that name), enter a different name in **State store name** and run again.

An award record is identified by the notice's Open Contracting id and the supplier, so the same win reported first in a contract award notice (UK6) and later in a contract details notice (UK7) is returned once. A tender is identified by its Open Contracting id.

Records are returned newest first and `maxItems` caps each run. If a run hits `maxItems`, the next `onlyNew` run continues with older records it has not returned yet. For a complete daily feed, use a short `daysBack` (1 or 2) with `maxItems` set to 0.

### Good to know

- **One record per winner.** A notice with several lots or several winning suppliers gives one record per supplier. When a supplier wins several lots on one notice, they are combined into one record (`lotsWon`, `lotTitles`) and `value` is the sum of those lots.
- **Frameworks.** When an award names several suppliers, `valueShared` is `true` and `value` is the whole award (often a ceiling for the framework), not that supplier's share.
- **Companies House numbers** are given when the notice includes them: most suppliers registered on the Central Digital Platform do, and many older notices do too. When they are missing, `supplierPpon` or `supplierId` identifies the supplier on the notice.
- **Regions** come from the region code on the notice where there is one, otherwise from the postcode area. Postcode areas that cross a regional border are given the region that holds most of the area.
- **Private individuals are removed.** Some suppliers are sole traders listed under their own name (for example individual tutors). Those records are dropped, along with placeholder names such as "Various". The check is automatic and errs on the side of removal, so a small number of businesses named after a person may also be left out.
- **Time budget.** The government APIs allow a limited number of requests per minute and ask callers to wait two minutes when that is exceeded. A run stops reading after `timeBudgetSecs` (100 seconds by default) and returns what it has, with `stoppedAtTimeBudget` in `RUN_SUMMARY`. A normal 7 day window reads in well under a minute. For backfills of 30 days or more with no maximum, set `timeBudgetSecs` to 0 or several minutes.
- **Updated notices** appear again with `isUpdate: true` when a buyer corrects them. Turn off `includeUpdates` to skip them.

### Data source, licence and attribution

All data comes from the official open APIs of Find a Tender (`find-tender.service.gov.uk`) and Contracts Finder (`contractsfinder.service.gov.uk`), both run by the UK Cabinet Office and Crown Commercial Service. The notice data is published in the Open Contracting Data Standard (OCDS) format under the Open Government Licence.

Contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). Source: Find a Tender and Contracts Finder, © Crown copyright.

The Actor reads the APIs politely (at most one request per second per service, with backoff on rate limits), uses no login, and keeps only company-level information.

### FAQ

**Why do some awards have an award date months before the publication date?**
Buyers publish some notices after the contract is signed, and contract details notices (UK7) are often published later than the award. `publishedAt` is when the notice appeared; `awardDate` is the date the buyer gives for the award.

**Why is the value empty or very large on some records?**
Some buyers leave the value out. Frameworks and dynamic markets often state the maximum spend across all suppliers over several years, which can run into hundreds of millions.

**Does it cover Scotland, Wales and Northern Ireland?**
It covers every notice published on Find a Tender and Contracts Finder, which includes many Scottish, Welsh and Northern Irish buyers. Public Contracts Scotland, Sell2Wales and eTendersNI also carry notices that are not on these two services.

**Something looks wrong. What should I do?**
Open an issue on the Actor's Issues tab with the run link and the notice URL.

### Disclaimer

This Actor is independent and is not affiliated with, endorsed by or sponsored by the Cabinet Office, Crown Commercial Service, Find a Tender, Contracts Finder, Companies House or any buyer or supplier named in the data. Check the original notice before acting on it.

# Actor input Schema

## `mode` (type: `string`):

Contract awards (one record per winning supplier), open tender notices, or both.

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

Notices published or updated from this many days ago up to now. Ignored when 'From date' is set.

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

Optional exact start of the publication window, for example 2026-10-01. Overrides 'Published in the last N days'.

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

Optional end of the publication window (inclusive), for example 2026-10-15. Empty means up to now.

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

Only notices with a CPV code under any of these. Trailing zeros mean 'everything below', so 72000000 matches all IT services and 4521 matches 45210000 to 45219999. Leave empty for all.

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

Only notices whose title, description, lot title, CPV description or supplier name contains any of these words or phrases, for example 'software', 'cleaning', 'cyber'. Case-insensitive.

## `buyerKeywords` (type: `array`):

Only notices from buyers whose name contains any of these, for example 'NHS', 'Council', 'Ministry of Defence'.

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

Only notices worth at least this much (value excluding VAT, or including VAT where that is all the notice gives). Notices without a value are left out when this is above 0.

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

Only notices in these UK regions. 'England' covers the nine English regions. See 'Region applies to'.

## `regionAppliesTo` (type: `string`):

Match the region against the buyer's address or the place of delivery, or against the winning supplier's address (awards only).

## `supplierSize` (type: `string`):

Awards only: keep all winners, only SMEs, or only large organisations, as stated on the notice.

## `onlyOpenTenders` (type: `boolean`):

Tenders only: drop tenders whose submission deadline has passed.

## `includeUpdates` (type: `boolean`):

Include notices that were changed or corrected in the window, not only first publications.

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

Find a Tender carries every notice under the Procurement Act 2023 (since 24 February 2025) and above-threshold notices under the old rules. Contracts Finder carries lower-value notices under the old rules. Leave empty for both.

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

Remember which records were already returned for these filters and only return new ones. The first run returns everything that matches. Ideal for scheduled daily runs. The date window and maxItems are not part of the memory, so a rolling window keeps one history.

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

Stop after this many records, newest first. 0 means no limit. You pay per record returned.

## `stateStoreName` (type: `string`):

Only used when 'Only records not seen in previous runs' is on. Name of the key-value store in your account that remembers records already returned. Each different set of filters gets its own record inside it. Change it only to keep separate histories. If a run reports that it cannot open the store, enter a different name here.

## `timeBudgetSecs` (type: `integer`):

Stop reading after this many seconds and return what was found so far, so runs stay quick even when the government APIs are rate limiting. 0 means no limit. Raise it (or set 0) for large windows, for example 30 days or more with no maximum.

## `requestDelaySecs` (type: `number`):

Minimum seconds between requests to the same API. Keep this polite.

## Actor input object example

```json
{
  "mode": "awards",
  "daysBack": 7,
  "minValue": 0,
  "regionAppliesTo": "buyerOrDelivery",
  "supplierSize": "any",
  "onlyOpenTenders": true,
  "includeUpdates": true,
  "onlyNew": false,
  "maxItems": 500,
  "stateStoreName": "agents001-uk-public-contracts-feed-state",
  "timeBudgetSecs": 100,
  "requestDelaySecs": 1
}
```

# Actor output Schema

## `awards` (type: `string`):

No description

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

No description

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

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("agents001/uk-public-contracts-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("agents001/uk-public-contracts-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 '{}' |
apify call agents001/uk-public-contracts-feed --silent --output-dataset

```

## MCP server setup

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