SG Property Data

Methodology

Last updated: 2026-06-30

This page explains exactly how every figure returned by the SG Property Data API and MCP server is calculated, including the limitations we want you to know about before relying on any number.

Data sources

  • Private residential sale transactions: Singapore's Urban Redevelopment Authority (URA) PMI_Resi_Transaction data service, covering the past 5 years of caveats lodged.
  • Private residential rental contracts: URA's PMI_Resi_Rental data service, covering the past 5 years of contracts submitted to IRAS for stamp duty assessment.
  • HDB resale transactions: data.gov.sg's Resale flat prices based on registration date from Jan-2017 onwards dataset, published by HDB, covering registrations from January 2017 onwards.
  • We do not currently cover subdistrict-level geography for private property, or block/street-level geography for HDB (see Known limitations for why).

We are not affiliated with URA or HDB. All figures below are independently computed by us from their published data.

Update cadence

We recalculate the full dataset monthly from a fresh pull of URA's two data services and HDB's resale dataset. Call /meta (or the get_data_freshness MCP tool) to see exactly when the current dataset was calculated and what period of underlying data it covers - never assume a figure reflects today's market without checking this first.

Geographic and market levels (private residential)

Every private-residential metric below is available at three levels:

  • District - the 28 postal districts (01-28).
  • Market segment - CCR (Core Central Region), RCR (Rest of Central Region), or OCR (Outside Central Region), URA's own core-vs-fringe classification, assigned per transaction.
  • Project - a named development.

Property category: condo vs landed

We split every private-residential metric, at every geographic level, into two separate categories: condo (Apartment, Condominium, Executive Condominium) and landed (Detached, Semi-detached, Terrace, and their Strata variants). This isn't a filter you opt into - it's structural. A condo's psf is computed on floor area; a landed house's is computed on land area. Blending the two into one "median psf" would average two different units of measurement together, which would be actively misleading, not just imprecise. We use the same category boundaries URA's rental data already uses natively, so sale and rental data classify things consistently.

A small number of projects genuinely contain both condo and landed units (URA documents this as possible). Rather than force one label onto a mixed project, it gets one stats row per category it actually has - querying it under condo and under landed returns two different, independently-computed sets of figures.

HDB resale: geography and flat type

HDB metrics are a separate namespace, not a third property category alongside condo/landed - public and private housing are different enough markets (different sale process, different eligibility rules, different financing) that we treat them as genuinely distinct products, the same reasoning behind the condo/landed split applied one level higher.

  • Geography: HDB's 26 towns (e.g. Ang Mo Kio, Sengkang, Punggol). This is the finest grain we publish - the most granular thing in HDB's own data is block + street name, and individual blocks typically have too few annual transactions for a reliable trend/CAGR figure (the same reasoning that keeps us from publishing block-level data applies here as it does to not publishing a sub-project, per-unit figure for private property).
  • Flat type: an optional flat_type parameter (e.g. "4 ROOM"), the same role tenure plays for private property - a slice you can ask for specifically, or omit for the blended "ALL" figure across every flat type in that town.
  • No market-segment rollup: CCR/RCR/OCR is a private-market-specific classification with no HDB equivalent.
  • No rental-yield metric: HDB subletting of an owned flat, under HDB's eligibility rules, isn't priced as an investment product the way private rental is - we don't force that model onto data it doesn't fit.
  • Remaining lease: HDB's source data reports this as a free-text string (e.g. "61 years 04 months"). We parse it into a single median_remaining_lease_years figure per slice - the median across that slice's transactions, not a per-transaction figure.

Units and conversions

  • URA reports floor area in square metres. We convert to price-per-square-foot (psf) using area_sqm x 10.7639, since that's the unit Singapore's market actually quotes in. HDB's data uses the same square-metre convention and the same conversion.
  • Bundled transactions (multiple units under one caveat, common in collective/en-bloc sales) report a total price and total area across all units. Dividing total price by total area still yields a correct psf figure, since the per-unit count cancels out of the ratio.

Tenure

We parse URA's tenure string into one of three categories:

  • Freehold - exactly as URA records it.
  • Freehold-equivalent - any fixed-term lease of 900+ years (covers round numbers like 999/9999 years and several historical lease lengths in the 929-998 year range). At this length, remaining lease is not a meaningful constraint for any realistic investment horizon, so we treat it the same as Freehold.
  • Leasehold - everything else, with lease_years and remaining_lease_years (as of today) computed from the lease commencement year.

A small number of URA records omit the lease commencement year. Where another transaction for the same project and lease length includes the commencement year, we backfill it; where no sibling record has it, remaining_lease_years is returned as null rather than guessed.

Price snapshot

