# UK Property Market Data API - Prices, Rents, Yields, EPC (`nabeelbaghoor/uk-property-market-data-api`) Actor

Read UK property data by postcode, coordinates, what3words or town: asking and sold prices, rents, yields, growth and demand, planning applications, listed buildings, flood risk, EPC ratings, UPRNs, title ownership and leases, sale and rental valuations, and investment sourcing lists.

- **URL**: https://apify.com/nabeelbaghoor/uk-property-market-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Real estate, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 local market record returneds

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

## UK Property Market Data API - Prices, Rents, Yields, EPC

Turn a list of UK postcodes into a dataset: what sells, what rents, what it yields, who owns it, and what the council has already said yes to.

### What it collects

- **Local market**: live asking prices and sold prices, long let and HMO rents, commercial quoting rents, rental yields, up to seven years of capital growth, sales and rental demand, price and growth per square foot, estate agent market share, local housing allowance rates and national market indicators.
- **Planning and constraints**: planning applications filtered by project type, application type, outcome, age and radius; listed buildings by grade; conservation area and green belt checks; flood risk from rivers and sea; build cost and rebuild cost per property.
- **Buildings and energy**: EPC ratings and known internal floor areas for every property in a postcode.
- **Ownership and identifiers**: UPRNs across a postcode area with structured address parts and coordinates, one property by its UPRN with its use class and registered leases including years remaining, the title number behind a UPRN, a title's address, type, ownership and lease information, local freehold titles, and an address matched to its closest UPRN.
- **Valuation and sourcing**: sale, rental, HMO and historical valuations with the provider's estimate, margin and confidence; investment sourcing lists such as unmodernised, repossessed, reduced, high-yield and auction properties; the national HMO register.
- **Neighbourhood**: crime statistics by radius, demographics, average household income, population and density, nearby schools, average council tax bills, area type, internet speeds, and property stock by type and tenure.

### FAQ

#### What is a UK property data API used for?

Screening at a scale that manual research cannot reach. An investor runs sold prices, rents and yields across two hundred postcode districts to find where the numbers work. A lender or insurer runs flood risk, EPC and construction data across a book of addresses. A developer runs planning applications and listed building status across a search area before spending anything on a site. A proptech product puts valuations and title ownership behind its own screens. The common shape is a list of locations in and a table of facts out, which is exactly what this actor is.

#### How do I tell it where to look?

One location per line, in any of the four forms the provider accepts: a UK postcode (full, district or sector such as `W14 9JH`, `W14` or `W14 9`), a `latitude,longitude` pair, a what3words address, or a town name. Each line is read by its shape unless you set the location type explicitly. Exactly one location parameter is sent per request, because the provider refuses a call that carries two and a call that carries none, and a line read as the wrong kind would be a charged answer about the wrong place.

#### What happens to a postcode with no data?

It becomes its own row, marked `found: false`, with a note explaining which of the two things happened: the provider has insufficient data for that location, or it did not recognise the input at all. Those need different fixes, so they are not collapsed into one message. A run over a hundred postcodes therefore returns a hundred rows rather than eighty-eight, and you can see at a glance which twelve were empty.

#### Can this actor spend money beyond the data call?

No. The provider publishes routes that buy Land Registry documents and order scale site plans, and neither is wired up anywhere in this actor. Every route it can reach is a read. That is a deliberate limit, because a scheduled run that could buy documents is a scheduled run that eventually will.

#### Which services return many rows and which return one?

The list services return one row per record: planning applications, listed buildings, freehold titles, UPRNs, EPC ratings, floor areas, HMO register entries, schools and sourced properties. Everything else returns one row per location or per property. The distinction matters for cost on both sides, because the provider itself charges per ten or per fifty results on the list services, and this actor prices a list row well below an area reading for the same reason.

#### Why is the provider's record kept whole instead of split into columns?

Because these services answer in many different shapes, and a fixed set of columns would silently drop most of what you asked for. The columns that are lifted are the ones every row has regardless of service: which service answered, which endpoint it came from, what was asked, which location parameter it was sent as, whether anything came back, and when. The provider's own record sits beside them under `record`, unchanged.

#### How long may I keep what it returns?

The provider's licence allows you to store what a call returns for up to 60 days from retrieval, then refresh or delete it, and that clock runs from the moment of retrieval rather than from the end of your subscription. Dated snapshots, derived events, your own aggregates and reports you have already produced may be kept indefinitely provided they are marked as historical and not presented as current. The rows this actor writes are ordinary dataset rows on your own account, so the retention is yours to manage: check the provider's terms before building a standing copy.

