# Planning Permission UK Scraper — Applications & Constraints (`muhammadafzal/planning-permission-uk-scraper`) Actor

Search the Planning Data API for England planning applications and constraints. Filter by postcode, UPRN, coordinates, geometry, date, authority, or reference. Returns typed records with proposals, decisions, addresses, and council links. For research, not legal advice. $0.005/record + $0.00005/run.

- **URL**: https://apify.com/muhammadafzal/planning-permission-uk-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Real estate, MCP servers, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 planning record returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Planning Permission UK Scraper

Search the official UK Planning Data API for structured planning applications and planning constraints. The actor is designed for planning consultants, property researchers, developers, solicitors, journalists, and AI agents that need public planning records in a stable JSON shape.

### What it does

The actor queries the public `planning.data.gov.uk` entity API and stores one normalized record per result. The default dataset is `planning-application`, but you can also request datasets such as `listed-building`, `conservation-area`, `green-belt`, `flood-risk-zone`, `article-4-direction-area`, or `tree-preservation-zone`.

The API currently provides England-focused coverage. Local planning authorities are not yet required to publish application data to the national specification, so coverage varies by authority. The actor preserves the official source URL and any council documentation URL so results can be audited.

### When to use it

- Find recent planning applications from a date range.
- Search applications or constraints around a postcode, UPRN, latitude/longitude point, or WKT polygon.
- Filter applications to a local planning authority entity or planning reference.
- Collect public decision, proposal, address, authority, and council portal links for property research.
- Feed typed planning records into an AI workflow, dashboard, CRM, or data warehouse.

Do not use this actor as a substitute for a local authority planning search, title investigation, environmental assessment, or legal advice. An empty result does not prove that no planning constraint or application exists.

### Input

The default input is intentionally runnable:

```json
{
  "datasets": ["planning-application"],
  "startDate": "2025-05-01",
  "maxResults": 100
}
```

Important fields:

| Field | Purpose |
| --- | --- |
| `datasets` | Official dataset slugs. Defaults to `planning-application`. |
| `postcodeOrUprn` | Search a UK postcode or UPRN, for example `BN15 0EE` or `10008315764`. |
| `reference` | Match an authority reference such as `AWDM/0550/25`. |
| `organisationEntity` | Restrict results to an LPA entity ID, such as `626195`. |
| `latitude`, `longitude` | Search around a WGS84 point. Supply both. |
| `geometryWkt` | Search a custom WGS84 WKT geometry. |
| `geometryRelation` | Spatial relation such as `intersects` or `within`. |
| `startDate`, `endDate` | ISO dates used for entity start-date filtering. |
| `maxResults` | Maximum records and result charges, from 1 to 1,000. |
| `responseFormat` | `concise` omits geometry WKT; `detailed` retains it. |

For constraint screening around a location:

```json
{
  "datasets": ["listed-building", "conservation-area", "green-belt"],
  "postcodeOrUprn": "SW1A 1AA",
  "maxResults": 50
}
```

For an application monitor:

```json
{
  "datasets": ["planning-application"],
  "startDate": "2025-05-01",
  "endDate": "2025-09-30",
  "maxResults": 100
}
```

### Output

Each dataset item contains stable, agent-friendly fields:

| Field | Description |
| --- | --- |
| `recordType` | `planning-application`, `planning-constraint`, or `planning-entity`. |
| `entityId`, `dataset`, `reference` | Official identity and dataset metadata. |
| `description`, `address` | Proposal or source description and address text. |
| `startDate`, `decisionDate`, `planningDecision` | Key application dates and decision outcome where supplied. |
| `organisationEntity` | Source planning authority entity ID where supplied. |
| `documentationUrl` | Direct council/source record link where supplied. |
| `sourceUrl` | Exact Planning Data API page used. |
| `warnings` | Non-fatal source coverage or missing-field notes. |

The `OUTPUT` key-value record contains the result count, API request and page counts, total available count when provided, event charges, source datasets, and warnings.

### Pricing

The actor charges:

- `$0.00005` for the actor-start event.
- `$0.005` per schema-valid planning record stored.

The maximum result charge is visible in the run status before records are requested. `maxResults` is a hard output and billing guard. Apify compute and proxy usage pricing may also apply according to the selected billing model.

### API and MCP use

The actor can be called through the Apify API or Apify MCP. A useful agent prompt is: “Find planning applications submitted since 2025-05-01 around BN15 0EE and return the council links.” The response is already shaped for retrieval and downstream filtering without exposing opaque source payloads.

### Reliability and limits

The implementation uses the public JSON API, bounded retries, polite pagination delays, and a 100-page ceiling. It does not bypass login walls, CAPTCHAs, or access controls. The national planning application specification is still evolving and data is incomplete in some areas; inspect `warnings`, `sourceUrl`, and `documentationUrl` before relying on a record.

If the source returns no matches, the actor completes with an empty dataset and a warning-level status. If every API request fails, the actor fails with an actionable run error so infrastructure or source outages are not mistaken for a genuine empty search.

### Legal and attribution notice

