# UK Contracts Finder Scraper — Public Tenders & Awards (`northbell/uk-contracts-finder-scraper`) Actor

UK public tenders and contract awards from Contracts Finder: buyer, title, CPV codes, value, deadline, region and winning supplier. Filter by keyword, CPV code, region or value, and flag notices that are new since your last run. Official API, no login.

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

## Pricing

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

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 Contracts Finder Scraper — Public Tenders & Awards

Search the UK government's **Contracts Finder** by keyword, CPV code, region, value or notice kind and get one clean row per notice: **buyer, title, description, CPV codes, value range and currency, deadline, delivery regions and — on award notices — the winning supplier and awarded value**, with a link to the notice on Contracts Finder. **$2.00 per 1,000 notices**, no login, no API key.

Run it again, or put it on a daily schedule, and every row also tells you **whether the notice is new since the last run** (`isNew`). Set *What to return* to *Only new* and you pay only for the notices you have not seen before.

**What Contracts Finder holds now.** Under the Procurement Act 2023, procurements started on or after 24 February 2025 are published on **Find a Tender**, not on Contracts Finder ([GOV.UK guidance](https://www.gov.uk/government/publications/procurement-act-2023-guidance-documents-define-phase/guidance-below-threshold-contracts-html)). Contracts Finder still carries the notices of procurements started before that date, so most of what it publishes today are **award results** (on 16 October 2026: 83 award notices and 8 open opportunities). The form starts on *Award results* for that reason. For new UK tenders to bid on, search Find a Tender.

### What you get

| Field | What it is |
|---|---|
| `noticeId`, `noticeReference`, `url` | Contracts Finder's notice id, the reference the buyer or its procurement portal gave it and the link to its page |
| `noticeKind`, `noticeType`, `status` | `open-call` (a live opportunity), `closed-call`, `award`, `planning` (future opportunity), `early-engagement`, `withdrawn`; Contracts Finder's own type (`Contract`, `Pipeline`, `PreProcurement`) and status (`Open`, `Closed`, `Awarded`, `Withdrawn`) |
| `publishedOn`, `updatedAt` | the date the notice was first published (UK date) and the time of its last update, with the UK offset |
| `deadline` | the submission deadline with time and offset as the notice states it. `null` on award notices (their stored deadline is the old tender deadline, not a live one) |
| `isNew`, `previousRunAt` | `true` / `false` whether you had not seen this notice in your previous run of the same search, and when that run was (`null` on the first run) |
| `buyerName` | the buying organisation (a public body) |
| `title`, `description` | the title, and the description cleaned of markup and cut at 500 characters on a word boundary (`…` marks a cut) |
| `cpvCodes`, `mainCpv`, `cpvDescription` | the notice's CPV codes (8 digits), the first one, and Contracts Finder's text for them |
| `valueMin`, `valueMax`, `currency` | the value as stated, in pounds (`GBP`). A single stated value arrives as `valueMin` alone; a range as both. `null` where the buyer stated nothing |
| `regions` | the delivery regions the buyer ticked (`["Wales"]`, `["Any region"]`, or all twelve for a UK-wide notice) |
| `contractStart`, `contractEnd` | the contract's start and end dates |
| `suitableForSme` | whether the buyer marked the notice as suitable for small businesses |
| `awardedSupplier`, `awardedValue`, `awardedDate`, `awardedToSme` | on award notices: the supplier name as the buyer entered it (several winners come in one text, separated by commas), the value awarded, the date, and whether the winner is marked as an SME |
| `observedAt` | when the row was collected |

### Run it again and again

- **On a schedule**: save your input as a task and add a **Schedule**: the same search every morning. Send each run to Google Sheets, Slack or email with an integration on the task.
- **Watch for changes**: Set **What to return** to *Only notices that are new since the last run*.
- **In bulk**: Combine **Keywords**, **CPV codes**, **Regions** and a value range in one run.

### Use it for

- **Bid monitoring**: a daily schedule with your keywords or CPV codes, *Open opportunities* and *Only new*, sent to Sheets, Slack or your CRM
- **Lead lists for suppliers**: the public bodies that buy what you sell: buyer, region, CPV, value and the notice link
- **Market research**: *Award results* by CPV code and region show who wins, how often and for how much
- **Pipeline planning**: *Planning notices* (future opportunities and early engagement) announce purchases before the call is published

### Input

```json
{
  "keywords": ["software"],
  "cpvCodes": ["72000000"],
  "regions": ["London", "South East"],
  "noticeKind": "open-calls",
  "valueFrom": 50000,
  "publishedWithinDays": 7,
  "maxNotices": 200,
  "output": "new"
}
```

- All filters are combined with AND; the entries inside one list are combined with OR.
- **keywords**: Contracts Finder searches the notice title and description and treats every word separately (OR): in a live check on 16 Oct 2026, `road` found 19 open notices, `maintenance` 58 and `road maintenance` 71, the union of the two. A phrase in quotation marks found none, so the Actor removes quotation marks. Use short single words.
- **cpvCodes**: a code covers its whole branch: `72000000` matched 29 open notices on 16 Oct 2026, and 20 of them carried only narrower `72…` codes such as `72223000`. Contracts Finder does not accept a short code such as `72` (0 notices), so the Actor pads it to `72000000`.
- **regions**: the delivery region as Contracts Finder names it (`London`, `Wales`, `Yorkshire and The Humber`…). Notices that apply to the whole UK are included, because the buyer ticked every region.
- **valueFrom / valueTo**: in pounds. A notice that states no value is left out when you set a value range (30 of 30 award rows in a live check with `valueFrom` had a value).
- **noticeKind**: `open-calls` (live opportunities), `awards`, `planning` (future opportunities and early engagement) or `all` (also closed and withdrawn notices).
- **publishedWithinDays**, **publishedFrom**, **publishedTo** — Contracts Finder works in whole days, in UK time. It returns a notice when it was first published **or last updated** in the period: of 416 award notices returned for 14–15 Oct 2026, 26 had been published earlier and updated in the period. `publishedFrom` / `publishedTo` (`YYYY-MM-DD`) replace *Published or updated within*.
- Results are sorted newest first (by last update), and **maxNotices** (default 200, up to 5,000) cuts the list from the old end. With *Only new* it is the number of new notices to return: the Actor reads down the list, past the notices you have already seen (up to 5,000 notices deep), until it has found that many. Notices below the cut-off are not marked as seen, so they come back as new in your next run.

"Is it new" is remembered per search — the same keywords, CPV codes, regions, value range and notice kind — in a named key-value store in your Apify account, so the second run of the same search already shows `isNew`. Changing the period or *Maximum notices* keeps the same history. A notice counts as seen by its Contracts Finder notice id.

### Pricing

**$2.00 per 1,000 notices**, plus $0.01 per run. Error rows (a search Contracts Finder rejects, Contracts Finder not answering) are free. With *Only new*, notices you have already seen are skipped and not charged. The $0.01 run-start fee is the one charge every run pays, even one that returns nothing.

### Notes

- Source: the public notice search of Contracts Finder (`/api/rest/2/search_notices`), run by the Crown Commercial Service. Anonymous access, nothing from behind a login. Contracts Finder's terms say most of its content is published under the Open Government Licence v3.0, with some exemptions listed on its site. Contains public sector information licensed under the Open Government Licence v3.0. The terms also ask users not to crawl in a way that impairs the service: the Actor sends one search at a time, waits a second between searches, and waits five minutes and tries once more if the service answers HTTP 403, the "too many requests" answer its API documentation describes.
- Buyers are public bodies. **No contact persons, email addresses or phone numbers are returned**; the Actor never reads those fields, and it removes e-mail addresses and phone numbers that buyers typed into titles and descriptions (36 of 754 descriptions in a read of 520 open and 234 award notices on 16 Oct 2026 held an e-mail address). It cannot recognise a person's name written into free text, so a description can still name a contact. `awardedSupplier` is whatever the buyer entered; for a sole trader or a small firm that can be the trader's own name, as Contracts Finder publishes it.
- Contracts Finder returns at most 1,000 notices per search. When a period reaches that, the Actor splits it in half and asks again, newest half first, down to single days. If one single day still reaches 1,000 it adds a free error row saying the list for that day may be incomplete; narrow the search with a notice kind, region, CPV code or keyword.
- Values are in pounds sterling; Contracts Finder has no currency field and its notice pages show £. A value of 0 means the buyer stated none (100 of the 520 open notices state no value at all), so `valueMin` / `valueMax` are `null` there. Some buyers enter a placeholder such as 1, passed on as stated.
- `deadline` is filled on every open notice in that read (520 of 520). `awardedSupplier` was empty on 101 of 234 award notices; `awardedValue` was filled on 233 of 234.
- Descriptions are long (median 1,000 characters, longest 5,777 among the 520 open notices), so they are cut at 500.
- Dates: `publishedOn` is the UK calendar date; `deadline` and `updatedAt` keep the offset Contracts Finder sends (`Z` or `+01:00`).
- If Contracts Finder is rate limiting or down, the Actor waits and retries, then adds a free error row, and the run is marked failed when nothing at all could be read. Reading the 520 open notices in one go took about 20 seconds on 16 Oct 2026.

For EU tenders, see [EU Tenders Scraper (TED)](https://apify.com/northbell/eu-tenders-ted-search). If the winner of an award is a UK company, see [UK Companies House Scraper](https://apify.com/northbell/companies-house-search) for its register entry.

### For AI agents

`{"noticeKind": "open-calls", "publishedWithinDays": 3, "maxNotices": 5}` returns up to 5 rows, newest first, each with buyer, title, CPV codes, deadline and value. Rows have `type`: `notice` or `error`. Fields that do not apply to a notice are `null` (or an empty list), never missing. Schedule the same input daily with `"output": "new"` to get only what was published or updated since the previous run.

# Actor input Schema

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

Words to find in the notice title and description. One per line; a notice that matches any word is returned. Contracts Finder treats every word separately (OR), so "road maintenance" finds notices with road or maintenance. Use short single words, e.g. software, cleaning, bridge. Leave empty to skip.

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

Only notices for these CPV codes (the Common Procurement Vocabulary), one per line, e.g. 72000000 for IT services or 45000000 for construction work. A code covers its whole branch: 72000000 also matches 72262000. A shorter code such as 72 is padded to 72000000. Leave empty for all.

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

Only notices delivered in one of these regions, one per line: London, Wales, Scotland, Northern Ireland, North West, North East, Yorkshire and The Humber, East Midlands, West Midlands, East of England, South East, South West (also Isle of Man, Guernsey, Jersey). Notices that apply to the whole UK are included. Leave empty for all.

## `valueFrom` (type: `integer`):

Only notices whose stated value is at least this many pounds. Many notices state no value; those are left out when you set a value range.

## `valueTo` (type: `integer`):

Only notices whose stated value is at most this many pounds. Many notices state no value; those are left out when you set a value range.

## `noticeKind` (type: `string`):

Open opportunities are live contract notices. Award results name the winning supplier and the awarded value. "All notices" also returns closed and withdrawn notices. Procurements started since 24 February 2025 are published on Find a Tender, not here, so Contracts Finder now carries few open opportunities (8 on 16 October 2026) and mostly award results of older procurements.

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

Only notices first published or last updated in the last N days (UK time, today included). Ignored when "Published from" is set. Run it on a daily schedule with 7 and "Only new" below for a cheap feed of fresh tenders.

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

First day to include, written YYYY-MM-DD, e.g. 2026-09-01. When set, it replaces "Published or updated within". Contracts Finder works in whole days.

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

Last day to include, written YYYY-MM-DD. Leave empty for today. Contracts Finder works in whole days.

## `maxNotices` (type: `integer`):

How many notices to return, newest first. You pay per notice returned. With "Only new" the Actor reads past the notices you have already seen until it has found this many new ones. Narrow the search with the filters above rather than raising this.

## `output` (type: `string`):

With "Only new", notices you already got in an earlier run of the same search are skipped and not charged. The first run returns everything, because there is nothing to compare with yet.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "noticeKind": "awards",
  "publishedWithinDays": 7,
  "maxNotices": 200,
  "output": "all"
}
```

# Actor output Schema

## `notices` (type: `string`):

Buyer, title, CPV codes, value, deadline, region and awarded supplier for each notice.

# 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"
    ],
    "noticeKind": "awards"
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbell/uk-contracts-finder-scraper").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"],
    "noticeKind": "awards",
}

# Run the Actor and wait for it to finish
run = client.actor("northbell/uk-contracts-finder-scraper").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"
  ],
  "noticeKind": "awards"
}' |
apify call northbell/uk-contracts-finder-scraper --silent --output-dataset

```

## MCP server setup

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

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/5BJNGuCa6xLOb1JlW/builds/19ANAIsMaQUQY2W8i/openapi.json