#### How fast will it run?

The provider rate limits per account across every key on it, between 12 and 72 requests per 30 seconds depending on plan, and the actor defaults to the slow end of that. A refusal is retried against the provider's own `Retry-After` header rather than a guessed delay, because a fixed backoff against a per-account limit means racing whatever else is calling the same account. Raise the requests per minute input if your plan allows and nothing else is using the key.

#### Why did a refusal say it was an actor bug rather than my key?

Because this provider answers an unknown endpoint and a missing key with the same HTTP 400, and only its own error code separates them: `X01` for a path that does not exist, `X02` for a missing key, `X03` for an invalid one. The actor reads the code, so a routing mistake on its side is reported as its own fault instead of sending you off to reissue a credential that was fine all along.

#### Do I need my own API key?

Yes. This actor is bring-your-own-key and never ships a key of its own. Paste your key from your provider account, or set it once as the DATA\_API\_KEY environment secret. It travels as a request header rather than in the query string, which the provider also accepts, because a credential in a URL ends up in logs and proxy records for no benefit.

#### What does it cost?

Pay per result. A single property or valuation row costs the most, because one row is a complete answer about one property. A local market reading costs a little less. A list row costs well under half that, because one request commonly returns dozens. Reading your own remaining credits is priced near zero, since finding out what you have left should not itself cost anything worth counting. Platform usage is included, and locations the provider holds nothing for are never charged.

### Example output

```json
{
  "service": "soldPrices",
  "serviceLabel": "Local sold prices",
  "endpoint": "/sold-prices",
  "requested": "W14 9JH",
  "requestedAs": "postcode",
  "found": true,
  "recordType": "market",
  "retrievedAt": "2026-09-20T09:14:52.118Z",
  "record": { "...": "every field the provider published, unchanged" },
  "note": null
}
```

### Keyword map

UK property data API, property market data API, sold prices API, asking prices API, UK rent data API, rental yield API, property valuation API UK, HMO rent data, EPC data API, energy performance certificate API, UPRN lookup API, title number lookup, Land Registry title data, freehold title search, planning applications API, listed buildings API, conservation area check, green belt check, flood risk API UK, council tax by postcode, property sourcing API, repossessed property data, auction property data, UK postcode property data, house price data by postcode, property investment data API, proptech data API, what3words property lookup.

# Actor input Schema

## `service` (type: `string`):

One service per run. Market services answer with one record for a local area. List services answer with many records for one area, such as planning applications or UPRNs. Property services read one thing by its identifier or its address. The account service reports the credits left on your own plan and costs the provider nothing.

## `locations` (type: `array`):

One location per line. The provider accepts a UK postcode (full, district or sector), a "latitude,longitude" pair, a what3words address or a town name, and every service names which of those it takes. Exactly one is sent per request, because the provider refuses a call carrying two.

## `locationType` (type: `string`):

Leave on automatic and each line is read by its shape: a postcode pattern, a coordinate pair, three dot separated words, or a town name otherwise. Set it explicitly when a place name could be mistaken for something else, or when a service accepts more than one kind and you want a particular one.

## `identifiers` (type: `array`):

One per line, for the services that read a single thing rather than an area: a UPRN for the UPRN and title lookup services, a title number for the title service, and a full address for the address matching service.

## `bedrooms` (type: `integer`):

Restrict the comparable properties to this bedroom count. Accepted by the asking prices, sold prices, rents and sale valuation services.

## `propertyType` (type: `string`):

Restrict the comparable properties to one type. Accepted by the asking prices, sold prices and rents services.

## `comparablePoints` (type: `integer`):

How many nearby comparable properties the provider should base the answer on. A larger number widens the area the answer describes, so a tight local reading wants a smaller one.

## `maxAgeMonths` (type: `integer`):

Ignore sold prices older than this many months. Accepted by the sold prices service.

## `minSquareFeet` (type: `integer`):

Ignore comparables below this internal floor area. Accepted by the two price per square foot services.

## `maxSquareFeet` (type: `integer`):

Ignore comparables above this internal floor area. Accepted by the two price per square foot services.

## `crimeRadiusKm` (type: `number`):

How far around the location the crime statistics should cover. The provider accepts 0.1 to 3 kilometres and uses 0.4 when this is left blank.

## `planningCategory` (type: `string`):