This is an independent data-access tool and is not affiliated with, endorsed by, or sponsored by the UK Government, MHCLG, Planning Data, or any local planning authority. The source dataset is published under the Open Government Licence v3.0 where stated by the source. You are responsible for complying with source terms, licence conditions, privacy law, and applicable planning or professional requirements.

# Actor input Schema

## `datasets` (type: `array`):

Use this to choose official Planning Data dataset slugs. Example: \['planning-application'] for applications or \['listed-building','conservation-area'] for constraints. Defaults to planning-application and accepts up to 10 slugs. This is not a council portal name or a free-text keyword search.

## `postcodeOrUprn` (type: `string`):

Use this to search by a UK postcode or Unique Property Reference Number. Example: 'BN15 0EE' or '10008315764'. Defaults to no location filter. This is not a council name, planning reference, or latitude/longitude pair.

## `reference` (type: `string`):

Use this to match an authority planning reference such as 'AWDM/0550/25'. Example: 'AWDM/0550/25'. Defaults to no reference filter. This is not the numeric Planning Data entity ID; use postcodeOrUprn or the dataset search for that.

## `organisationEntity` (type: `integer`):

Use this to restrict applications to a local planning authority entity ID from the Planning Data API. Example: 626195 for Lambeth in the official documentation. Defaults to no authority filter. This is not a council postcode or planning application reference.

## `latitude` (type: `number`):

Use this with longitude to search entities intersecting a point. Example: 51.5074. Defaults to no coordinate filter. This is WGS84 decimal latitude, not a British National Grid easting.

## `longitude` (type: `number`):

Use this with latitude to search entities intersecting a point. Example: -0.1278. Defaults to no coordinate filter. This is WGS84 decimal longitude, not a British National Grid northing.

## `geometryWkt` (type: `string`):

Use this for a custom WGS84 Well-Known Text geometry, such as 'POLYGON((-0.15 51.50,-0.10 51.50,-0.10 51.52,-0.15 51.52,-0.15 51.50))'. Defaults to no geometry filter. This is not GeoJSON; use coordinates for a single point.

## `geometryRelation` (type: `string`):

Use this to select the spatial relation between geometryWkt and returned entities. Example: 'intersects'. Defaults to intersects. This applies only to geometryWkt, not postcode, UPRN, or coordinates.

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

Use this as the inclusive lower date for entity start dates. Example: '2025-05-01'. Defaults to no lower date filter. This is an ISO date, not a council decision date or a relative phrase like 'last week'.

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

Use this as the upper date for entity start dates. Example: '2025-12-31'. Defaults to no upper date filter. This is an ISO date, not a planning decision date or a page number.

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

Use this to cap stored records and result-event charges. Example: 100. Defaults to 100 and accepts 1-1,000; the actor paginates the official API in pages of up to 100. This limits output rows, not the number of matching records available from the source.

## `responseFormat` (type: `string`):

Use detailed when you need geometry WKT retained, or concise for smaller AI-agent output. Example: 'detailed'. Defaults to detailed. This changes geometry inclusion only; applications and constraints use the same record fields.

## `requestDelayMs` (type: `integer`):

Use this to pace paginated requests to the public Planning Data API. Example: 250. Defaults to 250 milliseconds and accepts 100-5,000. This is not a browser wait, proxy setting, or total run timeout.

## Actor input object example

```json
{
  "datasets": [
    "planning-application"
  ],
  "postcodeOrUprn": "BN15 0EE",
  "reference": "AWDM/0550/25",
  "organisationEntity": 626195,
  "latitude": 51.5074,
  "longitude": -0.1278,
  "geometryWkt": "POLYGON((-0.15 51.50,-0.10 51.50,-0.10 51.52,-0.15 51.52,-0.15 51.50))",
  "geometryRelation": "intersects",
  "startDate": "2025-05-01",
  "endDate": "2025-12-31",
  "maxResults": 100,
  "responseFormat": "detailed",
  "requestDelayMs": 250
}
```

# Actor output Schema

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

One typed application, constraint, or planning entity per dataset item.

## `summary` (type: `string`):

Request, pagination, result, billing, and warning summary.

# 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 = {
    "datasets": [
        "planning-application"
    ],
    "postcodeOrUprn": "",
    "reference": "",
    "geometryWkt": "",
    "geometryRelation": "intersects",
    "startDate": "2025-05-01",
    "maxResults": 100,
    "responseFormat": "detailed",
    "requestDelayMs": 250
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/planning-permission-uk-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 = {
    "datasets": ["planning-application"],
    "postcodeOrUprn": "",
    "reference": "",
    "geometryWkt": "",
    "geometryRelation": "intersects",
    "startDate": "2025-05-01",
    "maxResults": 100,
    "responseFormat": "detailed",
    "requestDelayMs": 250,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/planning-permission-uk-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "datasets": [
    "planning-application"
  ],
  "postcodeOrUprn": "",
  "reference": "",
  "geometryWkt": "",
  "geometryRelation": "intersects",
  "startDate": "2025-05-01",
  "maxResults": 100,
  "responseFormat": "detailed",
  "requestDelayMs": 250
}' |
apify call muhammadafzal/planning-permission-uk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=muhammadafzal/planning-permission-uk-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/z4grTxrqHAzwRE26H/builds/ZXfTXTs4C9FUJz4JI/openapi.json
