# EU Public Contract Renewal & Re-Tender Radar (`steppedatatools/eu-contract-expiry-radar`) Actor

Spot awarded EU public contracts approaching their recorded end dates and investigate potential renewal, re-tender, recompete, and replacement opportunities earlier. Filter official TED data by buyer country, CPV code, award value, end date, and keywords.

- **URL**: https://apify.com/steppedatatools/eu-contract-expiry-radar.md
- **Developed by:** [Oralzhan Kaliyev](https://apify.com/steppedatatools) (community)
- **Categories:** Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.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.

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

## EU Public Contract Renewal & Re-Tender Radar

Spot awarded EU public contracts approaching their recorded end dates and investigate potential renewal, re-tender, recompete, and replacement-procurement opportunities earlier.

Instead of manually reviewing large volumes of TED notices, this Actor turns official TED procurement data into structured early-warning records that help you identify awarded contracts that may be worth monitoring next.

### What you get

Each matching record can show:

- contracting authority / buyer;
- current or awarded supplier, where disclosed;
- contract or lot title;
- recorded award value and currency;
- CPV classification;
- recorded contract end date;
- days remaining until expiry;
- expiry / renewal signal score;
- supporting-evidence score;
- mapping confidence;
- direct link to the official TED source.

The result is a searchable dataset of awarded contracts approaching recorded expiry — not just another feed of already-published tender notices.

### Choose what to monitor

Focus the search on the procurement markets relevant to you by filtering by:

- buyer country;
- CPV code or prefix;
- recorded award value;
- contract end date;
- expiry window;
- optional keywords.

Leave the buyer-country or CPV filters empty when you want to search across all supported TED countries or all CPV categories.

This makes the same Actor usable for cleaning, maintenance, security, IT, energy, insurance, waste services, medical supplies, vehicles, and many other public-procurement sectors.

### Why this is useful

Many suppliers discover an opportunity only after a new tender has already been formally published.

This Actor is designed to move the research stage earlier.

A recorded contract end date does **not** guarantee that a new tender will be published. However, it can be an early signal that a contracting authority may soon need to renew, extend, replace, recompete, or re-tender an existing service or supply contract.

The Actor converts those records into structured signals that can be searched, filtered, ranked, and monitored automatically.

Typical users include:

- B2B suppliers selling to the public sector;
- tender and bid teams;
- business-development teams;
- procurement-intelligence providers;
- market-research companies;
- lead-generation teams serving public-sector suppliers.

### Key output fields

| Field               | Meaning                                     |
| ------------------- | ------------------------------------------- |
| `changeType`        | New, changed, or untracked signal           |
| `contractEndDate`   | Recorded contract end date                  |
| `daysUntilExpiry`   | Days remaining until recorded expiry        |
| `contractTitle`     | Contract or lot title                       |
| `buyerName`         | Contracting authority / buyer               |
| `buyerCountry`      | Buyer country                               |
| `incumbentName`     | Current or awarded supplier where disclosed |
| `awardValue`        | Recorded award value                        |
| `currency`          | Award currency                              |
| `cpvCodes`          | Procurement classification codes            |
| `signalScore`       | Strength of the expiry / renewal signal     |
| `evidenceScore`     | Strength of supporting source evidence      |
| `mappingConfidence` | Confidence in lot / contract mapping        |
| `sourceUrl`         | Direct TED source                           |

### Monitor new and changed opportunities

The Actor can maintain state between runs.

With **Track new and changed signals** enabled, the Actor remembers previously seen records and can distinguish newly detected or materially changed signals from unchanged ones.

Use **Output mode** to control what a run returns:

- **All matching records** — return all contracts matching the current filters, including records seen in previous runs.
- **New or changed only** — return newly detected or materially changed records while suppressing unchanged ones.
- **New only** — return only records that have not been seen before.

#### Need to rebuild the full dataset?

If previous results were deleted, lost, or need to be downloaded again, select **All matching records** and run the Actor.

The Actor will return the full current set of records matching your filters, including records seen in earlier runs. This does not require resetting the monitoring history.

After rebuilding the dataset, you can switch **Output mode** back to **New or changed only** for ongoing monitoring.

This makes the Actor suitable for scheduled monitoring, alerts, email delivery, spreadsheets, dashboards, and downstream automation.

### Example: EU cleaning contracts

A ready-made public task is available for EU cleaning and sanitation contracts using CPV prefix `909`.

It is configured to monitor higher-value cleaning contracts and surface new or changed expiry / re-tender signals.

[Open EU Cleaning Contract Renewal & Re-Tender Radar](https://apify.com/steppedatatools/eu-contract-expiry-radar/examples/eu-cleaning-contract-expiry-radar)

[Gebäudereinigung Ausschreibungen Deutschland – Frühwarnsignale](https://apify.com/steppedatatools/eu-contract-expiry-radar/examples/gebaudereinigung-ausschreibungen-deutschland-fruhwarnsignale)

German-language page for €100k+ cleaning contract expiry and re-tender signals in Germany.

The same Actor can also be configured for IT, security, maintenance, energy, insurance, waste services, vehicles, medical supplies, and other procurement sectors by changing the CPV filter.

### Example input

````json
{
  "countries": [],
  "cpvCodes": ["909"],
  "keywords": [],
  "publishedFrom": "2019-01-01",
  "awardCurrency": "EUR",
  "minAwardValue": 100000,
  "maxItems": 1000,
  "strictLotMapping": true,
  "enableStateTracking": true,
  "outputMode": "new_or_changed"
}

# Actor input Schema

## `countries` (type: `array`):

ISO alpha-3 country codes, for example DEU, FRA, NLD. Leave empty for all TED countries.
## `cpvCodes` (type: `array`):

Full CPV codes or prefixes, for example 72 or 72000000 for IT services. Leave empty for all CPV categories.
## `keywords` (type: `array`):

Keep records containing at least one keyword in title, buyer, supplier, or CPV data.
## `expiryFrom` (type: `string`):

ISO date YYYY-MM-DD. Default: 90 days from run date.
## `expiryTo` (type: `string`):

ISO date YYYY-MM-DD. Default: 730 days from run date.
## `publishedFrom` (type: `string`):

ISO date YYYY-MM-DD. Older award notices may contain contracts still in force.
## `awardCurrency` (type: `string`):

Filter by the recorded award currency. Select ANY to accept all notice currencies. No FX conversion is performed.
## `minAwardValue` (type: `number`):

Minimum recorded award value in the selected award currency. If Award currency is ANY, the threshold is applied in each notice's own currency. No FX conversion is performed. Use 0 to include notices with missing or zero value.
## `maxItems` (type: `integer`):

Maximum number of records to save in the output dataset.
## `strictLotMapping` (type: `boolean`):

Skip multi-lot notices when contract dates, winners, values, or lot CPV data cannot be mapped safely. Recommended for reliable expiry signals.
## `enableStateTracking` (type: `boolean`):

Remember previously seen records across runs so repeated monitoring can return only newly detected or materially changed signals.
## `outputMode` (type: `string`):

all = every matching record; new_or_changed = suppress unchanged records; new_only = only unseen records.
## `stateStoreName` (type: `string`):

Named Apify key-value store used when change tracking is enabled.
## `rawQuery` (type: `string`):

Optional. When supplied, it replaces the automatically generated base query. Local expiry, CPV, value, and keyword filters still apply.

## Actor input object example

```json
{
  "countries": [],
  "cpvCodes": [],
  "keywords": [],
  "publishedFrom": "2019-01-01",
  "awardCurrency": "ANY",
  "minAwardValue": 1000,
  "maxItems": 20,
  "strictLotMapping": true,
  "enableStateTracking": false,
  "outputMode": "all",
  "stateStoreName": "eu-contract-expiry-radar-state"
}
````

# Actor output Schema

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

No description

## `summary` (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 = {
    "countries": [],
    "cpvCodes": [],
    "keywords": [],
    "publishedFrom": "2019-01-01",
    "minAwardValue": 1000,
    "maxItems": 20,
    "strictLotMapping": true,
    "enableStateTracking": false,
    "outputMode": "all"
};

// Run the Actor and wait for it to finish
const run = await client.actor("steppedatatools/eu-contract-expiry-radar").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 = {
    "countries": [],
    "cpvCodes": [],
    "keywords": [],
    "publishedFrom": "2019-01-01",
    "minAwardValue": 1000,
    "maxItems": 20,
    "strictLotMapping": True,
    "enableStateTracking": False,
    "outputMode": "all",
}

# Run the Actor and wait for it to finish
run = client.actor("steppedatatools/eu-contract-expiry-radar").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 '{
  "countries": [],
  "cpvCodes": [],
  "keywords": [],
  "publishedFrom": "2019-01-01",
  "minAwardValue": 1000,
  "maxItems": 20,
  "strictLotMapping": true,
  "enableStateTracking": false,
  "outputMode": "all"
}' |
apify call steppedatatools/eu-contract-expiry-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steppedatatools/eu-contract-expiry-radar"
        }
    }
}

```

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/jqotMwITTbegmj0cB/builds/SWyV5gdbhFXjSMGnD/openapi.json
