# Uk Find A Tender Scraper (`kawsar/uk-find-a-tender-scraper`) Actor

Extract high-value UK procurement notices from Find a Tender. Filter by dates, keywords, CPV codes, or stages to track tenders, buyers, and contact details. Download your results directly in JSON, CSV, or Excel formats for your sheets or CRM.

- **URL**: https://apify.com/kawsar/uk-find-a-tender-scraper.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 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.
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 Find a Tender Scraper for High-Value Public Tenders](https://images.bigibyte.com/cdn-cgi/image/width=800,quality=80,format=auto/apify-actors-covers/uk-find-a-tender-scraper-cover.png)

## UK Find a Tender Scraper for High-Value Public Tenders

UK Find a Tender Scraper collects high-value UK procurement notices efficiently and structured for easy access. You can instantly export the extracted data into clean JSON, CSV, or Excel formats for your workflows.

### Use cases

- **Bid desks**: Pull new UK tender notices for a date window on a weekday morning.
- **CPV filters**: Keep notices whose classification ID matches the specific codes you target.
- **Buyer lists**: Export buyer names, emails, and postal codes whenever available.
- **Pipeline checks**: Match keywords across titles and descriptions without having to click through the site manually.
- **CSV handoff**: Download your dataset as a CSV or Excel spreadsheet for CRM imports or team reporting.

### What data does this actor extract?

You can collect tender data in two ways:

- **Releases by date**: Filter by start and end date windows with standard item caps.
- **Local filters**: Apply specific keywords, CPV code prefixes, and stage tags directly to refine your results.

Stage tags like `planning`, `tender`, and `award` help filter procurement notices to match the exact project phase you are looking for.

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `mode` | string | `releases` | Set to `releases` for date range extraction, or `filter` to match keyword, CPV, or tags. |
| `updatedFrom` | string | `2026-10-01T00:00:00` | Start date in ISO format. Leave empty to skip. |
| `updatedTo` | string | empty | End date in ISO format. Leave empty to skip. |
| `stages` | array | empty | Filter notices by stage tags locally. |
| `keyword` | string | empty | Match terms in tender titles and descriptions (filter mode). |
| `cpvPrefix` | string | empty | Classification ID prefix, e.g. `6411` (filter mode). |
| `maxItems` | integer | `100` | Maximum number of notice rows to collect (up to 1000). |
| `requestDelaySecs` | number | `1` | Pause duration between page fetches. |
| `userAgent` | string | kawsar research UA | Header sent on outgoing requests. |
| `timeoutSecs` | integer | `300` | Overall run execution time limit in seconds. |
| `requestTimeoutSecs` | integer | `30` | Timeout per individual request in seconds. |

#### Example input

```json
{
  "mode": "releases",
  "updatedFrom": "2026-10-01T00:00:00",
  "updatedTo": "",
  "maxItems": 100,
  "requestDelaySecs": 1,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "userAgent": ""
}

```

### Output

Notice records provide rich procurement details. Here is an example output structure:

```json
{
  "ocid": "ocds-h6vhtk-07853d",
  "id": "095881-2026",
  "date": "2026-10-11T22:16:50+01:00",
  "tag": ["tender"],
  "buyer_name": "Post Office Limited",
  "tenderTitle": "Post Office Branch - Sherwood",
  "tenderDescription": "Post Office Ltd is looking for a successful retailer to incorporate a Post Office Main into their existing or proposed business.",
  "buyer_email": "postmaster.onboarding@postoffice.co.uk",
  "buyer_postcode": "EC2V 7ER",
  "value": 33500,
  "url": "[https://www.find-tender.service.gov.uk/Notice/095881-2026](https://www.find-tender.service.gov.uk/Notice/095881-2026)",
  "scraped_at": "2026-10-12T00:00:00+00:00"
}

```

| Field | Type | Description |
| --- | --- | --- |
| `ocid` | string | Open Contracting ID. |
| `id` | string | Unique notice identifier. |
| `date` | string | Release date of the notice. |
| `tag` | array | Procurement stage tags. |
| `buyer_name` | string | Name of the purchasing organization. |
| `tenderTitle` | string | Title of the tender. |
| `tenderDescription` | string | Summary or description of the contract requirement. |
| `buyer_email` | string | Contact email address when available. |
| `buyer_postcode` | string | Postcode of the buyer address when available. |
| `value` | number | Estimated or awarded contract monetary value. |
| `url` | string | Direct web URL to view the notice on Find a Tender. |
| `scraped_at` | string | UTC timestamp when the record was collected. |

### How it works

1. Reads your configuration options including date windows and target items.
2. Iterates through standard notice pagination until reaching your target date, `maxItems` limit, or runtime cap.
3. Respects polite delay intervals between page requests to maintain reliable data extraction.
4. Deduplicates notice IDs and saves clean records in batches.
5. Soft errors on problematic pages are reported gracefully in output rows without interrupting the whole run.

### FAQ

**Can I export CSV?**
Yes. You can download the dataset directly as CSV or Excel from your dataset tab or through standard export links.

**How many notices can one run save?**
`maxItems` defaults to 100 records and can be set up to 1000 items.

**What happens if a request fails or returns an error?**
The scraper records an isolated error row with status details so you don't lose the rest of your collected dataset.

### Trademark Notice

UK Find a Tender and related names, logos, and trademarks belong to their respective owners. Their use in this documentation is solely to identify the source of the data and does not imply affiliation, sponsorship, endorsement, or partnership.

### Disclaimer

This tool is an independent tool and is not affiliated with, endorsed by, sponsored by, or otherwise officially associated with UK Find a Tender or its owners. All data is collected from publicly available sources. Users are responsible for complying with the source's terms of use, rate limits, and attribution or licensing requirements.

### Is web scraping legal?

This scraper only collects publicly available data from UK Find a Tender without bypassing access controls. Collecting public data is generally legal, but how you use it matters:

- **Personal data:** If the results include personal data (for example names, emails, or profile details), privacy regulations like GDPR may apply. Only collect and store personal data when you have a legitimate reason.
- **Copyright:** Some content (articles, images, detailed text) may be protected by copyright. Respect licensing conditions when reusing published information.
- **Terms of use:** Respect the source's terms, rate limits, and attribution requirements. Find a Tender notice data is offered under the Open Government Licence.
- **Legal advice:** This is general information, not legal advice. If you're unsure, consult a legal professional.

To learn more, read Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

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

releases downloads the public OCDS feed for a date window. filter downloads the same feed and keeps notices that match keyword, CPV prefix, or stage tags on your machine.

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

ISO 8601 start of the updatedFrom window sent to the OCDS releases endpoint. Leave empty to omit the parameter.

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

ISO 8601 end of the updatedTo window. Leave empty to omit the parameter and let the feed use its own upper bound.

## `stages` (type: `array`):

Local tag filter such as planning, tender, or award. Applied after download. This value is not sent as a query parameter because that parameter was not verified.

## `keyword` (type: `string`):

Used only in filter mode. Case-insensitive match against the tender title and tender text.

## `cpvPrefix` (type: `string`):

Used only in filter mode. Keeps notices whose CPV classification id starts with this prefix.

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

Maximum number of notice rows to save. Hard cap is 1000.

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

Seconds to wait between OCDS page requests. Default is 1 second.

## `userAgent` (type: `string`):

User-Agent sent on every request. Keep a contact address so the publisher can identify the client.

## `timeoutSecs` (type: `integer`):

Maximum seconds for the whole run. The actor stops fetching when this deadline is reached.

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

Maximum seconds to wait for a single HTTP response.

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

Optional proxy. Default is no proxy. Turn on Apify Proxy only if you need another IP.

## Actor input object example

```json
{
  "mode": "releases",
  "updatedFrom": "2026-10-01T00:00:00",
  "updatedTo": "2026-10-11T22:27:04",
  "stages": [],
  "keyword": "Post Office",
  "cpvPrefix": "6411",
  "maxItems": 100,
  "requestDelaySecs": 1,
  "userAgent": "",
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset of notice rows and any error rows.

# 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 = {
    "mode": "releases",
    "updatedFrom": "2026-10-01T00:00:00",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/uk-find-a-tender-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 = {
    "mode": "releases",
    "updatedFrom": "2026-10-01T00:00:00",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("kawsar/uk-find-a-tender-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 '{
  "mode": "releases",
  "updatedFrom": "2026-10-01T00:00:00",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call kawsar/uk-find-a-tender-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/uk-find-a-tender-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/sXeqhzRf5aKbfLiAR/builds/daL5oL8mwyQ6XjZHJ/openapi.json