Restrict planning applications to one or more project types, comma separated. The provider documents home improvement, small residential, medium residential, large residential, mixed and tree.

## `planningApplicationType` (type: `string`):

Restrict planning applications to one or more application types, comma separated. The provider documents full planning application, householder planning application, change of use, listed building consent, lawful development, advertisement consent, tree preservation order, utilities, environmental impact, non-material amendment and discharge of conditions. Left blank, it returns all but the last four.

## `planningMaxAgeDays` (type: `integer`):

Ignore planning applications older than this. The provider accepts 14 to 1500 days.

## `planningDecision` (type: `string`):

Restrict planning applications to one outcome, as the provider rates them.

## `planningRadiusMiles` (type: `number`):

How far around the location to look for planning applications. The provider accepts 0.01 to 3 miles.

## `listedGrade` (type: `string`):

Restrict listed buildings to one grade, as Historic England grades them.

## `listedAfterYear` (type: `integer`):

Only buildings added to the list after this year. Four digits, for example 1975.

## `sourcingLists` (type: `string`):

Which investment sourcing lists to search, comma separated, up to five in one call. The provider names unmodernised-properties, repossessed-properties, reduced-properties, high-yield-properties and auction-properties among them. Required by the sourced properties service.

## `sourcingRadiusMiles` (type: `integer`):

How far around the location to search the sourcing lists. The provider accepts 1 to 200 miles and uses 40 when this is left blank.

## `sourcingPropertyType` (type: `string`):

Restrict sourced properties to one or more of flat, terraced\_house, semi-detached\_house and detached\_house, comma separated. Prefix a type with an exclamation mark to exclude it instead.

## `sourcingMaxAgeDays` (type: `integer`):

Only sourced properties listed within the last this many days.

## `excludeSoldSubjectToContract` (type: `boolean`):

Leave out sourced properties that are already sold subject to contract, so the list is what is still available.

## `resultsPerCall` (type: `integer`):

How many records the provider should return in one call, on the services that take it. The provider charges per ten or per fifty results on those services, so this is what a single call costs you there.

## `page` (type: `integer`):

Which page of sourced properties to read, using the results per call value as the page size. The provider caps page times results at 500.

## `strictPostcode` (type: `string`):

Set to true to return only UPRNs that sit inside the postcode you gave, rather than the ones nearest to it.

## `internalAreaSqFt` (type: `integer`):

The property's internal floor area, for the sale valuation service.

## `valuationPropertyType` (type: `string`):

The property's type, for the sale valuation service.

## `constructionDate` (type: `string`):

When the property was built, for the sale valuation service. The provider takes a date or a period and does not publish a fixed list, so this is free text.

## `bathrooms` (type: `integer`):

The property's bathroom count, for the sale valuation service.

## `finishQuality` (type: `string`):

How well finished the property is, for the sale valuation service. The provider does not publish a fixed list, so this is free text.

## `extraParameters` (type: `object`):

Any other parameter the provider documents for the selected service that this actor does not have its own field for. Given as a JSON object, for example {"points": 40}. Nothing here is invented: it is passed to the provider exactly as written, so check the name against the provider's own documentation first.

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

Stop after this many rows. The list services can return hundreds of records for one location, so this is what bounds a run that reads a long list of postcodes.

## `requestsPerMinute` (type: `integer`):

Pacing ceiling. The provider rate limits per account across every key on it, between 12 and 72 requests per 30 seconds depending on your plan, so the default here is the slow end. Raise it if your plan allows and nothing else is calling the same account.

## `apiKey` (type: `string`):

Your own API key for the UK property data provider. This actor is bring-your-own-key and never ships a key of its own. Leave blank to use the DATA\_API\_KEY environment secret instead.

## `baseUrl` (type: `string`):

Override the host the actor calls. Only useful for testing against a different environment.

## Actor input object example

```json
{
  "service": "prices",
  "locationType": "auto",
  "excludeSoldSubjectToContract": false,
  "maxResults": 500,
  "requestsPerMinute": 24
}
```

# Actor output Schema

## `records` (type: `string`):

One row per record, alongside the location or identifier that produced it.

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

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/uk-property-market-data-api").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/uk-property-market-data-api").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 '{}' |
apify call nabeelbaghoor/uk-property-market-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/uk-property-market-data-api"
        }
    }
}
```

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/FBa2aVpPmCkSbegDb/builds/uhylIZE8c3EhwHw1r/openapi.json
