Madinah
Sources & methodology

Where this data comes from

This portal aggregates publicly available data — nothing is invented or paywalled. Every number on every map can be traced back to a named, public source. Use this page to verify, audit, or replace any of these inputs.

2,237

Listings tracked

103

Neighbourhoods

173

Amenities mapped

1,892

Listings geo-matched

Last full refresh: 9 May 2026.

Data sources

Primary listings source

Bayut.sa
Active

Apartments, villas, townhouses, land and buildings for sale in Madinah. Includes price, area, bedrooms, bathrooms, agent and one main image per listing.

Method: Server-rendered JSON-LD blocks per page parsed directly. No browser engine required.

2,154 items90 pagesUpdated 9 May 2026

Secondary listings source

PropertyFinder.sa
Active

Same listing categories, often with more international-buyer-oriented descriptions and photos. Smaller volume but adds diversity.

Method: __NEXT_DATA__ JSON payload parsed directly.

83 items4 pagesUpdated 9 May 2026

Listings source — currently blocked

Wasalt.sa
Blocked

Strong on apartments and land, Arabic-first portal.

Method: Cloudflare managed challenge requires a real browser engine; not currently scraped.

Neighbourhood boundaries + amenities

OpenStreetMap (Overpass)
Static

103 neighbourhood polygons within the Madinah municipality, plus 173 amenity points (supermarkets, hospitals, schools, mosques).

Method: Overpass API queries on place=neighbourhood, place=quarter, boundary=administrative (admin levels 9–10). Pulled once and stored as static JSON; rerun when OSM updates the administrative tree.

276 items

Travel time to Masjid Nabawi

OpenRouteService
Active

Driving and walking duration + distance from each neighbourhood centroid to Masjid Nabawi. Free tier, OSM-based road network.

Method: Pre-computed once per neighbourhood (driving + walking profile) and cached in data/distances.json. Free tier limits the refresh cadence; live traffic is not used.

206 itemsUpdated 7 May 2026

Foreign Muslim ownership status per neighbourhood

Zone classification (curated)

Curated

Whether each neighbourhood is Open / Pending / Saudi-only under the 22 January 2026 framework. The full Haram precinct around Masjid Nabawi is the only zone with a confirmed restriction today.

Method: data/zone-status.json — manually maintained ruleset with explicit overrides per neighbourhood. Default status is 'pending' until Saudi authorities publish the official zone designations.

Updated 5 May 2026

How listings reach the map

  1. Scrape — each source is fetched via a small Node.js script (npm run data:bayut, npm run data:propertyfinder) producing raw per-source JSON files in data/raw/.
  2. Normalise — each listing is reduced to a common shape: id, source, url, title, type, price (SAR), area (m²), bedrooms, bathrooms, lat/lng, image, scraped_at.
  3. Geo-match — each listing's lat/lng is point-in-polygon-tested against the 103 OSM neighbourhood polygons; only matches are surfaced on the map. 85% of listings currently match — the rest sit just outside any named neighbourhood.
  4. Aggregate — per neighbourhood we compute count, median, min and max price for the badges and panels.
  5. Build — the result ships as static data/listings.json, served by Next.js. No database, no runtime API for the public portal.

How distance to Masjid Nabawi is calculated

For every neighbourhood, we compute the area-weighted polygon centroid and ask OpenRouteService for both the driving and walking route to Masjid Nabawi (24.4672°N, 39.6112°E). The result is cached in data/distances.json and re-used on every page load — no live traffic, no per-visit API calls.

Two semantic post-processing flags are applied because raw routing produces misleading numbers around the Haram precinct:

  • contains_destination — when a polygon contains Masjid Nabawi itself, distances are forced to zero. Currently flags 1 neighbourhood (Al Haram Al Sharif).
  • pedestrian_zone_nearby — when a driving route runs more than 3× the walking distance and walking is under 2 km, the panel surfaces walking time as the realistic metric. The car has to detour around the pedestrian Haram complex; walkers don't. Currently flags 4 neighbourhoods adjacent to the Haram.

Known limitations

  • One photo per listing

    Bayut JSON-LD only exposes a single image per listing. Multi-photo galleries require either a different scrape strategy (Algolia API, browser rendering) or photo enrichment. Tracked as backlog item B2.

  • Wasalt is blocked

    Wasalt.sa sits behind a Cloudflare managed challenge and currently cannot be scraped without a headless browser. The infrastructure is in place — only the source is missing.

  • Zone status is curated, not authoritative

    The Saudi government publishes official ownership zones in stages under the 22 January 2026 law. Until those publications are complete, this portal treats most of the city as 'Pending'. Always verify with an official source before transferring any funds.

  • No live traffic

    Driving times reflect static OSM road weights, not current congestion. For a buyer comparing neighbourhoods this is fine; for an actual departure plan, use a live navigation app.

  • Listings are public-portal snapshots

    Properties may sell, change price or be re-listed between refreshes. Treat the count and price aggregates as a market signal, not a real-time inventory.

Replicating this stack

Anyone with access to the codebase can rebuild the data layer from scratch:

npm run data:neighbourhoods   # OSM polygons
npm run data:amenities        # OSM amenity points
npm run data:bayut            # Bayut listings (raw)
npm run data:propertyfinder   # PropertyFinder listings (raw)
npm run data:listings         # combine + geo-match
npm run data:distances        # ORS routes (requires ORS_TOKEN)
npm run data:distances:fix    # post-process flags

Data current as of 9 May 2026 · Not legal advice