# EU TED & UK Find a Tender Scraper (`northloop-labs/public-tenders-monitor`) Actor

Monitor UK and EU public tenders from Find a Tender, Contracts Finder and TED in one clean feed. Filter by keyword, CPV, country, region, value, deadline and status, and get only new tenders on each scheduled run.

- **URL**: https://apify.com/northloop-labs/public-tenders-monitor.md
- **Developed by:** [Northloop Labs](https://apify.com/northloop-labs) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 tender 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/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

## EU TED & UK Find a Tender Scraper

**Find and monitor UK and EU public tenders from Find a Tender, Contracts Finder and TED in one clean, normalized feed.** Enter a keyword like `software` or a CPV code like `72000000`. You get every matching notice with its buyer, country, value, currency, CPV codes, publication date, bid deadline, status and links, in one dataset you can export to JSON, CSV, Excel or Google Sheets.

Turn on **Only new since last run** and schedule it daily, and it works like a tender alert: each run returns only the tenders you haven't seen yet.

The data comes from the three official sources, through their own open APIs:

| Source | Coverage |
|---|---|
| **Find a Tender (FTS)** | UK public procurement above and below threshold (Procurement Act 2023 notices) |
| **Contracts Finder** | UK contracts over £12k (central government) and £30k (wider public sector) |
| **TED (Tenders Electronic Daily)** | All EU/EEA tenders above the EU thresholds, in every EU language |

No API key, login or proxy is needed.

### What you can use it for

- **Bid and sales teams:** get a daily list of new tenders in your sector (CPV) and countries before your competitors see them.
- **Consultancies and bid writers:** find opportunities for clients and check who won similar contracts (status `awarded`, with winning suppliers).
- **Tender alert services and newsletters:** feed a Slack channel, CRM, Google Sheet or email digest through the Apify API, a webhook or an integration.
- **Market research:** track public spending by category, buyer and country over time.
- **SaaS and data products:** one normalized schema for three sources, so you skip writing three integrations.

### What data you get

| Field | Description |
|---|---|
| `title` | Tender title (original language). TED notices also have `titleEnglish` |
| `buyer`, `buyerCountry`, `buyerCity` | Contracting authority, ISO country code and city |
| `regions` | NUTS codes (and region names on Contracts Finder) of the place of performance |
| `status` | `open`, `closed`, `awarded`, `planned`, `cancelled`, `modified` or `changed` |
| `noticeType` | Notice type from the source, e.g. `cn-standard`, `tender`, `award, contract` |
| `published`, `deadline` | Publication date and bid deadline (ISO 8601) |
| `value`, `valueType`, `currency` | Estimated or awarded value in the notice's currency |
| `valueEur` | The value converted to EUR with ECB reference rates (for filtering and sorting) |
| `cpvCodes`, `cpvDescription` | CPV classification codes and the main CPV label |
| `procurementMethod`, `category` | Procedure (open, restricted, competitive flexible…) and goods/services/works |
| `awardedSuppliers` | Winning suppliers on award notices |
| `description` | Description of the procurement (cut to 3,000 characters by default) |
| `url`, `documentsUrl` | Notice page and the tender documents / bidding portal link |
| `source`, `sourceId`, `procedureId` | Source, notice ID and procedure ID (OCID on UK sources) |
| `alsoListedOn` | The same tender found on another source |
| `matchedKeyword` | Which of your keywords found it |

### How to search UK and EU public tenders

1. Enter one or more **keywords** (any of them can match) and/or **CPV codes**.
2. Optionally pick **countries** (`GB`, `DE`, `FR`, …), **regions** (NUTS codes such as `UKI` for London), a **value range** in EUR, and the **status**.
3. Choose the **date window** (default: the last 7 days) and **max results**.
4. Click **Start**. For alerts, turn on **Only new since last run** and add a schedule (for example every morning) in Apify.

#### Input example

```json
{
  "keywords": ["software", "cloud"],
  "cpvCodes": ["72000000"],
  "countries": ["GB", "IE", "DE"],
  "status": "open",
  "publishedWithinDays": 7,
  "deadlineNotPassed": true,
  "minValueEur": 50000,
  "onlyNew": true,
  "maxResults": 200
}
```

#### Output example

```json
{
  "title": "CPRD Feasibility Tool",
  "titleEnglish": null,
  "buyer": "MHRA",
  "buyerCountry": "GB",
  "buyerCity": "London",
  "regions": ["UK", "UKI42"],
  "status": "open",
  "noticeType": "tenderUpdate",
  "published": "2026-10-19T15:13:59+01:00",
  "deadline": "2026-11-19T14:00:00Z",
  "value": 3000000,
  "valueType": "estimated",
  "currency": "GBP",
  "valueEur": 3562733.8,
  "cpvCodes": ["48517000"],
  "cpvDescription": "IT software package",
  "procurementMethod": "Open procedure",
  "category": "goods",
  "awardedSuppliers": [],
  "suitableForSme": null,
  "description": "The requirement is for a white-labelled feasibility and population analytics platform, deployed within CPRD-managed Microsoft Azure infrastructure…",
  "url": "https://www.find-tender.service.gov.uk/Notice/098594-2026",
  "documentsUrl": "https://www.find-tender.service.gov.uk/Notice/Attachment/A-24343",
  "source": "find-a-tender",
  "sourceId": "098594-2026",
  "procedureId": "ocds-h6vhtk-0776f0",
  "alsoListedOn": [],
  "matchedKeyword": "software",
  "scrapedAt": "2026-10-19T20:17:42.045Z"
}
```

### Tender alerts: get only new tenders every day

With **Only new since last run** on, the Actor stores the IDs it has already returned in a named key-value store in your own Apify account (`public-tenders-monitor-state`). The next run skips them, so a daily schedule gives you a daily list of new tenders only, and you pay only for those. If a tender you have already seen is later **awarded**, it comes back once more with status `awarded` (when your status filter includes awarded notices).

The memory is kept per set of filters. Change your filters and you start a fresh list. Set **Monitor name** if you want to keep the same memory after editing them.

### How much does it cost?

This Actor uses **pay-per-event** pricing, so you only pay for what you get:

- **$0.005 per run** (Actor start)
- **$0.003 per tender saved** ($3 per 1,000 tenders)

Example: a daily alert that finds 20 new tenders costs about $0.065 per day. Duplicates between sources are merged before saving, so you never pay twice for the same tender. In monitoring mode, tenders you have already received are free. You can cap your spend with the maximum cost per run setting in Apify, and the Actor then saves only as many tenders as fit. Platform usage is included in the price.

### Tips

- **Keywords:** TED searches the full notice text in every EU language, so an English keyword also finds notices that use the English word anywhere, which gives broad results. Add local-language keywords (`Software`, `logiciel`, `oprogramowanie`) for better coverage, or turn on **Strict keyword match** for fewer, more relevant results.
- **CPV codes** are the most precise filter across languages. `72` = IT services, `48` = software packages, `45` = construction work, `79` = business services, `85` = health and social work.
- **Regions** take NUTS codes or prefixes: `UKI` London, `UKM` Scotland, `DE2` Bayern, `FR1` Île-de-France, `PL9` Mazowieckie.
- **Values** are compared in EUR. Many notices don't publish a value; switch off **Keep tenders without a published value** to drop them when you set a range.
- Find a Tender has no keyword search, so the Actor reads every notice in your date window (about 3,000 a week, roughly 30 seconds). Windows over 30 days take a few minutes on that source.
- Since the Procurement Act 2023 (February 2025) most new UK tenders appear on Find a Tender. Contracts Finder still carries many awards and smaller contracts.

### Use with AI agents, MCP, Make, Zapier, n8n and the API

#### AI agents and the Apify MCP server

Your AI agent can run this Actor as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp). In Claude, Cursor, VS Code or any other MCP client, add this server URL to load only this Actor:

```text
https://mcp.apify.com?tools=northloop-labs/public-tenders-monitor
```

You sign in to Apify on first connection. Agents that use the default server can also find the Actor with `search-actors` and run it with `call-actor`. Pass `maxTotalChargeUsd` in `callOptions` to cap what one run may cost. The Actor uses pay-per-event pricing, so it also works with Apify's agentic payments.

Example prompt: *"Find open UK and Irish IT tenders published this week worth over 100,000 EUR, with their deadlines."*

#### Make, Zapier and n8n

Apify has official integrations for [Make](https://docs.apify.com/platform/integrations/make), [Zapier](https://docs.apify.com/platform/integrations/zapier) and [n8n](https://docs.apify.com/platform/integrations/n8n). Use "Run Actor", pick `northloop-labs/public-tenders-monitor`, paste your input as JSON, and send the dataset items on to Google Sheets, Slack, a CRM or email. Inside Apify you can also connect Google Sheets or Slack, or add a [webhook](https://docs.apify.com/platform/integrations/webhooks) that fires when a run finishes.

#### API

Run it and get the results in one call (this endpoint waits up to 5 minutes, which suits small and medium runs):

```bash
curl -X POST "https://api.apify.com/v2/acts/northloop-labs~public-tenders-monitor/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["software"], "countries": ["GB", "IE"], "publishedWithinDays": 7, "maxResults": 100}'
```

Or with the Python client (`pip install apify-client`). The JavaScript client works the same way:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("northloop-labs/public-tenders-monitor").call(run_input={"keywords": ["software"], "countries": ["GB", "IE"], "publishedWithinDays": 7, "maxResults": 100})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

### Data & privacy

- The Actor collects only **public procurement notices** that the UK Government and the EU Publications Office publish as open data for anyone to reuse: titles, buyers (public bodies), values, CPV codes, dates, statuses, awarded supplier names (companies) and links.
- It deliberately **does not collect contact persons**: no contact names, email addresses or phone numbers from the buyer sections of the notices. Descriptions are copied as published, and a buyer may have written a contact address into the description text itself.
- Results are written **only to your own Apify account**: the run's default dataset, plus, in monitoring mode, a list of seen notice IDs in a named key-value store. The Actor sends the data nowhere else and keeps no copy. A small `RUN_SUMMARY` record holds only counts, queries and errors per source.

### Is it legal to use this data?

Yes, this is official open data. UK Find a Tender and Contracts Finder data is published under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/), and TED data can be reused free of charge under the European Commission's reuse policy (Decision 2011/833/EU). The Actor uses the official public APIs and does not log in or bypass access controls. If you republish the data, credit the source (for example "Contains public sector information licensed under the Open Government Licence v3.0"). You are responsible for how you use it, including the GDPR if you contact suppliers.