snapshot.median_psf is the median psf across all transactions in the trailing 12 months of available data for that slice (a private-property project/segment/district, or an HDB town/flat-type combination) - this is "what it's worth now," not a long-run average. snapshot.p25_psf and snapshot.p75_psf (the 25th and 75th percentiles) show how wide that figure's spread actually is - a tight p25-p75 range means a fairly homogeneous set of units; a wide one means more variation (different floors, views, or unit types) sitting behind that one median number.

Price trend and CAGR

For each slice, we sort all available transactions by date, split them into an early half and a late half, and compare the median psf of each half. (For an odd transaction count, the middle transaction is included in both halves rather than dropped from the comparison entirely.) This is more resistant to a single outlier transaction than comparing two single points, but it has a known limitation: it does not control for which specific units transacted in each half. If a project or town's larger or higher-floor units happen to transact later in its history, psf can rise for reasons unrelated to market appreciation. We considered a more rigorous repeat-sales (same-unit-matched) approach and chose not to implement it for now - see "Known limitations."

CAGR is annualized over the actual time span covered by the data (capped at 5 years), not assumed to be exactly 5 years regardless of how much history exists.

Every price_trend/cagr response includes the raw first_psf/last_psf figures (with their dates and how many transactions backed each side) behind the derived percentage - not just our computed number. This means you can verify our arithmetic yourself, or do your own interpretation of the underlying movement, rather than relying solely on the single percentage we calculated from it. This applies identically to private property and HDB - both use the exact same calculation logic.

Yearly breakdown

price_trend and cagr each collapse the whole available window into one summary number. yearly_breakdown is different: it's the actual year-by-year time series - median psf for each calendar year that has data, its own transaction count, and its year-over-year change versus the previous calendar year. The first year in the series always has yoy_change_pct: null, since there's no prior year to compare against. Same shape, same calculation, for both private property and HDB slices.

This is shown independent of the overall trend confidence tier (including for excluded redevelopment-tagged private projects, since reporting what a given year's median actually was isn't the same claim as asserting a smooth organic trend) - each year's own transaction_count is the reliability signal for that specific year. A year with only 1 transaction behind it should be read with the same caution as any other low-count figure on this site.

Confidence tiers

Every trend and yield figure carries a confidence value, computed from how much data backs it:

Confidence Criteria
high 10+ data points spanning 3+ years
medium 5+ data points spanning 1+ year
low 2+ data points spanning 6+ months - CAGR and price change are both shown, but treat them with real caution at this tier
insufficient_data Fewer than 2 data points, or less than 6 months of span
excluded The project is tagged as a redevelopment/collective-sale project (for example, a name containing parentheses such as "(DEMOLISHED)") - its transaction prices reflect redevelopment economics, not organic market movement, so trend/CAGR is not computed at all

A null value with a stated confidence and the underlying transaction_count / years_used is a deliberate, honest result, not a missing feature.

Rental yield

Gross yield is estimated as:

yield_pct = (median rent psf, trailing 12 months x 12) / median sale psf, full history

Rental yield is only returned for projects with both rental and sale data; if a project has no rental contracts in the last 12 months, no yield figure is returned for it.

Unlike snapshot, trend, and CAGR, rental yield is not split by property category. For the rare mixed condo/landed project, the yield figure uses that project's full sale history regardless of category. We treat this as an acceptable simplification given how rare mixed projects are, rather than something requiring the same separation the other three metrics get.

URA's rental data reports floor area as a range (for example, "100-110 sqm"), not an exact value. We use the midpoint of that range to estimate psf, which introduces some approximation error - more so for wider bands. This is a limitation of the source data, not something we can correct for.

yearly_yield_breakdown is the year-by-year equivalent of yearly_breakdown on the price side: for each calendar year where a project has both sale and rental data, it shows what gross yield would have been if you'd bought and rented in that same year - that year's median sale psf against that year's median rent psf, not a fixed current price against a moving rent. Years where either side is missing simply don't appear in the series, rather than being filled in with an approximation.

Known limitations

  • CAGR does not control for unit-mix shift within a slice's transaction history (see above). We chose not to build repeat-sales matching to fix this: the disclosed confidence/count/span figures already let you judge reliability for the typical use cases this data serves, and a same-unit-matching approach would reduce coverage (many projects/towns lack enough unique area+floor-band matches) for a precision gain that doesn't change most practical decisions.
  • Rental psf is range-midpoint-derived, not exact.
  • No subdistrict-level or individual-unit comparable data for private property.
  • No block/street-level HDB data - town is the finest grain published, for the same reliability reasons private property doesn't get a per-unit figure.
  • No HDB rental-yield metric - deliberately not built, since HDB subletting isn't priced as an investment product the way private rental is (see "HDB resale: geography and flat type" above).

If you're building something where these limitations matter to your use case, contact [email protected] - that kind of feedback is genuinely useful for prioritizing what we build next.