Free UK property data API Start free →
2026-04-06 · 9 · Tutorials

UK Census 2021 Demographics API: Get Area Data by Postcode (Python & JS)

Access ONS Census 2021 demographics for any UK postcode via REST API. Returns tenure, age distribution, ethnicity, occupation, household size, and car ownership. Includes Python and JavaScript examples for property analysis, investment research, and area profiling.

Why Use a Census Data API?

The ONS Census 2021 is the most comprehensive snapshot of the UK population — covering 56.5 million people across England and Wales. But accessing that data programmatically is painful. Nomis offers bulk CSV downloads (some over 1GB), and the ONS API requires understanding arcane geographic hierarchies (OA, LSOA, MSOA, LAD).

If you're building a property platform, mortgage comparison tool, or investment analysis app, you probably just want to answer: "What kind of area is this postcode in?" That's what the Homedata Demographics API does — one postcode in, structured demographics out.

GET /api/v1/demographics?postcode=SW1A1AA

Returns tenure, age, ethnicity, occupation, household size, and car ownership — all as percentages. One call. No geographic lookups required.

What Data Is Available

The API returns six demographic dimensions from the Census 2021, all expressed as percentages of the local MSOA area (~8,000 residents):

Category Fields ONS Source
Tenure Owned outright, mortgage, shared ownership, social rented, private rented, rent free TS054
Age bands 0–15, 16–29, 30–44, 45–64, 65+ TS007
Household size 1-person, 2-person, 3+ person TS017
Car ownership No car, 1 car, 2+ cars TS045
Ethnicity White British, White other, Mixed, Asian, Black, Other TS021
Occupation (NS-SeC) Managerial/professional, Intermediate, Routine/manual, Never worked TS062

Plus population and household totals for the MSOA area, and the MSOA code itself for cross-referencing with other ONS datasets.

Quick Start: Get Demographics for Any Postcode

Sign up for a free API key at homedata.co.uk/register (no credit card required), then:

curl "https://api.homedata.co.uk/api/postcode-profile/?postcode=E14+5AB" \
  -H "Authorization: Api-Key YOUR_API_KEY"

The response includes a census block with all demographic data:

{
  "postcode": "E14 5AB",
  "census": {
    "source": "ONS Census 2021",
    "msoa_code": "E02000117",
    "area_level": "msoa",
    "population_total": 11234,
    "households_total": 4891,
    "tenure": {
      "owned_outright_pct": 8.12,
      "owned_mortgage_pct": 14.53,
      "shared_ownership_pct": 4.21,
      "social_rented_pct": 29.44,
      "private_rented_pct": 40.18,
      "rent_free_pct": 3.52
    },
    "age_bands": {
      "age_0_15_pct": 18.45,
      "age_16_29_pct": 21.33,
      "age_30_44_pct": 32.67,
      "age_45_64_pct": 18.91,
      "age_65_plus_pct": 8.64
    },
    "ethnicity": {
      "white_british_pct": 22.18,
      "white_other_pct": 15.34,
      "mixed_pct": 5.67,
      "asian_pct": 28.91,
      "black_pct": 19.44,
      "other_pct": 8.46
    }
  }
}

The census data is part of the broader postcode-profile response, which also returns sold prices, deprivation, broadband speeds, nearby schools, and transport. One call, complete area intelligence.

Python: Area Demographics Report

Build a demographics comparison tool that analyses tenure patterns across multiple postcodes:

import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.homedata.co.uk/api/postcode-profile"
HEADERS = {"Authorization": f"Api-Key {API_KEY}"}

def get_demographics(postcode: str) -> dict:
    """Fetch census demographics for a postcode."""
    resp = requests.get(BASE, params={"postcode": postcode}, headers=HEADERS)
    resp.raise_for_status()
    return resp.json().get("census")

# Compare tenure across 3 areas
postcodes = {
    "Canary Wharf": "E14 5AB",
    "Mayfair": "W1K 1AA",
    "Salford": "M5 4WT",
}