### FAQ

#### How much do tender alerts cost?

$0.003 per tender saved plus $0.005 per run start, with platform usage included. A daily alert that finds 20 new tenders costs about $0.065 a day, or about $2 a month. In monitoring mode, tenders you already received are free. Apify's free plan includes monthly usage credit you can spend on this Actor.

#### How do I get new tenders by email or Slack?

Turn on **Only new since last run** and add a daily schedule in Apify. Then connect the Slack integration in Apify, or send each run's results to email, Google Sheets or a CRM with Make, Zapier or n8n.

#### Which countries are covered?

The UK through Find a Tender and Contracts Finder, and the EU and EEA through TED, which carries every tender above the EU thresholds. Smaller tenders that appear only on national portals (for example Germany's or France's) aren't covered yet, and neither is the US.

#### How far back can I search, and how many tenders per run?

Up to 10,000 tenders per run (`maxResults`). `publishedWithinDays` goes up to 90 days, or set `publishedFrom` and `publishedTo` for a custom window. Windows over 30 days take a few minutes on Find a Tender.

#### Do I need a TED or Find a Tender account or API key?

No. All three sources are open APIs, so you need only your Apify account.

#### Can I get every tender without a keyword?

Yes. Without a keyword or CPV code the Actor falls back to the keyword `software`. Turn on `allowNoFilter` to get every notice in your date window, and narrow it by country, region, value or status.

#### Is it legal to use this data?

Yes, it's official open data. See "Is it legal to use this data?" above for the licences and how to credit the source.

#### Which export formats can I use?

Results land in an Apify dataset. Download them as JSON, JSONL, CSV, Excel, XML, HTML or RSS from the run page, or read them through the API, Make, Zapier, n8n or Google Sheets.

### How this Actor was made

This Actor was made with AI. An AI agent wrote and tested the code, this README and the store listing, and a human owns and maintains the Actor. It uses the official APIs: the Find a Tender OCDS release API, the Contracts Finder search API and the TED API v3 search. It maps all three into one schema and converts values to EUR with ECB reference rates.

### More Actors from Northloop Labs

