Midland Realty Scraper – HK Listings & Transactions (No API)
Pricing
from $2.00 / 1,000 listing / transaction / estates
Midland Realty Scraper – HK Listings & Transactions (No API)
Scrape Midland Realty Hong Kong without an API: 44K for-sale and for-rent listings, 1.8M historical transactions and 18K estates. Price, rent, saleable area, price per sq ft, bedrooms, school net and coordinates as JSON/CSV/Excel — for HK property research and agency inventory comparison.
Pricing
from $2.00 / 1,000 listing / transaction / estates
Rating
0.0
(0)
Developer
Chad
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
5 days ago
Last modified
Categories
Security
Limited permissionsShare
Midland Realty Scraper (Hong Kong)
Scrape Midland Realty's public Hong Kong property data with one Actor: listings for sale and rent, historical transaction records, and the full estate directory. Public JSON API — no login, no API key, no browser.
Midland has the largest branch network of any Hong Kong estate agency, and the dataset is a tier larger than most comparable sources:
| Mode | Rows available |
|---|---|
| Listings | 44,190 (31,530 for sale / 15,563 for rent) |
| Transactions | 1,855,568 |
| Estates | 17,964 |
Output fields
Listings (mode: search)
| Field | Type | Description |
|---|---|---|
serial_no | string | Midland listing number, e.g. M351962478 |
deal_type | string | buy or rent |
region | string|null | Hong Kong Island / Kowloon / New Territories |
subregion | string|null | Sub-region, e.g. Tsuen Wan |
district | string|null | District, e.g. Ma Wan |
sm_district | string|null | Smaller district subdivision |
estate / estate_id | string|null | Estate name and Midland estate ID |
phase | string|null | Phase, e.g. Phase 1 |
building / building_id | string|null | Building name and ID |
price_hkd | number|null | Asking price in HKD. null for rentals |
rent_hkd | number|null | Monthly rent in HKD. null for sale listings |
net_area_sqft | number|null | Saleable area in square feet |
gross_area_sqft | number|null | Gross area in square feet |
net_to_gross_ratio | number|null | Efficiency ratio (%) |
net_unit_price_hkd | number|null | Sale price per saleable square foot (HKD). null for rentals |
net_unit_rent_hkd | number|null | Monthly rent per saleable square foot (HKD). null for sales |
monthly_mortgage_hkd | number|null | Midland's estimated monthly mortgage payment |
bedroom / sitting_room | number|null | Bedroom / living room count |
orientation | string|null | Facing direction |
primary_school_net | number|null | Primary school net number |
has_video / has_photo_360 | boolean|null | Whether a video / 360° photo exists |
tags | string[]|null | Listing tags, e.g. sole (sole agency) |
agent_name_zh / agent_name_en | string|null | Agent name |
latitude / longitude | number|null | Coordinates |
photo_urls | string[]|null | Photo URLs |
listing_url | string|null | Midland listing page |
updated_at | string|null | Listing update time (ISO 8601) |
scraped_at | string | Scrape time (ISO 8601) |
Transactions (mode: transactions)
transaction_id, region / subregion / district, estate / estate_id, building, floor, flat, price_hkd, net_area_sqft, gross_area_sqft, net_unit_price_hkd, transaction_date, transaction_type, source (e.g. LANDREG for Land Registry), tags, latitude / longitude, transaction_url, updated_at, scraped_at
Estates (mode: estates)
estate_id, name, region / subregion / district / sm_district, first_op_date (occupation date), total_unit_count, total_block_count, primary_school_net, sale_listing_count / rent_listing_count, net_unit_price_hkd (recent price per saleable sq ft), recent_transaction_count, amenities (nearby facilities with walking minutes), latitude / longitude, photo_url, estate_url, scraped_at
Field names are always English snake_case. Missing values are always
null— fields are never omitted, so the output drops straight into a table.
Modes
| Mode | What you get | Typical use |
|---|---|---|
search | Listings for sale / rent | Cross-agency inventory comparison, sourcing, price monitoring |
transactions | Historical sales records | Building your own price index, valuation models, trend analysis |
estates | Estate directory and stats | Estate reference database, supply analysis |
Input
| Field | Type | Default | Description |
|---|---|---|---|
mode | enum | search | search / transactions / estates |
dealType | enum | buy | buy or rent (ignored in Estates mode) |
regions | string[] | all | Hong Kong Island / Kowloon / New Territories; empty = all three |
bulkRegions | string | — | One per line, merged with the field above |
bedrooms | integer | — | Exactly N bedrooms |
bathrooms | integer | — | Exactly N bathrooms |
schoolNet | integer | — | Specific primary school net |
sort | enum | default | Newest / price / saleable area / price per sq ft, ascending or descending |
language | enum | en | Language of region and estate names (field names stay English) |
maxItems | integer | 50 | Max rows for this run, max 500 |
onlyNew | boolean | false | Only return items not returned by earlier runs (monitoring); see below |
stateKey | string | auto | Name of the remembered state; empty = derived from mode + filters |
proxyConfiguration | object | residential | Keep the default — see Notes |
Input examples
1. 100 Kowloon listings for sale
{ "mode": "search", "dealType": "buy", "regions": ["Kowloon"], "maxItems": 100 }
2. Three-bedroom listings across Hong Kong, cheapest price per sq ft first
{ "mode": "search", "dealType": "buy", "bedrooms": 3, "sort": "net_ft_price", "maxItems": 200 }
3. Hong Kong Island rentals with Chinese estate names
{ "mode": "search", "dealType": "rent", "regions": ["Hong Kong Island"], "language": "zh-hk", "maxItems": 50 }
4. New Territories transaction records
{ "mode": "transactions", "dealType": "buy", "regions": ["New Territories"], "maxItems": 300 }
5. Full estate directory
{ "mode": "estates", "maxItems": 500 }
Use it from Claude or any AI agent (MCP)
This actor is already available as a tool through Apify's official hosted MCP server — nothing extra to install, and billing is identical to a normal run (per item, no MCP surcharge).
Add it to Claude Code in one line (get $APIFY_TOKEN from Apify Console → Settings → API & Integrations):
$claude mcp add --transport http apify "https://mcp.apify.com/?tools=claude_code_reviewer/midland-scraper-en" --header "Authorization: Bearer $APIFY_TOKEN"
Claude Desktop, Cursor and other MCP clients: add https://mcp.apify.com as a custom connector and sign in with OAuth.
Midland only filters by region — it does not accept estate names or keywords (the official API silently ignores them), so have the agent filter the estate field after fetching. Then just ask:
Use the Midland scraper (language: en) to fetch the latest 500 New Territories transactions, then keep only rows whose estate field contains "City One" and compute the median saleable price per sq ft.
The agent first receives a summary and a dataset id, then reads the rows with get-dataset-items (you can request only the fields you need to save tokens).
Don't want to set this up? See the managed option below.
Only new items (monitoring)
Default behaviour is unchanged: every run returns the full result. With onlyNew on, the actor remembers the items it already returned in a key-value store named delta-state-<actor ID> (one per actor) in your account, and later runs with the same input output only newly seen items; already-seen items are skipped and not charged. The first run behaves like a normal run and seeds the memory. When nothing is new the run still succeeds (the log says "No new items").
Scheduling example (same input every day, get only new listings):
{ "mode": "search", "dealType": "buy", "regions": ["Kowloon"], "sort": "latest", "onlyNew": true, "maxItems": 200 }
stateKey: when empty it is derived from the fields that define what is scraped (mode, deal type, regions, filters, sort;maxItems, proxy and language do not matter), so the same scheduled input continues where it left off. To keep separate memories for different schedules or integrations, set your own name (letters, digits,_,-, 1-100 chars). Most API callers reuse inputs, so setting it explicitly is recommended.- Identity:
searchusesserial_no,transactionsusestransaction_id,estatesusesestate_id(kept separate per mode). Inestatesmode only newly appearing estates are returned. - Sorting: any sort works, but for monitoring
sort: "latest"is the efficient choice. With other sorts the actor keeps paging through already-seen pages and stops after 5 such pages in a row, so new listings further down can still be found, at the cost of more requests. - Each state key remembers the latest 20,000 items;
maxItemscounts new items only.
Notes
- Keep the proxy default (Apify residential). Midland returns 403 to datacenter egress — even the page that issues the access token is blocked. Turning the proxy off or switching it to datacenter yields zero rows. JSON responses are about 4KB per row, so residential traffic cost is negligible.
- The only filters that actually work are
regions,bedrooms,bathroomsandschoolNet. Midland's public API silently ignores estate-name, sub-district, price-range and area-range filters — sending them changes nothing in the response. This Actor deliberately does not send them, so you are never misled into thinking a filter applied. To filter by estate or price, filter the output yourself. maxItemsis the total across all regions, not per region.- 2026-11-02 field fix: for listings,
net_unit_price_hkdused to read the rent-per-square-foot value, so it was almost alwaysnullfor sales and held the rent per square foot for rentals. It now holds the sale price per saleable square foot (sales only), and rent per square foot has moved to the newnet_unit_rent_hkdfield. If you usednet_unit_price_hkdon rentals as rent per square foot, readnet_unit_rent_hkdinstead. rent_hkdisnullon sale listings andprice_hkdisnullon rentals. Midland reports0in those fields; we normalise0tonullso you never see a "HK$0" property.- If new listings appear while scraping, pages shift and rows can repeat. This Actor de-duplicates across the whole run, so each row is output — and charged — only once.
- Public data only. No login, no authentication bypass.
- Usage terms: only public listing data from Midland's website is collected. Respect Midland's terms of use and do not reproduce or redistribute site content.
- Personal data: if the output includes agent names or phone numbers, you must comply with Hong Kong's Personal Data (Privacy) Ordinance (PDPO) and must not use them for unsolicited marketing.
- The Actor keeps a low request rate (at most 3 concurrent requests per run) to avoid burdening the site.
Pricing
A single event, search-listing, at $0.002 per row output (same in all three modes). Only rows successfully written to the dataset are charged; duplicates and filtered-out rows are not.
FAQ
Q: Can I scrape a single estate, e.g. Taikoo Shing?
A: Not directly — Midland's public API has no estate or keyword filter (we tested keyword, keywords, estate_id, q and others; all are ignored or break the response). Use estates mode to pull the estate directory, or scrape the region and filter on the estate field.
Q: How far back do the transaction records go?
A: The database holds 1.86 million records, sourced from Land Registry filings (source: LANDREG) among others. Currently they can be paged by region and sale/rent only — there is no date-range parameter.
Q: What's the difference between net_area_sqft and gross_area_sqft?
A: net_area is saleable area and area is gross area; net_to_gross_ratio is the efficiency ratio. Hong Kong has required saleable-area disclosure since 2013, so prefer net_area_sqft. Some listings have no gross area, in which case the field is null.
Q: Can I merge this with Centaline data? A: Yes — that's a primary use case. Both output snake_case fields, region hierarchies and estate names, which suits agency-vs-agency inventory and pricing comparison. Estate naming differs slightly between sites, so fuzzy-match on district plus estate name.
Q: Why does it need a residential proxy? Is that expensive? A: Midland blocks datacenter IPs, so without residential you get no data at all. The API is very compact (about 4KB per row), so measured traffic cost is far below the per-row price.
Q: I got fewer rows than maxItems.
A: That filter combination is exhausted. Loosen the filters (drop bedrooms, say) or scrape another region.
Q: With Only new items on, why did my run return 0 rows?
A: Nothing new appeared since the last run with the same state key. That is a normal result (the run succeeds and nothing is charged). To get everything again, use a different stateKey or turn onlyNew off.
Disclaimer
This Actor is intended for lawful purposes only, such as personal research, academic analysis, market research and property trend studies. Please comply with Midland Realty's (midland.com.hk) terms of service and applicable Hong Kong law. Do not scrape at excessive volume and do not resell raw data. The author accepts no liability for any damage arising from use of this tool.
Hong Kong property scraper Midland Realty scraper HK real estate data property listings transaction records estate directory saleable area price per square foot Hong Kong estate agency property data export HK housing market research valuation model
📚 Related tutorials & tools
Hands-on guides and free tools built on this actor, at AI Social API:
- 📖 Guide: Hong Kong Property Data: Estate Transactions, Listings and the CCL From Centaline, Midland and 28Hse
- 📖 Tutorial: Hong Kong's CCL Index Is Up 12% in 2026 — Sha Tin First City Still Sold at a HK$1M Loss
- 📊 Data: Site coverage: modes, fields & pricing — every live site, its modes, the exact output fields it returns, and per-item pricing — generated from the actors' own schemas
- 🛠 Free tools: Hong Kong property lookup · Apify cost calculator
- 🤝 Rather not run it yourself? I run it for you — scheduled daily, delivered to your Google Sheet or Slack, from US$299/mo.
Maintained by an operator running 30+ live Apify actors.