# UK Planning Applications (`spookyweb/uk-planning-applications`) Actor

Planning applications from every UK council in one feed, classified by work type such as solar, extension or loft conversion, with site address, applicant and agent details.

- **URL**: https://apify.com/spookyweb/uk-planning-applications.md
- **Developed by:** [Dan](https://apify.com/spookyweb) (community)
- **Categories:** Lead generation, Real estate, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 applications

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 Planning Applications, All Councils

Planning applications from every UK local authority in one feed, tagged by the type of work, with applicant and agent details attached.

Planning data is normally scattered across more than 300 separate council portals, each with its own site and search. This Actor gives you the lot from a single search.

### What makes this useful

Every application is classified by the kind of work proposed, so you can pull just the jobs you care about instead of filtering thousands of records yourself:

`solar`, `extension`, `loft-conversion`, `new-dwelling`, `change-of-use`, `demolition`, `roofing`, `windows-doors`, `driveway-landscaping`, `trees`, `signage`, `listed-building`, `commercial`

Ask for `solar` in the last 7 days within 10km of a postcode and you get exactly that.

### Who uses it

**Solar and heat pump installers.** Every approved or pending solar application in your area, with the property address.

**Builders, roofers, window and extension firms.** Homeowners with planning permission for the work you do, at the moment they are looking for a contractor.

**Architects and planning consultants.** Track which agents are winning work in your patch using the applicant and agent search.

**Estate agents and property investors.** Spot new dwellings, conversions and land coming forward before they hit the market.

**Suppliers and merchants.** Development pipeline by area and size.

### Search options

Set at least one of `recentDays`, `startDate`, `areas`, `postcode`, `searchText` or `developerText`.

| Field | Description |
|---|---|
| `recentDays` | Applications from the last N days. 0 means today |
| `startDate`, `endDate` | Explicit date range, YYYY-MM-DD |
| `areas` | Comma separated council names, blank for all UK |
| `postcode`, `radiusKm` | Search around a postcode instead |
| `opportunityTags` | Only return these work types |
| `applicationState` | Undecided, Permitted, Rejected, Withdrawn, Conditions |
| `applicationSize` | Small, Medium, Large |
| `searchText` | Free text search of the description |
| `developerText` | Search applicant and agent names and addresses |
| `maxResults` | Hard cap on billable results |

### Output

One item per planning application.

| Field | Description |
|---|---|
| `reference`, `uid`, `name` | Council reference and the nationally unique id |
| `council` | Local authority |
| `address`, `postcode` | Site address |
| `latitude`, `longitude` | Site coordinates where the council publishes them |
| `description` | What is being applied for |
| `opportunityTags` | Classified work types |
| `applicationType`, `applicationState`, `applicationSize` | Type, decision status and scale |
| `startDate`, `decidedDate`, `decision` | Key dates and the outcome |
| `dwellings` | Number of dwellings, where stated |
| `ward`, `parish` | Local geography |
| `applicantName`, `applicantAddress` | Who is applying |
| `agentName`, `agentCompany`, `agentAddress` | Acting agent or architect |
| `caseOfficer` | Council case officer |
| `documentsUrl`, `councilUrl`, `planitUrl` | Links to the source records |
| `retrievedAt` | Retrieval timestamp |

Applicant and agent fields depend on what each council publishes, so they are not present on every record. Results are deduplicated within a run.

### Data source and fair use

Data comes from [PlanIt](https://www.planit.org.uk/), an independent service that aggregates UK local authority planning portals, and originates from the councils themselves. This Actor rate limits itself between requests. If you are pulling large volumes regularly, consider [supporting PlanIt](https://www.planit.org.uk/), since the service is free and volunteer run.

Applicant and agent names are published by councils as part of the statutory planning process. If you retain them you are responsible for your own lawful basis under UK GDPR.

### Postcode formats

Type the postcode however you have it. All of these reach the same place:

```
BS1 4DJ      bs1 4dj      BS14DJ       bs14dj
BS1-4DJ      BS1.4DJ      "BS1 4DJ"    BS1 4DJ.
```

Case, spacing and surrounding punctuation are all normalised before the search
runs. PlanIt itself rejects a postcode without its space, so this matters: it
answers `BS14DJ` with "No location found" rather than resolving it.

`GIR 0AA` is handled as the special case it is. An outward code on its own, such
as `BS1`, is passed through untouched rather than guessed at, and a full address
is left alone so it can be matched as text.

### Radius, and why a wide one fails

PlanIt's own data source gives up after 45 seconds and reports it as an error.
A radius above roughly 10km crosses that line most of the time, whatever date
range it is paired with. Measured against the same postcode:

| Radius | Result |
|--------|--------|
| 10km, 7 / 30 / 90 days | succeeds every time, around 42 seconds |
| 20km, 7 / 30 / 90 days | times out five attempts out of six |

The date range is not what costs the time, the radius is. A 90 day search at
10km returns fine. So keep the radius at 10 or below and run several searches
around different postcodes rather than one wide one. The actor retries an
upstream timeout, but each retry costs another 45 seconds, so it is not a
substitute for a sensible radius.

# Actor input Schema

## `recentDays` (type: `integer`):

Return applications submitted in the last N days. 0 means today only. Leave blank to use a specific date range instead.

## `startDate` (type: `string`):

Earliest application date, YYYY-MM-DD. Ignored if 'Applications from the last N days' is set.

## `endDate` (type: `string`):

Latest application date to return, as YYYY-MM-DD. Leave blank to search up to today. Pair it with the start date to pull a single week as a lead list.

## `areas` (type: `string`):

Comma separated council names, for example: Cambridge, Fylde, Southwark. Leave blank to search every UK council.

## `postcode` (type: `string`):

Search around a postcode instead of by council, for example CB1 2AB.

## `radiusKm` (type: `integer`):

Search radius around the postcode or coordinates. Keep this at 10 or below. PlanIt's own data source gives up after 45 seconds, and a radius above about 10km times out far more often than it succeeds, whatever date range you pair it with. Several smaller searches are faster and far more reliable than one wide one.

## `opportunityTags` (type: `array`):

Only return applications matching these work types. Leave empty for all.

## `applicationState` (type: `string`):

Filter by status. Undecided applications are the freshest leads.

## `applicationSize` (type: `string`):

Filter by scale of development as classified by PlanIt.

## `searchText` (type: `string`):

Free text search of the application description.

## `developerText` (type: `string`):

Search applicant and agent company names and addresses. Useful for tracking a competitor or a specific developer.

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

Hard cap on results. Each application is one billable result.

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

Records requested per API call. Leave as default unless you have a reason.

## Actor input object example

```json
{
  "recentDays": 7,
  "radiusKm": 5,
  "opportunityTags": [],
  "applicationState": "",
  "applicationSize": "",
  "maxResults": 500,
  "pageSize": 200
}
```

# 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 = {
    "recentDays": 7
};

// Run the Actor and wait for it to finish
const run = await client.actor("spookyweb/uk-planning-applications").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 = { "recentDays": 7 }

# Run the Actor and wait for it to finish
run = client.actor("spookyweb/uk-planning-applications").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 '{
  "recentDays": 7
}' |
apify call spookyweb/uk-planning-applications --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spookyweb/uk-planning-applications"
        }
    }
}

```

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/cefP5nrfbIEUc4LHf/builds/tl8hqj9ZUuJ3YhHdP/openapi.json
