# UK Brownfield Development Sites (`zinin/uk-brownfield-development-sites`) Actor

Find bounded, attributed brownfield-land records by exact English Local Planning Authority name using official Planning Data.

- **URL**: https://apify.com/zinin/uk-brownfield-development-sites.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 66.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 brownfield site delivereds

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?

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 Brownfield Development Sites

Turn one to five exact English Local Planning Authority names into bounded, attributed brownfield-land records from the official Planning Data service. Every Dataset row keeps source facts, Crown copyright attribution, an Open Government Licence link, and an explicit screening caveat together.

![Exact authority names become bounded, attributed official brownfield-site records](https://api.apify.com/v2/key-value-stores/gZrsNPA8E4rMSCRw9/records/store-authority-to-sites-workflow.png)

Use the Actor to build research watchlists, compare source-reported site characteristics, identify permission or deliverability segments, and feed repeatable property-marketing research. It does not identify owners or contacts and does not claim that a site is available, buildable, for sale, or suitable for investment.

In short, this is official register data for screening — not availability, buildability, owner data, valuation or advice.

### What this Actor delivers

- **Official brownfield-land facts.** Records come from `planning.data.gov.uk`, not scraped council pages, property listings, or an enrichment vendor.
- **Exact authority matching.** Supply one to five current English LPA names, including the `LPA` suffix shown by Planning Data.
- **Bounded results.** Return at most 100 matching records per requested authority and 500 records per run.
- **Useful source fields.** Site reference, name, address, point, known hectares, dwelling range, source-reported permission, deliverability, ownership category, notes, plan/history links, and source dates.
- **Traceable output.** Each row includes the matched authority, deterministic positions and ID, source count, truncation flag, attribution, licence URL, source URL, and caveat.
- **Fail-closed delivery.** All authority and site responses are validated before the complete result batch is written. `result-found` is charged only after successful Dataset delivery.

### Use cases for property marketers

- Build a repeatable brownfield-market watchlist by LPA.
- Compare source-reported permission, deliverability, known area, or dwelling-range segments.
- Prioritize authorities and themes for factual market research or content planning.
- Feed an internal CRM, spreadsheet, data warehouse, Make scenario, or n8n workflow with attributed records.
- Refresh an authorized research dataset without copying facts manually from multiple records.

The output is a screening input. Any outreach, acquisition, development, valuation, planning, lending, legal, or investment decision requires independent verification and the appropriate professional advice.

### Input

| Field | Required | Limits | Meaning |
| --- | --- | --- | --- |
| `localPlanningAuthorities` | Yes | 1–5 unique names | Exact current Planning Data authority names, such as `Lambeth LPA`. Matching is case-insensitive after safe text normalization, but abbreviations and approximate names are not inferred. |
| `maxSitesPerAuthority` | Yes | Integer 1–100 | Maximum deterministic matching records retained for each authority. |
| `permissionStatus` | Yes | Unique values from the closed list | Optional local filter: `PERMISSIONED`, `PENDING_DECISION`, `NOT_PERMISSIONED`, or `SOURCE_OTHER`. Use `[]` for every source status. |
| `deliverability` | Yes | Unique values from the closed list | Optional local filter: `DELIVERABLE`, `NOT_DELIVERABLE`, `UNKNOWN`, or `SOURCE_OTHER`. Use `[]` for every source value. |
| `minimumHectares` | Yes | 0–10,000; four decimal places | Include only records with a known official hectares value at or above the threshold. |
| `acknowledgeScreeningOnly` | Yes | Must be `true` | Confirms that records are factual screening data and not availability, buildability, title, legal, planning, valuation, finance, or investment advice. |

Unknown fields, duplicate normalized authority names, unsafe text, unrecognized filter values, over-limit requests, and a false acknowledgement reject the input before any result is delivered.

### Output

![Each delivered site keeps its source facts, attribution, licence, and screening caveat together](https://api.apify.com/v2/key-value-stores/gZrsNPA8E4rMSCRw9/records/store-attributed-site-record.png)

The default Dataset contains zero to 500 closed `BROWNFIELD_SITE` rows. A successful row contains:

| Group | Fields |
| --- | --- |
| Identity | `rowId`, `officialEntityId`, `reference`, `siteName`, `siteAddress` |
| Location and scale | `point`, `hectares`, `dwellingRange` |
| Source classifications | `deliverability`, `ownershipCategory`, `planningPermission` |
| Supporting source facts | `notes`, `sitePlanUrl`, `planningPermissionHistoryUrls`, `sourceDates` |
| Query trace | `requestedAuthority`, `matchedAuthorityEntities`, `authorityPosition`, `resultPosition`, `sourceReportedCount`, `truncated` |
| Rights and boundary | `attribution`, `licenceUrl`, `sourceUrl`, `caveat` |

Representative shape:

```json
{
  "schemaVersion": "1.0",
  "rowType": "BROWNFIELD_SITE",
  "rowId": "64-character deterministic SHA-256 value",
  "sourceDataset": "brownfield-land",
  "officialEntityId": 1705636,
  "reference": "BLR001",
  "siteName": "Example source-reported site name",
  "siteAddress": "Example source-reported site address",
  "point": { "longitude": -0.109462, "latitude": 51.460578 },
  "hectares": 1.61,
  "dwellingRange": { "minimum": 304, "maximum": 304 },
  "deliverability": "DELIVERABLE",
  "ownershipCategory": "MIXED",
  "planningPermission": {
    "status": "PERMISSIONED",
    "type": "FULL",
    "date": "2017-03-23"
  },
  "requestedAuthority": { "name": "Lambeth LPA", "entity": 626195 },
  "truncated": false,
  "attribution": "© Crown copyright and database right 2026",
  "licenceUrl": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
  "sourceUrl": "https://www.planning.data.gov.uk/dataset/brownfield-land"
}
```

Nullable source fields remain `null`; they are not guessed. Equal records matched through multiple requested authority boundaries collapse to one row with all matched authority entity IDs. Conflicting duplicate source facts fail the run instead of silently choosing one version.

### Quick start

The prepared Task **Find Lambeth brownfield sites** (`find-lambeth-brownfield-sites`, Task ID `k02gAzIVW4wunC9WS`) uses a useful 25-row-per-authority cap:

```json
{
  "localPlanningAuthorities": ["Lambeth LPA"],
  "maxSitesPerAuthority": 25,
  "permissionStatus": [],
  "deliverability": [],
  "minimumHectares": 0,
  "acknowledgeScreeningOnly": true
}
```

To use another area, replace `Lambeth LPA` with the exact current name exposed by Planning Data. Leave both filter arrays empty for all source classifications, then narrow only when the source categories fit your research question.

### Make integration

1. Add an HTTP **Make a request** module.
2. Send `POST https://api.apify.com/v2/acts/8LM9F77bAJNsbOgVJ/runs?token=YOUR_APIFY_TOKEN&waitForFinish=240` with `Content-Type: application/json` and the Actor input as the request body.
3. Read `data.defaultDatasetId` from the response.
4. Fetch `GET https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json`.
5. Route only the factual fields your workflow needs and retain `attribution`, `licenceUrl`, `sourceUrl`, and `caveat` with exported records.

For longer-running automation, start without `waitForFinish`, poll the returned run ID until it reaches a terminal status, and fetch items only after `SUCCEEDED`.

### n8n integration

Use one **HTTP Request** node to start Actor ID `8LM9F77bAJNsbOgVJ`, an **If/Wait** loop to require `SUCCEEDED`, and a second **HTTP Request** node to retrieve default Dataset items. Keep the input object closed: do not add credentials, contacts, personal data, or free-form confidential notes to Actor fields.

If a workflow uses filters, store their exact enum values in version-controlled configuration. Treat a successful zero-row run as a valid result for the selected authority and filters, not as proof that an authority has no brownfield sites.

### API example

Start a run:

```bash
curl --request POST \
  'https://api.apify.com/v2/acts/8LM9F77bAJNsbOgVJ/runs?token=YOUR_APIFY_TOKEN&waitForFinish=240' \
  --header 'Content-Type: application/json' \
  --data '{
    "localPlanningAuthorities": ["Lambeth LPA"],
    "maxSitesPerAuthority": 25,
    "permissionStatus": [],
    "deliverability": [],
    "minimumHectares": 0,
    "acknowledgeScreeningOnly": true
  }'
```

Then retrieve the Dataset using the returned `defaultDatasetId`:

```bash
curl 'https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json&token=YOUR_APIFY_TOKEN'
```

Do not put a long-lived token in a shared URL, README, log, or spreadsheet. Use your automation platform's secret store and the narrowest practical Apify token permissions.

### Data source and attribution

The Actor reads the official [Planning Data brownfield-land dataset](https://www.planning.data.gov.uk/dataset/brownfield-land) and the Planning Data entity API at `https://www.planning.data.gov.uk/entity.json`. It does not crawl council websites, follow site-plan/history links, query property portals, or use an external enrichment or model service.

Every delivered row includes:

- `© Crown copyright and database right 2026`;
- the [Open Government Licence version 3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/) URL;
- the official dataset URL; and
- a caveat that coverage, freshness, permission, deliverability, and ownership categories are source facts rather than guarantees.

You remain responsible for complying with the licence, retaining required attribution, checking whether linked third-party material has separate rights, and verifying current primary records before relying on them.

### Screening and advice boundary

`PERMISSIONED`, `DELIVERABLE`, `PUBLIC_AUTHORITY`, and other normalized values describe source-reported categories. They do not establish that land is currently available, buildable, correctly titled, owned by a named party, for sale, financeable, or appropriate for a particular project.

The Actor performs no title search, ownership/contact inference, valuation, viability model, contamination assessment, constraint analysis, planning advice, legal advice, lending advice, or investment recommendation. It does not send outreach, submit planning applications, or make automated decisions.

### Pricing

Pay Per Event has one automatic `apify-actor-start` charge and one primary `result-found` charge per successfully delivered factual brownfield site row.

| Tier | Actor start | Each delivered row | 25-row Task maximum | 500-row hard maximum |
| --- | ---: | ---: | ---: | ---: |
| FREE | $0.01300 | $0.00200 | $0.06300 | $1.01300 |
| BRONZE | $0.01235 | $0.00190 | $0.05985 | $0.96235 |
| SILVER | $0.01170 | $0.00180 | $0.05670 | $0.91170 |
| GOLD | $0.01105 | $0.00170 | $0.05355 | $0.86105 |
| PLATINUM | $0.01066 | $0.00164 | $0.05166 | $0.83066 |
| DIAMOND | $0.01040 | $0.00160 | $0.05040 | $0.81040 |

The 25-row Task maximum is one start plus 25 delivered rows. The hard maximum is one start plus 500 delivered rows. Actual result charges are lower when fewer rows are delivered; a valid zero-row result has no `result-found` charge. Input/source failure before Dataset delivery also produces no paid result charge. Apify displays the tier applicable to your account.

### Privacy and retention

The input needs exact authority names and fixed filters only. Do not submit personal data, owner/contact details, credentials, confidential prose, or any information you lack the right to process.

Apify stores the original run `INPUT` in the run's default Key-Value Store and delivered rows in the default Dataset. Account permissions and Apify retention settings govern access and retention. The Actor does not erase those platform records. Configure retention, exports, and deletion for your own obligations.

The Actor never writes buyer input values, complete source bodies, site addresses, or source notes to logs or status messages.

### FAQ

#### Why did I get `authority_not_found`?

The name must match a current Planning Data Local Planning Authority name after safe normalization. Include the displayed suffix, for example `Lambeth LPA`; the Actor does not guess abbreviations or nearby authorities.

#### Why did a successful run return zero rows?

The official response may contain no records for that authority, or your permission, deliverability, or minimum-hectares filters may exclude every validated row. Zero rows is not proof that no relevant land exists outside the source or selected filters.

#### What does `truncated: true` mean?

The source reported or returned more matching rows than `maxSitesPerAuthority` retained for that authority, or the bounded source request indicated additional records. Increase the cap up to 100 if the wider result fits your use case.

#### Can this Actor find owners, emails, phone numbers, or agents?

No. Ownership is a source category such as `PUBLIC_AUTHORITY`, `NOT_PUBLIC_AUTHORITY`, or `MIXED`; it is not an owner identity or contact lead. The Actor performs no owner or contact inference.

#### Does a permissioned or deliverable row mean I can develop the site?

No. Those are normalized source-reported facts. Check current planning records, title, constraints, viability, availability, rights, and professional advice independently.

#### Why did the run fail instead of returning partial rows?

The Actor validates all authority and site responses before its single Dataset write. Invalid, oversized, mistyped, conflicting, or unavailable source data fails closed so a partial batch is not presented as complete.

### Limits and completeness

- Coverage and freshness are limited to what Planning Data published when the run queried it.
- Authority names and boundaries can change; exact current names are required.
- Result ordering is deterministic for validated source data, but source facts may change between runs.
- At most five authorities, 100 retained records per authority, and 500 delivered records per run are supported.
- The minimum-hectares filter excludes records whose hectares value is unavailable.
- Site plan and permission-history URLs are source facts; the Actor neither follows nor validates the content behind them.
- Permission, deliverability, ownership, dwelling, area, and date fields may be missing, historical, inconsistent with other registers, or subsequently superseded.
- `sourceReportedCount` and `truncated` describe the bounded source response and selected result, not universal market completeness.
- This is factual screening data, not legal, title, planning, valuation, finance, lending, development, or investment advice.

For operational use, preserve the attribution and caveat, record the run time and Dataset ID, compare refreshes explicitly, and verify current primary sources before taking action.

# Actor input Schema

## `localPlanningAuthorities` (type: `array`):

Exact current authority names from Planning Data, including any LPA suffix; one source query is made per matched authority.

## `maxSitesPerAuthority` (type: `integer`):

Return the deterministic first 1–100 matching official records per authority.

## `permissionStatus` (type: `array`):

Optional local filter; leave empty to include every source status.

## `deliverability` (type: `array`):

Optional local filter; leave empty to include every source value.

## `minimumHectares` (type: `number`):

Include only records whose official hectares value is present and at least this number.

## `acknowledgeScreeningOnly` (type: `boolean`):

Required and must remain true: records are factual screening data, not availability, buildability, title, legal, valuation, finance or investment advice. False is rejected by the runtime.

## Actor input object example

```json
{
  "localPlanningAuthorities": [
    "Lambeth LPA"
  ],
  "maxSitesPerAuthority": 100,
  "permissionStatus": [],
  "deliverability": [],
  "minimumHectares": 0,
  "acknowledgeScreeningOnly": true
}
```

# Actor output Schema

## `brownfieldSites` (type: `string`):

Attributed official records with source facts, truncation flags and screening caveats.

# 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 = {
    "localPlanningAuthorities": [
        "Lambeth LPA"
    ],
    "maxSitesPerAuthority": 100,
    "permissionStatus": [],
    "deliverability": [],
    "minimumHectares": 0,
    "acknowledgeScreeningOnly": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/uk-brownfield-development-sites").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 = {
    "localPlanningAuthorities": ["Lambeth LPA"],
    "maxSitesPerAuthority": 100,
    "permissionStatus": [],
    "deliverability": [],
    "minimumHectares": 0,
    "acknowledgeScreeningOnly": True,
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/uk-brownfield-development-sites").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 '{
  "localPlanningAuthorities": [
    "Lambeth LPA"
  ],
  "maxSitesPerAuthority": 100,
  "permissionStatus": [],
  "deliverability": [],
  "minimumHectares": 0,
  "acknowledgeScreeningOnly": true
}' |
apify call zinin/uk-brownfield-development-sites --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/uk-brownfield-development-sites"
        }
    }
}

```

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/8LM9F77bAJNsbOgVJ/builds/hsygNxM7Y7SOXaEdq/openapi.json
