A validated planning application means a council has accepted a proposal as complete and building work may be coming. For builders, scaffolders, architects, roofers and other trades, that is an early, public signal of a project.
The friction is the portals. Each council publishes its own weekly lists on its own site, with search forms that differ in small ways, so watching even a handful of areas every week takes real time, and copying results into a spreadsheet takes more.
This guide shows how to turn those weekly lists into a lead feed: checking coverage, choosing validated or decided applications, filtering proposals for your trade, pulling out postcodes and running it on a schedule without repeats.
Step by step
Check that your area is covered
The actor reads 15 council portals: Isle of Wight, Durham, Barnet (London), Leeds, York, Cornwall, Trafford, Gateshead, Bradford, Aberdeen, Aberdeenshire, Sunderland, Southampton, Greater Cambridge and Oxford. Use the lowercase ids in councils, for example leeds or greater-cambridge, or leave the field empty for all 15.
Pick validated or decided applications
For lead generation, use dateType validated: these are newly accepted applications, so the project is live and decisions are still ahead. Use decided if you sell to people who have just been granted permission, or to track approvals in an area.
{ "councils": ["trafford", "barnet"], "dateType": "decided", "weeksBack": 1, "maxResults": 300 }Fetch at least one full week
Weekly lists roll over on Mondays, so the newest list can be nearly empty early in the week. Set weeksBack to 2 so each run always includes a complete week. Each weekly list is read up to 20 result pages, about 200 applications, which covers a normal week for most councils.
Filter proposals for the work you do
The proposal field holds the council's description of the work, such as 'Erection of single storey rear extension and conversion of garage to habitable room'. A simple keyword filter separates likely jobs from tree works and signage. Adjust the pattern list to your trade.
import os import re from apify_client import ApifyClient PATTERNS = re.compile(r"extension|loft|dormer|conversion|new dwelling|erection of", re.I) EXCLUDE = re.compile(r"\btree\b|advertisement|signage", re.I) client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("actor-forge/uk-planning-applications").call(run_input={ "councils": ["leeds", "bradford", "york"], "dateType": "validated", "weeksBack": 2, "maxResults": 1000, }) leads = [] for app in client.dataset(run["defaultDatasetId"]).iterate_items(): text = app.get("proposal") or "" if PATTERNS.search(text) and not EXCLUDE.search(text): leads.append(app) for app in leads: print(app["council"], app["reference"], "|", app["address"], "|", app["url"]) print(len(leads), "matching applications")Pull out postcodes for routing and mapping
Site addresses usually end with a UK postcode, as in 'Land Adjacent To 6 Withyfields Shalfleet Newport Isle Of Wight PO30 4QA'. Extracting the postcode lets you sort leads by district, assign them to a rep or plot them on a map.
import re POSTCODE = re.compile(r"\b([A-Z]{1,2}\d[A-Z\d]?)\s*(\d[A-Z]{2})\b", re.I) def postcode(address): m = POSTCODE.search(address or "") return f"{m.group(1).upper()} {m.group(2).upper()}" if m else None def district(address): pc = postcode(address) return pc.split()[0] if pc else None print(postcode("12 Example Road Oxford OX4 1AB"), district("12 Example Road Oxford OX4 1AB"))Schedule weekly runs without repeats
Schedule the actor every Monday morning with weeksBack 2. Because consecutive runs overlap by a week, deduplicate on the council plus reference pair before sending leads on, so the same application is not followed up twice. Every row links to the council's own application page, where your team can read the documents.
Follow up through the right channels
Applicant and agent personal details are deliberately not collected, so the dataset gives you the site, the proposal and the link, not a contact list. Use the address and the council record to plan how you reach the project, and keep your outreach within data protection and marketing rules.
Sample input
{
"councils": [
"leeds"
],
"weeksBack": 2,
"dateType": "validated",
"maxResults": 200
}Sample output
Applications from every council share one layout with a deep link to the official record:
| council | reference | proposal | address | status | validatedDate | url |
|---|---|---|---|---|---|---|
| isle-of-wight | 26/00909/TW | T1; Ash - Dismantle to near ground level and replant with tree in keeping with the area… | Land Adjacent To 6 Withyfields Shalfleet Newport Isle Of Wight PO30 4QA | Registered | Fri 03 Jul 2026 | https://publicaccess.iow.gov.uk/online-applications/applicationDetails.do?keyVal=… |
| oxford | 26/01423/FUL | Erection of single storey rear extension and conversion of garage to habitable room | 12 Example Road Oxford OX4 1AB | Registered | Tue 30 Jun 2026 | https://public.oxford.gov.uk/online-applications/applicationDetails.do?keyVal=… |
Run it from code
cURL
curl -X POST "https://api.apify.com/v2/acts/actor-forge~uk-planning-applications/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"councils": ["leeds"], "weeksBack": 2, "dateType": "validated", "maxResults": 200}'JavaScript (Node.js)
// Node.js 18+ (built-in fetch). Set APIFY_TOKEN in your environment.
const input = {
"councils": [
"leeds"
],
"weeksBack": 2,
"dateType": "validated",
"maxResults": 200
};
const res = await fetch(
"https://api.apify.com/v2/acts/actor-forge~uk-planning-applications/run-sync-get-dataset-items",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
}
);
const items = await res.json();
console.log(items.length, items[0]);Python
# pip install apify-client (set APIFY_TOKEN in your environment)
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run_input = {
"councils": [
"leeds"
],
"weeksBack": 2,
"dateType": "validated",
"maxResults": 200
}
run = client.actor("actor-forge/uk-planning-applications").call(run_input=run_input)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)The run-sync-get-dataset-items endpoint waits for the run (up to 5 minutes) and returns the dataset rows directly. For longer runs, start the run asynchronously and read the dataset when it finishes, as the Python example does. Replace APIFY_TOKEN with your own token from the Apify console.
What it costs
At $0.003 per application, a typical single-council week of about 25 applications costs around $0.08. If three councils produce 400 validated applications across two weeks, that run costs 400 x $0.003 = $1.20.
| Charged for | When | Price | Per 1,000 | Worked example |
|---|---|---|---|---|
| Planning application | One planning application (reference, address, proposal, status, dates, council) from a UK council portal. | $0.003 | $3 | 1,000 applications = $3.00; a typical single-council week (≈25 applications) = $0.08 |
| Actor Start (platform start fee) | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). | $0.00005 | — | One run at up to 1 GB = $0.00005 (charged as one event) |
Ready to try it? UK Planning Applications Scraper — 15 Councils, Weekly Leads runs on Apify, pay per result.
Run on Apify → Read the full actor pageTips and pitfalls
- A council portal outage only affects that council; it is flagged in the run log and exit message and the rest of the run continues.
- Busy weeks at a large council can be cut off after about 200 applications, so check the count if a big council looks light.
- Decided lists are useful a second time: an approved extension that you quoted for is a reason to follow up.
- The actor makes no more than one request per second per council portal, so all-council runs take a little longer than single-council ones.
FAQ
Are UK planning applications public information?
Councils publish weekly lists of applications on their planning portals. The actor reads those published lists and returns the reference, proposal, site address, status, dates and a link.
Can I get leads for councils outside the 15 covered?
Not with this actor. It covers 15 verified Idox council portals; other councils would need to be checked on their own portals.
How do I find the company behind a development?
The dataset does not include applicant details. If the applicant is a company you identify another way, Companies House Enrichment can return its directors and filings.
What does the status field mean?
It is the status text as published by the council, such as 'Registered'. Wording varies between portals, so check the council's page for the latest position.
Actors used in this guide
UK Planning Applications Scraper — 15 Councils, Weekly Leads
New and decided UK planning applications (applications for planning permission) from 15 council portals in one clean dataset: reference, proposal…
$3 per 1,000 · planning applicationRelated guides
How to Export UK Company Directors from Companies House in Bulk
Give Companies House Enrichment a list of company numbers or a SIC code, status and location filter, keep includeOfficers on, then flatten the…
How to Get Local Business Leads Without Scraping Google Maps
Query the open Overture Maps places dataset by city and category with Business Places Data to get names, addresses, phones, websites and emails for…