- [Luma, Eventbrite & Meetup Events Scraper](https://apify.com/northloop-labs/tech-events-finder): tech, AI and startup events from Luma, Eventbrite and Meetup.
- [Greenhouse, Lever, Ashby & Workable Jobs Scraper](https://apify.com/northloop-labs/company-jobs-finder): open jobs from company career pages.
- [Google Ads Transparency Center Scraper](https://apify.com/northloop-labs/google-ads-transparency-library): a company's ads from the Google Ads Transparency Center.
- [Podcast Transcriber for RSS & Apple Podcasts](https://apify.com/northloop-labs/podcast-transcriber): podcast transcripts with timestamps and SRT subtitles.

### Feedback

Want another source, such as US SAM.gov, Germany's service.bund.de, France's BOAMP or Ireland's eTenders? Open an issue in the **Issues** tab and we will look at it.

# Actor input Schema

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

Tenders matching any of these keywords are returned. Every word of a keyword must appear (e.g. "cyber security"). TED searches the full notice text in all EU languages; for UK sources the title, description, buyer and CPV labels are searched. Leave empty if you filter by CPV code only.

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

Common Procurement Vocabulary codes or prefixes. "72000000" or "72" means all IT services, "48" all software packages. Child codes are included. Combined with keywords, a tender must match both (UK sources: a keyword match or a CPV match).

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

2-letter ISO codes of the buyer's country, e.g. GB, DE, FR, PL, IE. Empty = all. UK sources are only searched if GB is included (or the list is empty).

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

NUTS codes or prefixes of the place of performance (e.g. UKI = London, DE21 = Oberbayern, FR10 = Île-de-France), or region names for Contracts Finder (e.g. "London"). Empty = all.

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

Which official sources to search. All three by default.

## `status` (type: `string`):

open = calls for competition you can still bid on; awarded = contract award notices (with winning suppliers); planned = prior information / pipeline notices; all = every notice type.

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

Only notices published (or updated, for Find a Tender) in this many days. Ignored if Published from is set. Max 90.

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

Optional start date (YYYY-MM-DD). Overrides "Published in the last N days".

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

Optional end date (YYYY-MM-DD). Default: now.

## `deadlineNotPassed` (type: `boolean`):

Drop calls for competition whose bid deadline is already over. Tenders without a published deadline are kept.

## `minValueEur` (type: `integer`):

Minimum estimated (or awarded) value, converted to EUR with ECB reference rates (approximate for non-EUR notices).

## `maxValueEur` (type: `integer`):

Maximum estimated (or awarded) value in EUR.

## `includeNoValue` (type: `boolean`):

Many notices do not publish a value. When a value range is set, keep those (on) or drop them (off).

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

Remember which tenders were already returned (in a named key-value store in your account) and return only new ones. Use it with a schedule, e.g. daily. A tender that later gets awarded is returned again as awarded.

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

Optional name for the remembered state. By default it is derived from your filters, so different searches never share state. Set it to keep the same memory after editing filters.

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

Maximum number of tenders to save (newest first, mixed fairly across sources). You pay per tender saved.

## `strictKeywordMatch` (type: `boolean`):

Also require the keyword in the title or description (not just anywhere in the TED notice). Gives fewer, more relevant EU results; English keywords will then miss non-English notices.

## `descriptionMaxLength` (type: `integer`):

Cut descriptions to this many characters (0 = no limit).

## `allowNoFilter` (type: `boolean`):

When you give no keyword, CPV code, country or region, the search falls back to "software". Turn on to get every notice in the window instead.

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

Named key-value store for monitoring mode.

## `proxyConfiguration` (type: `object`):

Not needed: all sources are official open APIs. Only turn on if you see blocked requests.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "cpvCodes": [],
  "countries": [],
  "regions": [],
  "sources": [
    "find-a-tender",
    "contracts-finder",
    "ted"
  ],
  "status": "open",
  "publishedWithinDays": 7,
  "deadlineNotPassed": true,
  "includeNoValue": true,
  "onlyNew": false,
  "maxResults": 100,
  "strictKeywordMatch": false,
  "descriptionMaxLength": 3000,
  "allowNoFilter": false,
  "stateStoreName": "public-tenders-monitor-state",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Newest first: published, title, buyer, country, status, deadline, value and link.

## `details` (type: `string`):

Every field: CPV codes, regions, description, documents link, awarded suppliers and more.

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

Counts, queries and errors per source for this run (no tender data).

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northloop-labs/public-tenders-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 = { "keywords": ["software"] }

# Run the Actor and wait for it to finish
run = client.actor("northloop-labs/public-tenders-monitor").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"
  ]
}' |
apify call northloop-labs/public-tenders-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,northloop-labs/public-tenders-monitor"
        }
    }
}
```

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/EDIeUXfwqUAgbquUt/builds/t3LcKOCK5COScpyDJ/openapi.json