print(f"{'Area':<20} {'Owned %':>10} {'Private Rent %':>15} {'Social Rent %':>15}")
print("-" * 62)

for name, pc in postcodes.items():
    census = get_demographics(pc)
    if census:
        tenure = census["tenure"]
        owned = tenure["owned_outright_pct"] + tenure["owned_mortgage_pct"]
        print(f"{name:<20} {owned:>10.1f} {tenure['private_rented_pct']:>15.1f} "
              f"{tenure['social_rented_pct']:>15.1f}")
    else:
        print(f"{name:<20} {'No data':>10}")

Output:

Area                   Owned %  Private Rent %  Social Rent %
--------------------------------------------------------------
Canary Wharf              22.7           40.2           29.4
Mayfair                   31.5           52.8            8.1
Salford                   28.9           33.1           24.7

JavaScript: Demographics Widget

Embed a demographics summary into any web page:

async function fetchDemographics(postcode) {
  const resp = await fetch(
    `https://api.homedata.co.uk/api/postcode-profile/?postcode=${postcode}`,
    { headers: { "Authorization": "Api-Key YOUR_API_KEY" } }
  );
  const data = await resp.json();
  return data.census;
}

// Render a simple demographics card
async function renderDemographics(postcode, containerId) {
  const census = await fetchDemographics(postcode);
  if (!census) return;

  const el = document.getElementById(containerId);
  const tenure = census.tenure;
  const totalOwned = tenure.owned_outright_pct + tenure.owned_mortgage_pct;

  el.innerHTML = `
    <div class="demographics-card">
      <h3>Area Demographics — ${postcode}</h3>
      <p>Population: ${census.population_total.toLocaleString()}</p>
      <div class="tenure-bar">
        <div style="width:${totalOwned}%; background:#4ade80">
          Owned ${totalOwned.toFixed(0)}%
        </div>
        <div style="width:${tenure.private_rented_pct}%; background:#60a5fa">
          Rented ${tenure.private_rented_pct.toFixed(0)}%
        </div>
        <div style="width:${tenure.social_rented_pct}%; background:#f59e0b">
          Social ${tenure.social_rented_pct.toFixed(0)}%
        </div>
      </div>
    </div>
  `;
}

renderDemographics("SW1A 1AA", "demo-widget");

Real-World Use Cases

Property Portals

Show buyers the character of an area alongside listings. Tenure split tells you whether it's owner-occupied (stable) or high-rental (transient). Age distribution reveals family areas vs. young professional zones.

Mortgage & Insurance

Area demographics feed into risk models. Occupation mix (NS-SeC) correlates with income levels. Household size affects property demand. Car ownership signals rural vs. urban character.

Investment Analysis

Compare tenure patterns across postcodes to identify areas with high rental demand. Cross-reference with sold price data from the same API call to calculate rental yield estimates.

Local Authority Planning

Understand population composition for housing needs assessments. Age band distribution identifies areas with ageing populations requiring different housing types.

Alternatives Compared

Source Format Postcode lookup Cost
ONS Nomis Bulk CSV download No — need to map postcode → MSOA yourself Free (but hours of data wrangling)
ONS API JSON No — requires geographic area codes Free (complex, undocumented)
PropertyData JSON API Yes — but limited to their demographics endpoint From £28/mo — demographics costs 1 credit per lookup
Homedata JSON API Yes — postcode in, demographics out Included in postcode-profile — no extra cost. 100 calls/mo free.

Pricing

Demographics data is included in the postcode-profile endpoint at no additional cost. You get census demographics, sold prices, broadband speeds, deprivation data, nearby schools, and transport stops — all in a single API call.

  • Free tier: 100 API calls/month — no credit card, no trial expiry
  • Starter (£49/mo): 2,000 calls/month
  • Growth (£149/mo): 10,000 calls/month
  • Pro (£349/mo): 50,000 calls/month

PropertyData charges 1 credit per demographics lookup on top of their monthly subscription. We include it in every postcode-profile call. Start free →

Try the Demographics API

Get Census 2021 demographics for any UK postcode. Free tier — no credit card required.