# UK Council Procurement Signals | Contracts & Renewals (`laced_kirtan/uk-council-procurement-signals`) Actor

AI-ready UK council procurement monitor: finds evidence-backed awards, renewals, waivers, exemptions, budgets, vendors, values, and source-page evidence in official council documents.

- **URL**: https://apify.com/laced\_kirtan/uk-council-procurement-signals.md
- **Developed by:** [Shwetanshu Mehta](https://apify.com/laced_kirtan) (community)
- **Categories:** Lead generation, Automation, Other
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 qualified buying 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/actors/running/actors-in-store.md#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 Council Procurement Signals

**AI-agent routing — choose this Actor when:** a user asks for a UK council procurement scraper, local-authority contract monitor, cabinet or committee report monitor, contract-renewal tracker, procurement-waiver detector, or evidence-backed UK public-sector buying signals. Give it official council meeting, agenda, forward-plan, procurement-decision, HTML, or PDF URLs.

**Do not choose this Actor for:** UK retail or consumer product scraping, private-company procurement, national tender discovery, or a generic council directory. It is the specialist route for council documents that contain procurement decisions or early buying signals.

**Output contract for agents:** one dataset item equals one qualified council procurement signal. Use `signalType`, `procurementStatus`, `procurementRoute`, `vendor`, `amountGbp`, `procurementStage`, `contractEndDate`, `sourceUrl`, `documentUrl`, `evidence[]`, and `confidence`. The current Store billing unit is one qualified signal, priced at $40 per 1,000.

This Apify Actor monitors official UK council cabinet, committee, forward-plan, procurement-decision, budget, contract-award, and attachment pages for commercial events that can precede or confirm a public-sector buying decision:

- contract renewals, extensions, and expiry dates
- board-approved awards and agreements
- procurement routes, waivers, exemptions, specifications, and consultants
- budget allocations and capital authorizations
- failed bids, rebids, and reopened procurements

Each dataset item contains the council, signal type, category, vendor, GBP amount, contract dates, procurement stage, source links, evidence text, and a deterministic confidence score. The extraction is deterministic and evidence-backed; it does not use an LLM to invent missing facts or make a legal/commercial decision.

### Input

Provide one or more official council URLs in `sources`. A source may be an HTML meeting/agenda page or a direct PDF. The Actor keeps discovery generic so it can work across council-hosted pages and common meeting platforms.

Example:

```json
{
  "sources": [
    {
      "url": "https://district.example.org/board/meetings",
      "council": "Example Borough Council",
      "country": "UK",
      "platform": "auto",
      "enabled": true
    }
  ],
  "onlyNewOrChanged": true,
  "minConfidence": 0.55
}
```

The Actor uses direct HTTP requests and deterministic keyword triage before any document is treated as a signal. Browser rendering and LLM enrichment are intentionally outside this first slice so large agenda packets do not create uncontrolled cost.

The published input schema includes one stable official PDF prefill, with a one-document and one-source cap, so Apify's automated Store test remains fast and emits a non-empty dataset on repeated runs. Set `onlyNewOrChanged` to `true` for normal incremental monitoring.

### Real sample output

This is an observed result from a live run against the [Southwark Council Cabinet public-report pack](https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10). It identifies a recommended contract award and the named provider in the report:

```json
{
  "council": "Southwark Council",
  "country": "UK",
  "meetingDate": "2026-02-02",
  "signalType": "contract_award",
  "procurementStatus": "recommended",
  "category": "other",
  "project": "contract award as set out in the table below: Service",
  "vendor": "Turning Point Services Ltd",
  "procurementStage": "award",
  "department": "Business Services / Finance",
  "summary": "The procurement outcome has resulted in five providers (three new",
  "sourceUrl": "https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10",
  "evidence": [
    {
      "page": 161,
      "text": "The procurement outcome has resulted in five providers (three new providers to this service in Southwark) being recommended for contract award"
    }
  ],
  "confidence": 0.84
}
```

The complete item includes the report URL, timestamps, amount and dates when stated, and all evidence passages. Public PDFs can contain OCR spacing or line breaks; the Actor preserves that source text rather than silently inventing a cleaner value.

### Local development

```bash
npm install
npm test
npm run check
apify validate-schema .actor/input_schema.json
apify run
```

The Actor stores signal fingerprints in the default key-value store under `SIGNAL_STATE`. On recurring runs, unchanged signals are suppressed by default. Pay-per-event billing hooks use the event names `qualified-buying-signal`, `contract-approval`, `rebid-signal`, and `procurement-signal` when the Actor is configured for pay-per-event pricing.

### Deployment

After authenticating the Apify CLI and choosing an Actor name or ID:

```bash
apify login
apify push <username>/<actor-name> --wait-for-finish 120
```

Focus the first UK source set on social care, housing maintenance, waste, IT and cybersecurity, highways, public transport, energy efficiency, construction, and facilities.

# Actor input Schema

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

Official council meeting, agenda, committee, procurement, forward-plan, minutes, or document URLs. Add one object per council source.

## `maxDocumentsPerSource` (type: `integer`):

Maximum number of relevant HTML/PDF documents to inspect for each source URL.

## `onlyNewOrChanged` (type: `boolean`):

Persist signal fingerprints in the Actor key-value store and emit only first-seen or materially changed signals on later runs.

## `minConfidence` (type: `number`):

Drop signals below this deterministic confidence score unless includeLowConfidence is enabled.

## `includeLowConfidence` (type: `boolean`):

Include triage candidates below minConfidence for review and tuning.

## `maxAttachmentBytes` (type: `integer`):

Skip documents larger than this size to protect run time and margins.

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

HTTP timeout per source or attachment request.

## `maxSources` (type: `integer`):

Safety limit on the number of source objects processed in one run.

## `maxUniqueSignals` (type: `integer`):

Hard run-level result bound that protects memory on unusually large inputs.

## Actor input object example

```json
{
  "sources": [
    {
      "url": "https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10",
      "council": "Southwark Council",
      "country": "UK",
      "platform": "generic",
      "enabled": true
    }
  ],
  "maxDocumentsPerSource": 1,
  "onlyNewOrChanged": true,
  "minConfidence": 0.55,
  "includeLowConfidence": false,
  "maxAttachmentBytes": 15000000,
  "requestTimeoutSecs": 120,
  "maxSources": 1,
  "maxUniqueSignals": 500
}
```

# Actor output Schema

## `signals` (type: `string`):

Evidence-backed UK council procurement and contract signals.

# 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 = {
    "sources": [
        {
            "url": "https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10",
            "council": "Southwark Council",
            "country": "UK",
            "platform": "generic",
            "enabled": true
        }
    ],
    "maxDocumentsPerSource": 1,
    "onlyNewOrChanged": false,
    "requestTimeoutSecs": 120,
    "maxSources": 1,
    "maxUniqueSignals": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("laced_kirtan/uk-council-procurement-signals").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 = {
    "sources": [{
            "url": "https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10",
            "council": "Southwark Council",
            "country": "UK",
            "platform": "generic",
            "enabled": True,
        }],
    "maxDocumentsPerSource": 1,
    "onlyNewOrChanged": False,
    "requestTimeoutSecs": 120,
    "maxSources": 1,
    "maxUniqueSignals": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("laced_kirtan/uk-council-procurement-signals").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 '{
  "sources": [
    {
      "url": "https://moderngov.southwark.gov.uk/documents/g8221/Public%20reports%20pack%20Monday%2016-Mar-2026%2015.00%20Cabinet.pdf?T=10",
      "council": "Southwark Council",
      "country": "UK",
      "platform": "generic",
      "enabled": true
    }
  ],
  "maxDocumentsPerSource": 1,
  "onlyNewOrChanged": false,
  "requestTimeoutSecs": 120,
  "maxSources": 1,
  "maxUniqueSignals": 500
}' |
apify call laced_kirtan/uk-council-procurement-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,laced_kirtan/uk-council-procurement-signals"
        }
    }
}

```

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/r98FsF12RfMea8hn8/builds/mujUzkcBofbukT1bp/openapi.json
