# UK Public Contract Performance & Change Monitor (`nordicdataforge/uk-public-contract-performance-monitor`) Actor

Monitor official UK9 performance, UK10 contract changes, UK11 terminations, and UK12 cancellations from the Find a Tender OCDS API.

- **URL**: https://apify.com/nordicdataforge/uk-public-contract-performance-monitor.md
- **Developed by:** [Nordic Data Forge](https://apify.com/nordicdataforge) (community)
- **Categories:** Lead generation, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 contract signals

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## UK Public Contract Performance & Change Monitor

Monitor official UK public-contract performance, changes, completion or termination, and procurement cancellations without maintaining a scraper.

This Actor reads the UK Cabinet Office's public **Find a Tender OCDS API** and turns four Procurement Act 2023 transparency notices into consistent, filterable records:

- **UK9 — Contract performance notice:** published KPI metrics, observations, and source classifications.
- **UK10 — Contract change notice:** amendment dates, rationales, and classification codes.
- **UK11 — Contract termination notice:** published completion/termination outcome, end date, and final value.
- **UK12 — Procurement termination notice:** cancelled procurement reason and date.

It requires no Find a Tender account, API key, browser session, proxy, or CAPTCHA service. The default input works immediately.

### What you receive

Every result includes the official notice ID and URL, OCID, buyer and supplier organisation names, CPV codes, contract period and values when available, exact source classifications, and collection metadata. The Actor enriches each signal from the official OCDS record package so a UK9 or UK10 notice can be connected to the wider procurement record.

Persistent monitoring marks each item as `new`, `updated`, or `unchanged` and lists changed fields. Use `new-and-updated` on a schedule to create a low-noise feed.

### Quick start

1. Keep the default input.
2. Click **Start**.
3. Open the default dataset as JSON, CSV, Excel, RSS, or through the Apify API.

The default scans the last 14 days for all four signal types and returns up to 100 matching signals.

#### Example input

```json
{
    "noticeTypes": ["UK9", "UK10", "UK11", "UK12"],
    "maxResults": 100,
    "updatedWithinDays": 14,
    "keywords": ["cloud", "cyber security"],
    "buyerNames": ["Department for Transport"],
    "cpvCodes": ["72"],
    "enableChangeMonitoring": true,
    "outputMode": "new-and-updated"
}
```

All text filters are case-insensitive and match any supplied value. CPV entries match prefixes, so `72` covers the IT family while `72000000` is exact.

### Output example

```json
{
    "noticeId": "072153-2026",
    "ocid": "ocds-h6vhtk-056b63",
    "noticeType": "UK9",
    "signalType": "contract-performance",
    "title": "715124450 TWE 3",
    "buyerName": "Defence Equipment and Support",
    "supplierNames": ["Rubb Buildings Limited"],
    "performanceOutcomeCounts": {
        "met": 3,
        "approaching": 0,
        "notMet": 0,
        "other": 0
    },
    "sourceUrl": "https://www.find-tender.service.gov.uk/Notice/072153-2026",
    "sourceLicenceUrl": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
    "changeType": "new"
}
```

The complete dataset also contains the individual source-reported KPI metrics and observations. Outcome counts are a direct aggregation of the published classification IDs; the Actor does not calculate a risk score or label a supplier.

### Suggested monitoring setup

For a daily alert feed:

1. Save an input with the desired buyer, supplier, keyword, or CPV filters.
2. Set `outputMode` to `new-and-updated`.
3. Create an Apify schedule.
4. Connect the dataset or webhook to your CRM, BI tool, email automation, Slack, or database.

The history scope is based on the business filters, not the rolling date, so scheduled runs compare correctly as time advances. History is only advanced after all selected records have been delivered; a spending limit cannot silently hide records and then mark them as seen.

### Pricing and charging safety

The first **5 delivered signals per run are free**. After that, the Store price is charged only when a result is successfully written to the dataset using the `contract-signal` event. The Actor checks that Apify's automatic dataset-item event is disabled to prevent double charging. Local runs and non-Pay-per-event builds never charge.

If an Apify spending limit is reached, the Actor stops before charging or marking an undelivered record as seen.

### Data source, licence, and responsible use

Source: [Find a Tender OCDS API](https://www.find-tender.service.gov.uk/Developer/Documentation), published by the UK Cabinet Office. The API identifies the data licence as the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). Every record preserves the official notice, release-package, record-package, attribution, licence, and retrieval context.

This is an independent product by Nordic Data Forge. It is not affiliated with, endorsed by, or operated by the UK Government, Cabinet Office, or Find a Tender. No government marks or branding are used.

The output deliberately excludes structured contact-person names, email addresses, telephone numbers, postal addresses, and attachments. Email-like strings in retained narrative fields are redacted. Organisation names and identifiers are retained because they are necessary to understand the published contracting record. Customers remain responsible for their own lawful use, retention, and downstream decisions.

The Actor reports factual source fields. It does not infer misconduct, supplier quality, creditworthiness, legal breach, or risk. A termination classification can also mean normal contract completion. Verify the linked official notice before any legal, procurement, financial, or reputational decision.

### Source and operational limitations

- Find a Tender controls publication timing, coverage, classifications, and corrections.
- Older records and legacy notice formats can contain fewer fields than post-2025 notices.
- Narrow filters may require a larger `maxPages` value because the official release feed contains all notice types.
- If record enrichment is temporarily unavailable, the Actor can deliver release-only data and marks `recordContextAvailable` as `false`.
- The Actor retries temporary `429` and `5xx` responses, respects `Retry-After`, uses conservative pacing, and never bypasses access controls.

### Support

For reproducible support, include the Actor run ID, notice ID, input with secrets removed, and the unexpected field or behavior. This Actor does not require or accept source credentials.

# Actor input Schema

## `noticeTypes` (type: `array`):

UK9 reports contract KPIs, UK10 reports changes, UK11 reports completion or termination, and UK12 reports cancelled procurements.

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

Maximum matching contract signals delivered by this run.

## `updatedWithinDays` (type: `integer`):

Used when Updated from is blank. The default scans the latest 14 days.

## `updatedFrom` (type: `string`):

Optional fixed YYYY-MM-DD start date. Overrides the recent update window.

## `updatedTo` (type: `string`):

Optional inclusive YYYY-MM-DD end date.

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

Match any term across title, published rationale, buyer, supplier, CPV, or KPI text.

## `buyerNames` (type: `array`):

Optional case-insensitive partial buyer names, for example Department for Transport or NHS.

## `supplierNames` (type: `array`):

Optional case-insensitive partial supplier organisation names.

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

Match a 2–8 digit CPV prefix or exact code, for example 72 for IT or 45000000 for construction work.

## `performanceOutcomes` (type: `array`):

Optional exact source classifications. Use only with UK9 selected. No outcome is inferred by this Actor.

## `enableChangeMonitoring` (type: `boolean`):

Compare results with the prior run of the same filters in persistent Apify storage.

## `outputMode` (type: `string`):

On the first run every result is new. Later runs can emit only actionable deltas.

## `maxPages` (type: `integer`):

Safety limit for source pages scanned before stopping. Increase for narrow filters or older ranges.

## `pageSize` (type: `integer`):

The official API permits up to 100 release records per page.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each official API request.

## `maxRetries` (type: `integer`):

Retries temporary timeouts, rate limits, and server errors with backoff.

## `minRequestIntervalMillis` (type: `integer`):

Conservative delay between official API requests.

## Actor input object example

```json
{
  "noticeTypes": [
    "UK9",
    "UK10",
    "UK11",
    "UK12"
  ],
  "maxResults": 100,
  "updatedWithinDays": 14,
  "keywords": [],
  "buyerNames": [],
  "supplierNames": [],
  "cpvCodes": [],
  "performanceOutcomes": [],
  "enableChangeMonitoring": true,
  "outputMode": "all",
  "maxPages": 50,
  "pageSize": 100,
  "requestTimeoutSecs": 45,
  "maxRetries": 3,
  "minRequestIntervalMillis": 150
}
```

# Actor output Schema

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

UK9–UK12 performance, change, termination, and cancellation records.

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

Source scan counts, filters, delivery status, privacy statement, and change totals.

# 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("nordicdataforge/uk-public-contract-performance-monitor").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("nordicdataforge/uk-public-contract-performance-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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 nordicdataforge/uk-public-contract-performance-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=nordicdataforge/uk-public-contract-performance-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/ZdeuYZaE8lvNnF3fX/builds/CqswJtD2SIiQMeFhA/openapi.json
