# London Planning Applications & Development Pipeline (`sweet-orb/london-planning-applications`) Actor

Search planning applications in all 33 London boroughs from the GLA's official Planning London Datahub. Get decisions, homes, affordable homes, floorspace, storeys, cost, developer and build dates. Filter by borough, date, status, size, keyword, postcode or radius. No personal data.

- **URL**: https://apify.com/sweet-orb/london-planning-applications.md
- **Developed by:** [Karol Olechno](https://apify.com/sweet-orb) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 planning 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/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

## London Planning Applications & Development Pipeline

Search every planning application in London. Results come from the Greater London Authority's official **Planning London Datahub**. It covers all 33 boroughs plus the London Legacy (LLDC), Old Oak and Park Royal (OPDC) and Oxford Street (OSDC) development corporations.

Each application comes back as one clean JSON record:

- status and decision;
- key dates;
- the development pipeline figures that UK-wide planning scrapers don't have: **proposed homes, affordable homes, floorspace by use class, storeys, building height, projected cost band, lead developer, and intended and actual start and completion dates**.

No login, no proxy, no browser. **No personal data**: no applicant or agent names, phone numbers or emails.

### What can you do with it?

- **Construction and supply-chain lead generation:** "approved schemes with 50+ homes in East London decided this quarter", with storeys, cost band and developer.
- **Development pipeline and market analysis:** count homes or floorspace in the pipeline by borough, tenure or use class. Track which schemes have started or completed.
- **Site due diligence:** "everything applied for within 300 m of this site in the last 5 years".
- **New-application alerts:** schedule a daily run on `dateFilterOn: "validated"` with `dateFrom: "1 day"`.
- **AI agents:** one tool call answers planning questions about London with structured, cited data (see [Use with AI agents](#use-with-ai-agents-mcp)).

### Data source and coverage

| | |
|---|---|
| Source | Planning London Datahub, Greater London Authority (live feeds from every London planning authority's back-office system, updated daily) |
| Coverage | ~1.3 million applications, all London planning authorities, records back to 2004 |
| Development details | Homes, floorspace, storeys, cost band, phasing and similar fields exist for applications submitted through the national Planning Portal since the Datahub launched (November 2020). Others have the core fields only. Use `onlyWithDevelopmentDetails` to keep only the rich records |
| Personal data | None. The GLA excludes personal information from the Datahub, and this Actor outputs no applicant or agent contact details |
| Freshness | Each run queries the live Datahub, so you get the latest records |

The data is supplied by applicants and councils. The Greater London Authority cannot warrant the quality or accuracy of the data. Check the council's own page (`councilApplicationUrl`) before relying on an individual record.

This Actor is independent. It is not endorsed by, affiliated with, supported or approved by the Greater London Authority.

### Input

Every filter is optional and filters combine with AND. With an empty input you get the newest 100 non-householder applications validated in the last 30 days.

| Field | What it does |
|---|---|
| `boroughs` | Planning authorities, e.g. `["Newham", "Tower Hamlets"]`. Empty = all of London |
| `keywords` / `excludeKeywords` | Phrases matched against the description, site name and scheme name, e.g. `["student accommodation", "data centre"]` |
| `dateFilterOn` | `validated` (new applications), `decided` (decision date) or `updated` (record changed) |
| `dateFrom` / `dateTo` | `YYYY-MM-DD` or a relative period like `"7 days"`, `"6 months"`. Default: last 30 days up to today |
| `statuses` | `pending`, `approved`, `refused`, `withdrawn`, `appeal`, `commenced`, `completed`, `lapsed` |
| `applicationTypes` | `full`, `priorApproval`, `householder`. Default excludes householder |
| `minProposedHomes` / `minFloorspaceGainedSqm` | Size thresholds |
| `costBands` | `Up to £2m`, `Between £2m and £100m`, `Over £100m` |
| `postcodes` | Full postcodes or districts, e.g. `["E15", "SE1 9SG"]`. Many records have no postcode, so for location searches prefer the radius filter |
| `nearLatitude` / `nearLongitude` / `radiusMeters` | Applications within a radius of a point |
| `sortBy` | `newest`, `oldest`, `mostHomes`, `largestFloorspace` |
| `maxResults` | Default 100, up to 50,000 |
| `includeGeometry` | Adds the site boundary as GeoJSON |
| `includeFullDetails` | Adds the complete raw development-details object (unit mix, tenures, parking, energy, open space) |

#### Example input

Approved schemes of 10+ homes in Newham and Tower Hamlets decided this year, biggest first:

```json
{
    "boroughs": ["Newham", "Tower Hamlets"],
    "statuses": ["approved"],
    "dateFilterOn": "decided",
    "dateFrom": "2026-01-01",
    "minProposedHomes": 10,
    "sortBy": "mostHomes",
    "maxResults": 25
}
```

### Output

One record per application, from a live run on 3 Nov 2026 (`description` shortened here):

```json
{
    "id": "Tower_Hamlets-PA_24_00812_A1",
    "planningAuthority": "Tower Hamlets",
    "reference": "PA/24/00812/A1",
    "applicationType": "All Other",
    "applicationTypeFull": "Full planning permission",
    "description": "Full phased planning application for redevelopment of the site following demolition of all existing buildings ... Purpose Built Student Accommodation ... Residential dwellings (Use Class C3) ...",
    "siteName": "Orchard Wharf, Orchard Place, London, E14",
    "schemeName": "Orchard Wharf",
    "address": "Orchard Wharf, Orchard Place, London, E14",
    "postcode": null,
    "ward": "Blackwall and Cubitt Town",
    "uprn": "6158219",
    "latitude": 51.508619,
    "longitude": 0.005106,
    "status": "Approved",
    "statusGroup": "approved",
    "decision": "Approved",
    "decisionDate": "2026-09-10",
    "validDate": "2024-06-03",
    "permissionLapsesDate": "2029-09-10",
    "workCommencedDate": null,
    "workCompletedDate": null,
    "proposedHomes": 1573,
    "existingHomes": 0,
    "netHomes": 1573,
    "proposedAffordableHomes": 208,
    "proposedBedrooms": 1812,
    "floorspaceGainedSqm": 79330,
    "floorspaceLostSqm": 1702.1,
    "floorspaceByUseClass": [
        { "useClass": "SG", "gainedSqm": 45875, "lostSqm": 0, "existingSqm": 0 },
        { "useClass": "C3", "gainedSqm": 20735, "lostSqm": 0, "existingSqm": 0 },
        { "useClass": "B2", "gainedSqm": 7524, "lostSqm": 0, "existingSqm": 0 }
    ],
    "siteAreaHa": 2.35,
    "maxStoreys": 25,
    "maxHeightM": 85.65,
    "projectedCostOfWorks": "Over £100m",
    "leadDeveloper": "Regal Orchard Wharf Limited",
    "intendedStartMonth": "2025-06",
    "intendedCompletionMonth": "2030-08",
    "councilApplicationUrl": "https://development.towerhamlets.gov.uk/online-applications/applicationDetails.do?keyVal=DCAPR144363&activeTab=summary",
    "lastUpdated": "2026-11-02T21:01:19.818Z",
    "source": "Planning London Datahub (Greater London Authority)",
    "sourceUrl": "https://planninglondondatahub.london.gov.uk/"
}
```

- Dates are `YYYY-MM-DD`.
- `statusGroup` normalises more than 100 council status spellings into a small set of values.
- Fields a council didn't supply are `null`.
- The dataset has two views: **Overview** and **Development pipeline**.
- The run also writes a `RUN_SUMMARY` record (matches, saved, requests) to the key-value store.

### Pricing

Pay per result, with no subscription and no start fee:

| Event | Price |
|---|---|
| `planning-application`: one application written to the dataset | **$0.02** ($20 per 1,000) |

- You only pay for records you receive. Filtered-out applications are free.
- The Actor never returns more records than your run's **maximum cost** allows; it stops cleanly at that limit.
- Examples:
  - a 25-result agent query costs $0.50;
  - a daily alert returning 40 new applications costs $0.80.

### Use with AI agents (MCP)

The input schema is written to be read by language models: every filter has a plain-English description and examples.

To give an agent (Claude, ChatGPT, Cursor and others) this Actor as a tool, add the Apify MCP server with only this Actor enabled:

```
https://mcp.apify.com/?tools=<username>/london-planning-applications
```

Example questions the agent can answer with a single call:

- "Which schemes of over 100 homes did Southwark approve in the last six months, and who are the developers?"
- "List planning applications within 500 m of 51.5416, -0.0098 since 2024 that mention student accommodation."
- "How many approved homes in Tower Hamlets have not started construction yet?"

Tips for agents:

- Keep `maxResults` small (10–50) for exploratory questions.
- Use `sortBy: "mostHomes"` for "largest schemes" questions.
- Use the radius filter rather than `postcodes` for "near" questions.

### Run it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/<username>~london-planning-applications/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"boroughs":["Hackney"],"statuses":["approved"],"dateFilterOn":"decided","dateFrom":"30 days","maxResults":50}'
```

### FAQ

**Why do some applications have no homes or floorspace figures?**
Those figures come from the London-specific questions on the Planning Portal application form. Applications submitted another way, older records, householder works, tree works and similar have only the core fields.

**Is this legal to use?**

- The Actor reads only the GLA's public, read-only Datahub API.
- It sends at most 2 requests per second and backs off when the service is busy.
- It returns no personal data.
- You are responsible for how you use the results.

**How fresh is the data?**
Councils' systems sync into the Datahub daily, and each run reads the live Datahub.

**Something looks wrong or a filter is missing?**
Open an issue on the Actor's Issues tab. Issues are answered within a few days.

# Actor input Schema

## `boroughs` (type: `array`):

Only return applications handled by these local planning authorities. Leave empty for all of London. Values are exact Datahub names, e.g. "Newham", "Tower Hamlets", "Kensington & Chelsea". LLDC = London Legacy Development Corporation, OPDC = Old Oak and Park Royal Development Corporation, OSDC = Oxford Street Development Corporation.

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

Return applications whose description, site name or scheme name contains ANY of these phrases (case-insensitive, whole-phrase match). Examples: "student accommodation", "data centre", "demolition", "solar", "hotel".

## `excludeKeywords` (type: `array`):

Drop applications whose description, site name or scheme name contains any of these phrases. Example: "tree works", "advertisement", "discharge of condition".

## `dateFilterOn` (type: `string`):

Which date "dateFrom" and "dateTo" apply to. "validated" = date the council validated (registered) the application, best for new-application alerts. "decided" = decision date, best for recent approvals or refusals. "updated" = last time the record changed in the Datahub, best for incremental syncs.

## `dateFrom` (type: `string`):

Earliest date, inclusive. Use YYYY-MM-DD (e.g. "2026-01-01") or a relative period meaning 'ago' (e.g. "7 days", "6 months", "2 years"). Default: "30 days". Records go back to 2004.

## `dateTo` (type: `string`):

Latest date, inclusive, as YYYY-MM-DD or a relative period meaning 'ago'. Default: today.

## `statuses` (type: `array`):

Only return applications in these normalised status groups. pending = received or under consideration; approved = approved, or allowed on appeal; refused = refused, or appeal dismissed; appeal = appeal in progress; commenced / completed = construction started or finished; lapsed = permission expired. Leave empty for any status.

## `applicationTypes` (type: `array`):

full = all full, outline, reserved-matters, listed-building, change-of-use and other non-householder applications; priorApproval = permitted-development prior approvals (e.g. office-to-residential); householder = extensions and alterations to single homes. Default: full + priorApproval (householder applications are excluded unless you add them).

## `minProposedHomes` (type: `integer`):

Only return schemes proposing at least this many residential units (C3 homes). Example: 10 for 'major' housing schemes, 150 for referable schemes. Only applications made through the national Planning Portal carry this figure.

## `minFloorspaceGainedSqm` (type: `integer`):

Only return applications that add at least this much gross internal floorspace in square metres, across all uses. Example: 1000 for 'major' commercial schemes.

## `costBands` (type: `array`):

Only return applications in these construction-cost bands, as declared on the application form.

## `onlyWithDevelopmentDetails` (type: `boolean`):

If true, skip applications that have no structured development data (homes, floorspace, storeys, cost band, phasing). Useful for construction-lead and pipeline analysis.

## `postcodes` (type: `array`):

Only return applications at these full postcodes (e.g. "E15 2GW") or in these postcode districts (outward codes, e.g. "E15", "SE1"). Matches any.

## `nearLatitude` (type: `number`):

Latitude (WGS84) of a London point. Use together with nearLongitude and radiusMeters to get applications around a site, e.g. 51.5416.

## `nearLongitude` (type: `number`):

Longitude (WGS84) of a London point, e.g. -0.0098.

## `radiusMeters` (type: `integer`):

Search radius around nearLatitude/nearLongitude, 10–50,000 metres. Default 500.

## `sortBy` (type: `string`):

newest / oldest = by the date chosen in "dateFilterOn"; mostHomes = largest housing schemes first; largestFloorspace = most floorspace gained first.

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

Stop after this many applications. You are charged per application returned, so keep this low for exploratory or agent queries. 1–50,000.

## `includeGeometry` (type: `boolean`):

Add the site boundary as a GeoJSON polygon (WGS84) in the "geometry" field. Makes records larger.

## `includeFullDetails` (type: `boolean`):

Add the complete raw Datahub "application_details" object (unit mix, tenures, parking, energy, open space, phasing and more) in "developmentDetails". Makes records much larger.

## Actor input object example

```json
{
  "keywords": [],
  "dateFilterOn": "validated",
  "dateFrom": "30 days",
  "applicationTypes": [
    "full",
    "priorApproval"
  ],
  "onlyWithDevelopmentDetails": false,
  "radiusMeters": 500,
  "sortBy": "newest",
  "maxResults": 100,
  "includeGeometry": false,
  "includeFullDetails": false
}
```

# Actor output Schema

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

All matching planning applications with every field (reference, borough, address, status, decision, homes, floorspace, storeys, height, cost, developer, dates, coordinates, council link).

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

The same applications in the compact overview view of the dataset.

# 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": [],
    "dateFrom": "30 days",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("sweet-orb/london-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 = {
    "keywords": [],
    "dateFrom": "30 days",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("sweet-orb/london-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 '{
  "keywords": [],
  "dateFrom": "30 days",
  "maxResults": 100
}' |
apify call sweet-orb/london-planning-applications --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sweet-orb/london-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/TkD5ubrZ6PJQ3007j/builds/gvcrBJIsZxAFlQ9ne/openapi.json
