Saudi Real Estate — Bayut, Wasalt, Aqar.fm, PropertyFinder
Pricing
from $4.00 / 1,000 listing fetcheds
Saudi Real Estate — Bayut, Wasalt, Aqar.fm, PropertyFinder
Saudi-only real estate intelligence across 4 verified platforms: Bayut.sa (72K listings), Wasalt.sa PIF-owned (24K), Aqar.fm, PropertyFinder.sa. REGA license cross-reference, installment plans, Vision 2030 zone tagging, Arabic district normalization. $4/1K listings.
Pricing
from $4.00 / 1,000 listing fetcheds
Rating
5.0
(1)
Developer
Omar Eldeeb
Maintained by CommunityActor stats
2
Bookmarked
51
Total users
5
Monthly active users
8 days ago
Last modified
Categories
Share
Saudi Real Estate Scraper
Saudi-only real estate intelligence across 4 verified platforms. No UAE-only wrappers pretending to cover KSA. No remote-dev guesses about Arabic district variants. No silent gaps on REGA license cross-reference.
Pulls listings from Wasalt.sa (~78K, PIF-owned), PropertyFinder.sa, Aqar.fm (1.5M total, #1 in KSA), and Bayut.sa (~127K) — normalizes everything into a single schema, surfaces the REGA license number as a cross-platform join key, and auto-tags Vision 2030 mega-project zones (NEOM, Red Sea, Diriyah, ROSHN, Qiddiya).
Why use this actor
- ✅ REGA license cross-reference. Saudi Real Estate General Authority license number is the canonical join key across Bayut.sa, Wasalt.sa, PropertyFinder.sa and Aqar.fm — surfaced under a single
rega_license_numberfield (Aqar.fm rows also carry the licence expiry inrega_license_expires_at). - ✅ Installment plan extraction (Aqar.fm-unique). Most Saudi listings expose 2/4/12-month installment splits. No other actor surfaces these as structured fields.
- ✅ Vision 2030 zone auto-tagging. Listings inside NEOM, Red Sea Project, Diriyah Gate, ROSHN developments, Qiddiya, and King Salman Park are auto-tagged via description regex + coordinate bounds.
- ✅ Arabic district normalization. Variant spellings of top-50 KSA districts (
النرجس/Narjis/Narjes/Al Narjis) collapse to canonical English + Arabic forms. - ✅ Per-platform field union, not lowest-common-denominator. PIF/Wasalt's
darReferenceSaudi MoJ ID, Bayut'spermitUrllink to rega.gov.sa, Aqar's REGA-declared reference price — all preserved alongside the unified schema. - ✅ No proxy needed for Aqar / Bayut / Wasalt. PropertyFinder rate-limits pages 2+ from non-US IPs — actor auto-falls-back to Apify US residential proxy on 403.
How to use
- Pick one or more platforms in the input form (default:
wasalt+pf_sa) - (Optional) filter by city, district, category, sale/rent, price range, posting date, REGA-verified-only, or Vision 2030 zone
- Run. First 10 chargeable events per run are free — try it before committing.
You are only charged for rows that pass every filter. Rows dropped by a filter (wrong city, wrong district, wrong category, no price, too old...) are counted in the run's SUMMARY record under filtered and are never billed.
How filtering works (all four platforms)
Filters run in two places:
- At the source. The actor asks each platform only for what you requested, using the platform's own filters:
| Filter | Wasalt.sa | PropertyFinder.sa | Aqar.fm | Bayut.sa |
|---|---|---|---|---|
| City | cityId (one request per city id) | l=<location ids> (all of PF's duplicate entries for that city) | city id in Aqar's search | location.slug (e.g. /riyadh) |
| District | districtId (ids looked up in Wasalt's district list, Arabic and English names) | l=<district ids> (ids looked up in PF's location search) | district ids from Aqar's district list | district location.slug, resolved through Bayut's locations index |
| Category | type=residential|commercial + propertyTypeData sub-types | c=1/2 (residential buy/rent) or c=3/4 (commercial) + t=<type id> | Aqar category ids | category.slug |
| Sale / rent | /sale/search or /rent/search | c= + rent price period rp=y and rp=m (PF lists monthly-priced rentals separately) | sale/rent category ids | purpose |
| Posted within N days | (output check only) | newest-first sort (ob=nd), so the run stops early | (output check only) | reactivatedAt (server-side) |
- Before output, on every platform. Each row's
city_en/city_ar,district_en/district_ar,property_type,listing_type, price andposted_atare checked again. City and district names are compared after Arabic and English normalisation (الرياض = Ar Riyadh = Riyadh; جدة = جده = Jiddah; النرجس = An Narjis = Al Narjis). A row whose city or district is unknown while that filter is set is dropped. This catches promoted listings that platforms insert into filtered pages.
Page budget. If a platform cannot filter something server-side (for example, a city name it does not know), the actor reads the general feed and filters at output. It stops after 3 consecutive pages in which no row passes your filters, and says so in the log and in SUMMARY.notes.
Input examples
Example 1 — Riyadh apartments on Wasalt.sa + PropertyFinder.sa
{"platforms": ["wasalt", "pf_sa"],"cities": ["Riyadh"],"categories": ["apartment"],"listingType": "sale","maxListingsPerPlatform": 50}
Example 1b — Price-index feed: Riyadh apartments, sale and rent, last 90 days, two districts
{"platforms": ["wasalt", "pf_sa"],"cities": ["Riyadh"],"districts": ["Al Narjis", "الملقا"],"categories": ["apartment"],"listingType": "all","postedWithinDays": 90,"maxListingsPerPlatform": 1000}
Every row carries price_per_sqm_sar, and rent rows also carry annual_rent_sar (monthly x12, weekly x52, daily x365), so sale and rent averages can be computed directly. Group by city_key, district_key, property_type and listing_type, and exclude rows with quality_flags.
Example 2 — All 4 platforms, broad sweep
{"platforms": ["bayut_sa", "wasalt", "aqar", "pf_sa"],"listingType": "sale","maxListingsPerPlatform": 100}
Example 3 — REGA-verified only (listings that carry a REGA ad license number)
{"platforms": ["bayut_sa", "wasalt", "pf_sa", "aqar"],"cities": ["Riyadh", "Jeddah"],"listingType": "sale","regaVerifiedOnly": true,"maxListingsPerPlatform": 200,"fetchBayutRegaDetails": true}
Example 4 — Vision 2030 mega-project zones only
{"platforms": ["bayut_sa", "wasalt", "aqar"],"listingType": "sale","vision2030ZonesOnly": true,"priceMinSar": 2000000,"maxListingsPerPlatform": 100}
Example 5 — Aqar.fm with installment plans (3-bed villas in Jeddah)
{"platforms": ["aqar"],"cities": ["Jeddah"],"categories": ["villa"],"listingType": "sale","bedroomsMin": 3,"priceMinSar": 500000,"maxListingsPerPlatform": 200}
Example 6 — PropertyFinder.sa with US proxy enabled (deeper pagination)
{"platforms": ["pf_sa"],"cities": ["Riyadh"],"categories": ["apartment", "villa"],"listingType": "sale","maxListingsPerPlatform": 500,"useProxy": true}
Output sample (Bayut.sa, real row captured 2026-10-06 — villa for monthly rent, Khobar)
{"listing_id": "bayut_sa:88001794","platform": "bayut_sa","platform_listing_id": "88001794","source_url": "https://www.bayut.sa/en/property/details-88001794.html","fetched_at": "2026-10-06T19:16:05.917Z","rega_license_number": null,"rega_license_url": null,"rega_license_expires_at": "2026-12-31T21:00:00.000Z","is_rega_verified": false,"price_sar": 13000,"rega_declared_price_sar": null,"installment_plans": null,"is_auction": false,"listing_type": "rent","rent_period": "monthly","property_type": "villa","property_type_raw": "Villas","completion_status": "completed","area_sqm": 270,"plot_area_sqm": null,"bedrooms": 4,"bathrooms": 4,"living_rooms": null,"furnished": true,"amenities": ["Electricity","Water Supply","Sewerage","Flood Drainage","Air Conditioning","Waste Disposal","ATM Facility","Swimming Pool","Schools","Hospitals","Shopping Malls","Maintenance Staff","CCTV Security","Laundry Facility","Cleaning Services","Close to Metro Station","Close to Main Roads","Mosque"],"age_of_listing_days": 119,"country": "SA","city_en": "Khobar","city_ar": "الخبر","district_en": "Al Khuzama","district_ar": "الخزامى","region_en": null,"region_ar": null,"location_path": ["Al Khobar","Al Khuzama"],"coordinates": {"lat": 26.207996,"lng": 50.184892},"street_name": "عبدالرحيم ابن شيت","street_direction": null,"street_width_m": null,"zip_code": null,"vision_2030_zone": null,"agent_name_en": "Jumana Mohammad","agent_name_ar": "جمانه محمد","agent_phone": "+966555418028","agent_email": null,"agent_whatsapp": null,"brokerage_name": "PLACES","brokerage_logo_url": "https://bayut-sa-production.s3.eu-central-1.amazonaws.com/image/5620998/f47ec19abfed4afab1975fad0b3c461e","agent_capacity": "developer","cover_photo_url": "https://images.bayut.sa/thumbnails/9454961-800x600.jpeg","photo_urls": ["https://images.bayut.sa/thumbnails/9454961-800x600.jpeg"],"photo_count": 27,"video_count": 0,"panorama_count": 0,"title_en": "4 Bedroom Villa For Rent in Al Khuzama, Al Khobar","title_ar": "فيلا مكونة من 4 غرف نوم للإيجار في الخزامى، الخبر","description_en": null,"description_ar": null,"posted_at": "2026-06-08T21:00:00.000Z","updated_at": "2026-10-05T14:02:00.000Z","refreshed_at": "2026-10-05T14:02:00.000Z","is_verified": false,"is_premium": true,"is_featured": false,"platform_score": 375,"scraping_strategy": "algolia_api","price_per_sqm_sar": 577.78,"annual_rent_sar": 156000}
Output sample (Aqar.fm, real row, Saudi-unique fields)
{"listing_id": "aqar:6902064","platform": "aqar","platform_listing_id": "6902064","source_url": "https://sa.aqar.fm/%D9%81%D9%84%D9%84-%D9%84%D9%84%D8%A8%D9%8A%D8%B9/%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6/%D8%BA%D8%B1%D8%A8-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6/%D8%AD%D9%8A-%D8%A7%D9%85-%D8%A7%D9%84%D8%AD%D9%85%D8%A7%D9%85-%D8%A7%D9%84%D8%BA%D8%B1%D8%A8%D9%8A/%D8%B4%D8%A7%D8%B1%D8%B9-%D8%AC%D8%A8%D9%84-%D8%B7%D8%A7%D8%B1%D9%82-%D8%AD%D9%8A-%D8%A3%D9%85-%D8%A7%D9%84%D8%AD%D9%85%D8%A7%D9%85-%D8%A7%D9%84%D8%BA%D8%B1%D8%A8%D9%8A-%D9%85%D8%AF%D9%8A%D9%86%D8%A9-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6-%D9%85%D9%86%D8%B7%D9%82%D8%A9-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6-6902064","fetched_at": "2026-10-06T18:48:48.015Z","rega_license_number": "7100326971","rega_license_url": null,"rega_license_expires_at": "2026-11-25T00:00:00.000Z","is_rega_verified": true,"price_sar": 3800000,"rega_declared_price_sar": 3800000,"installment_plans": null,"is_auction": false,"listing_type": "sale","rent_period": null,"property_type": "villa","property_type_raw": "villa","area_sqm": 580,"bedrooms": 10,"bathrooms": null,"living_rooms": null,"street_direction": "N","street_width_m": 15,"city_en": "Riyadh","city_ar": "الرياض","district_en": "Umm Al Hamam Al Gharbi","district_ar": "ام الحمام الغربي","region_en": "Riyadh","location_path": ["Riyadh","West of Riyadh","Umm Al Hamam Al Gharbi"],"coordinates": {"lat": 24.687417,"lng": 46.649235},"posted_at": "2026-10-02T12:24:50.000Z","updated_at": "2026-10-06T18:45:25.000Z","vision_2030_zone": "King Salman Park","scraping_strategy": "graphql"}
Pay-per-event pricing
| Event | Price | Description |
|---|---|---|
apify-actor-start | $0.01 | Per run start. Apify default. |
listing-fetched | $0.004 (= $4/1,000) | One normalized listing emitted to dataset. Primary event. |
proxy-fetch | $0.001 (= $1/1,000) | Fires once for every request routed through an Apify proxy: any platform's requests when useProxy is on, PropertyFinder.sa's automatic US-proxy fallback when a direct request is blocked, and Bayut.sa's detail-API fallback after a bot challenge (fetchBayutRegaDetails). Lookups and retries included. Runs that never use the proxy never fire it. |
Free trial: first 10 chargeable events per run.
Spend cap respected. If you set a maximum total charge for the run, the actor collects only what the cap can pay for, stops collecting as soon as the cap is reached, and never writes a row it cannot charge. The run's SUMMARY record reports spendCapReached and how many rows were held back (filtered.spendCap).
Cost scenarios
| Scenario | Listings × platforms | Total cost |
|---|---|---|
| Solo broker scanning Aqar Riyadh apartments | 500 listings | $2.01 |
| Mid-tier weekly Wasalt+PropertyFinder sweep | 5,000 listings | $20.01 |
| REIT monthly full Saudi sweep (4 platforms) | 100,000 listings | $400 |
| Vision 2030 entity quarterly intel (filtered) | 50,000 listings | $200 |
vs Property Monitor ($135/mo UAE-only) + REIDIN ($1.5K–$5K/mo enterprise) + JLL bespoke reports ($5K–$50K). This actor is API-grade infrastructure at SMB pricing.
Data fields (canonical NormalizedListing schema)
| Field | Type | Notes |
|---|---|---|
listing_id | string | ${platform}:${platform_id} |
platform | enum | bayut_sa / wasalt / aqar / pf_sa |
platform_listing_id | string | Native ID |
source_url | string | Direct listing URL |
fetched_at | ISO 8601 | When scraped |
rega_license_number | string | null | Cross-platform JOIN KEY. Present on Wasalt/PF/Aqar; Bayut only with fetchBayutRegaDetails |
rega_license_url | string | null | Direct link to rega.gov.sa registry (Bayut only, with fetchBayutRegaDetails) |
rega_license_expires_at | ISO 8601 | null | Ad-licence expiry (Bayut from search results; Aqar) |
is_rega_verified | bool | null | Platform's verified flag |
price_sar | number | Canonical Saudi Riyal price |
rega_declared_price_sar | number | null | REGA reference price (Aqar.fm exclusive) |
installment_plans | object | null | {months_2, months_4, months_12, monthly_rnpl} (Aqar.fm exclusive) |
is_auction | bool | |
price_per_sqm_sar | number | null | Sale rows: price_sar / area_sqm. Rent rows: annual_rent_sar / area_sqm (so monthly and yearly rentals are comparable). Land falls back to plot_area_sqm. Null when price or area is missing |
city_key | string | null | Canonical city key (riyadh, jeddah, khobar ...). Group by city_key + district_key to aggregate across platforms |
district_key | string | null | Normalised district key: the Arabic district name when present, with أ/إ/آ→ا, ة→ه, ى→ي folded, diacritics removed and the حي / Al / Ar / An ... prefixes stripped (e.g. حي الملك عبدالله and الملك عبدالله give the same key). When a row has only an English district name, it is mapped to Arabic only through the curated district dictionary or an exact match with an English/Arabic pair from Wasalt's, PropertyFinder's or Bayut's own bilingual location lists seen in the same city in the run (never by fuzzy spelling, never from Aqar.fm's English names); otherwise the key stays Latin. A Latin key does not join an Arabic one |
district_key_script | ar | ar_inferred | latin | null | Where district_key came from: ar the row's own Arabic name; ar_inferred an English name mapped to Arabic as described above; latin no safe mapping. Use ar + ar_inferred for cross-platform grouping |
quality_flags | string[] | Data-quality warnings; the row is still delivered. See Quality flags below |
annual_rent_sar | number | null | Rent rows only: price_sar x 1 (yearly), x 12 (monthly), x 52 (weekly), x 365 (daily). Null for sale rows and when the platform gives no rent period. Exception: Aqar.fm listings with no period are shown as yearly by Aqar itself; we follow Aqar's display and flag implausible values with rent_period_suspect |
listing_type | enum | sale / rent / off_plan / auction. Off-plan sale units keep listing_type: sale with completion_status off_plan / under_construction; the off_plan input returns exactly those (Bayut.sa: under-construction listings). No platform currently exposes auctions |
rent_period | enum | null | daily / weekly / monthly / yearly — the period price_sar is quoted in |
property_type | enum | apartment / villa / land / building / commercial / townhouse / penthouse / office / shop / hotel-apartment / other. Mapping notes: whole-floor units (Wasalt دور, PF "Full Floor") → apartment; duplex → townhouse; Wasalt بيت (house) and قصر (palace) → villa; showrooms → shop; warehouses / workshops / hotels → commercial; rest houses, chalets, compounds → other; farms and agricultural plots → other, not land (industrial and commercial plots stay land). The source label is kept in property_type_raw |
area_sqm | number | null | Built-up area in sqm (land plots: plot area) |
plot_area_sqm | number | null | Land / plot area (Bayut detail page, Wasalt carpetArea) |
bedrooms / bathrooms / living_rooms | number | null | Coerced to numbers (PF gives strings) |
furnished | bool | | coordinates |
amenities | string[] | Expanded from PF short codes ("WT" → "Water") |
age_of_listing_days | number | null | Parsed from Wasalt Arabic relative time strings |
city_en / city_ar | string | null | Canonical names for 96 Saudi cities (e.g. Riyadh / الرياض, Khobar / الخبر, Al Ahsa / الأحساء incl. Hofuf) so all platforms group the same way. Other cities keep the platform's own name, in the field matching its script. Arabic text never goes into *_en |
district_en / district_ar | string | null | Canonical names from the district dictionary where known, otherwise the platform's own English / Arabic names (Wasalt and PropertyFinder rows both carry the Arabic district name) |
region_en / region_ar | string | | coordinates |
location_path | string[] | Variable depth 2-5 levels |
coordinates | {lat, lng} | null | null when the platform pin is outside Saudi Arabia (lat 16–33, lng 34–56) or a placeholder near 0,0 |
street_direction | enum | null | N / NE / E / SE / S / SW / W / NW (Aqar.fm exclusive) |
street_width_m | number | null | Aqar.fm exclusive |
vision_2030_zone | enum | null | NEOM / Red Sea / Diriyah / ROSHN / Qiddiya / King Salman Park |
agent_name_en / agent_name_ar / agent_phone / agent_email / agent_whatsapp | strings | null | agent_whatsapp is null when the number is a call-tracking line shared across agencies |
brokerage_name / brokerage_logo_url | strings | | coordinates |
agent_capacity | enum | null | individual / company_broker / developer |
cover_photo_url / photo_urls[] / photo_count / video_count / panorama_count | media | |
title_en / title_ar / description_en / description_ar | strings | null | Wasalt.sa: description_ar is the REGA / Ministry of Justice description from the search results; the seller's free-text description exists only on the listing page and is not fetched (it would cost one extra page per row), so about 40% of Wasalt rows have no description. Bayut.sa: description only with fetchBayutRegaDetails |
posted_at / updated_at / refreshed_at | ISO 8601 | null | posted_at = Wasalt publishedAt, PropertyFinder listed_date, Aqar creation time, Bayut reactivatedAt (the site's "Added on") |
is_verified / is_premium / is_featured | booleans | |
platform_score | number | null | PF qs, Bayut indyScore, Wasalt totalScore |
scraping_strategy | enum | next_data / rsc_chunks / window_state_algolia / algolia_api / dom / graphql |
Quality flags
Listing sites contain seller typos. The actor never edits or removes them; it flags them in quality_flags so a price index can exclude them. Thresholds are national plausibility bounds, not per-city statistics:
| Flag | Raised when |
|---|---|
rent_period_suspect | Residential rent labelled yearly below 6,000 SAR, or monthly above 300,000 SAR (period probably mislabelled) |
sale_price_suspect | A sale of anything other than land / other priced below 20,000 SAR (usually a per-m² price typed as the total) |
area_suspect | Apartment under 15 m² or over 1,500 m²; villa over 5,000 m² (often square feet typed as m², or a whole-building area) |
price_per_sqm_outlier | Sale of a built home below 300 or above 50,000 SAR/m²; land sale below 10 or above 50,000 SAR/m²; residential rent below 10 or above 3,000 SAR/m² per year |
Example: a 300 m² Riyadh plot listed on Wasalt at 180,000,000 SAR (the site itself displays that price) gets price_per_sqm_outlier.
Tips
-
Price indexes: use medians or trimmed means. Listing data contains seller typos (for example a 600 sqm land plot priced at 508 million SAR, or an apartment listed with 6,528 sqm). The actor reports what the platform publishes and does not edit or remove outliers.
-
postedWithinDaysdrops rows without a posting date while it is on. Wasalt (publish or creation date) and PropertyFinder (listed date) rows normally have one. -
Pair with Egyptian Real Estate Scraper for MENA-wide coverage. Same NormalizedListing-equivalent shape.
-
Pair with Gulf Used Cars if your buyer audience overlaps (Saudi consumers + brokers).
-
fetchBayutRegaDetails: truemakes 2 extra small API calls per emitted Bayut listing; fills the REGA permit, permit URL, description and all photos. Bayut.sa blocks these permit lookups from many server IPs (including Apify's own) with a bot page, so the actor automatically retries them through an Apify residential (Saudi) proxy. Measured on Apify cloud (October 2026): 100% permit fill on runs of 15–300 Bayut rows, about 2 proxy-fetch events per row. If every route is blocked, Bayut rows are still delivered without permit, permit URL and description, the run's SUMMARY says so, and failed proxy attempts that never succeed are capped (the larger of 6 or 2% of planned lookups, plus at most 9 requests already in flight when the cap is reached). Failed attempts that are retried successfully don't count toward the failure cap, but every proxy-routed request (including retries) is billed as proxy-fetch. Speed with details: roughly 40-60 Bayut rows per minute through the residential proxy — allow about 2 minutes per 100 Bayut listings; rows the timeout cuts off are still delivered, without permits. -
regaVerifiedOnly: truedrops any listing without a REGA license number (Aqar.fm listings carry their REGA ad license, so they are kept). Bayut.sa rows needfetchBayutRegaDetailsand a run IP that Bayut allows; otherwise Bayut is skipped (nothing fetched or billed). Use when downstream KYB/compliance requires REGA verification. -
Vision 2030 tagging is conservative — only tags when description matches OR coordinates fall inside tight project bounds. Broader zones (NEOM, Red Sea) require text match; narrower zones (Diriyah, King Salman Park) accept coordinate-only.
FAQ
Q: Why no Sakan.co / OpenSooq KSA / Haraj? A: All three returned YELLOW on the platform spike — Sakan is DOM-only (no JSON state), OpenSooq's KSA finder returns 404 from non-KSA IPs, Haraj's GraphQL endpoint has introspection blocked and would require operation reverse-engineering. Deferred to v1.1+.
Q: Why no Bayut UAE / PropertyFinder UAE / other GCC platforms? A: This actor is Saudi-positioned. For UAE/Qatar/Bahrain/Kuwait coverage, watch for a separate Gulf actor on its own roadmap.
Q: REGA license verification — is the license actually valid?
A: We extract and surface the license number + permitUrl (Bayut). We do NOT call rega.gov.sa to verify validity in v1 (REGA portal is geo-locked from non-KSA IPs). Manual verification via the surfaced permitUrl is straightforward. Programmatic REGA cross-reference is a v1.1 add.
Q: Why did older runs return so few Aqar.fm listings?
A: It shouldn't any more. Aqar.fm is now collected through Aqar's own search (the same one sa.aqar.fm uses), filtered server-side by city, district and category and paged deeply — up to maxListingsPerPlatform (5,000) per run, with real posted_at timestamps. Aqar has no off-plan or auction feed, so listingType: off_plan / auction returns 0 Aqar rows (and costs nothing).
Q: What does agent_phone: null mean?
A: For platforms that gate phone behind a "click to reveal" UI (Aqar.fm, Wasalt), v1 surfaces null. Bayut.sa and PF.sa expose phone directly in the search-result payload.
Changelog
-
2026-10 (0.1.14) — Bayut permit lookups no longer stop early on small runs (the failure cap counted requests still in flight); measured 15/15, 20/20 and 100/100 permits on Apify cloud.
-
2026-10 (0.1.13) — District keys fold a trailing hamza (الصفاء = الصفا); English district names use one article spelling ("Ar Rimal" → "Al Rimal"). Bayut permit lookups run 5 workers with parallel calls (~40-60 rows/min via residential proxy), pace down on 429, and the failed-attempt cap scales with the run (max of 6 or 2% of lookups; only settled failures count, requests still in flight never trip it). Also:
district_keyinference is strict: an English-only district is mapped to Arabic only via the curated dictionary or an exact English/Arabic pair from Wasalt's, PropertyFinder's or Bayut's own location lists (never by fuzzy spelling, never from Aqar.fm's English names); such keys are labelleddistrict_key_script: ar_inferred. Bayut permit lookups: 429 and server errors are retried on the same route (honouring Retry-After) instead of switching route; lookups are paced; after a block the last working route is retried once after 30 s. SUMMARY gainsstopReason(spend_cap/write_failed);spendCapReachedis only set by the spend cap. -
2026-10 (0.1.12) — Bayut permit lookups: a route that works is kept through a single bot challenge, concurrent requests never skip an untried route, and failed proxy attempts are reserved up front (superseded in 0.1.14: the cap now scales with the run and only settled failures count).
district_keyresolves English-only district names to Arabic where possible; newdistrict_key_scriptfield. A failed dataset write stops the run cleanly with an honest SUMMARY. -
2026-10 (0.1.11) — Cloud QA fixes:
- Bayut permit lookups: a 3-request preflight detects whether Bayut blocks permit lookups from the run's IP; if so, rows are delivered without permits and the SUMMARY says so. Failed proxy attempts are capped at 6 per run (previously up to 72 billed proxy requests for zero permits).
regaVerifiedOnlywith a blocked Bayut skips Bayut entirely at no cost. listingType: "all"collects sale and rent side by side (round-robin), so a run cut by its timeout returns both (previously only sale).- Short timeouts keep collecting longer (safety margins now scale with the run's timeout) and deadline-cut runs keep Arabic district names on PropertyFinder and English district names on Wasalt.
- Coordinates outside Saudi Arabia (e.g. placeholder pins near 0,0) are now
null. off_planreturns Bayut.sa under-construction listings (previously nothing). Auctions: no platform exposes them; documented.
- Bayut permit lookups: a 3-request preflight detects whether Bayut blocks permit lookups from the run's IP; if so, rows are delivered without permits and the SUMMARY says so. Failed proxy attempts are capped at 6 per run (previously up to 72 billed proxy requests for zero permits).
-
2026-10 (0.1.10) — Billing and robustness:
- Your spend cap is respected. Rows are written with Apify's charge-aware push, collection is capped to what your maximum total charge can pay for, and collection stops once the cap is reached. Previously rows past the cap could be delivered unpaid.
- Proxy billing disclosed and billed as it happens:
proxy-fetchfires for every proxy-routed request on any platform (see the pricing table). - A platform still running at the run timeout is no longer lost: rows it already delivered are saved. One platform failing no longer stops the others; one malformed row no longer stops the run.
- Categories: if none of your categories is recognised the run fails instead of returning everything. New Aqar.fm-only categories: warehouse, farm, studio, floor, rest-house, chalet, room, hotel, tower, complex.
- Cities: 96 cities and more spellings (Taef, Hael, Khamis, Burayda, Unaiza, Jubayl, Diriya, Qunfudah ...). A city a platform does not list is skipped on that platform, never widened to the whole Kingdom.
- Farms, agricultural plots and rest houses are
otheron every platform (Bayut's land category no longer includes farms). - New fields:
city_key,district_key(group across platforms) andquality_flags. - Wasalt
area_sqmis null for a built unit whose only size on the search card is the plot (it used to report the plot). - Platform names are case-insensitive and common spellings are accepted (bayut, propertyfinder, pf, aqar_fm).
-
2026-10-06 — Bayut.sa rebuilt on its search API and returns rows again. City, district, category, posting-date, price, bedroom and area filters run on Bayut's side.
posted_atis Bayut's "Added on" date. REGA permits come fromfetchBayutRegaDetails. Shared call-tracking WhatsApp numbers are no longer reported as the agent's. When no category is given, Bayut returns residential listings only. -
2026-10-06 — Aqar.fm rebuilt on Aqar's own search: city, district and category filtered server-side, deep paging (up to 5,000 rows), correct property and sale/rent labels, real
posted_at, REGA ad licence on every row. Short district names (e.g.الشاطئ) expand to their East/West parts on every platform. -
2026-10-06 — Filtering and price-index fields for Wasalt.sa + PropertyFinder.sa:
- City filter now works on Wasalt and PropertyFinder (it was ignored before, so rows from other cities were returned and billed). Cities are filtered on the platforms' servers and re-checked on every row before output; off-city rows are dropped and not charged.
- New
districtsinput (English or Arabic), filtered server-side on both platforms and re-checked at output. - PropertyFinder rent returns rows again (it returned 0: rent periods were misread as sales).
rent_periodis now filled from the platform; PropertyFinder's separately listed monthly-priced rentals are included.rent_periodgainsweekly. - Categories are applied on Wasalt (it always returned residential) and enforced on the output
property_typefor every platform. Commercial and land listings are returned when asked. - New fields
price_per_sqm_sarandannual_rent_sar, and a "Price index" dataset view. - New
postedWithinDaysinput andincludePriceOnRequestinput. Listings without a price are now dropped by default (previously emitted withprice_sar: 0). listingType: "all"now returns sale and rent from Wasalt and PropertyFinder (it returned only sale).- Data fixes: Wasalt
city_en/district_enno longer contain Arabic; Wasalt rent price uses the platform's per-period amounts; Wasaltfurnishedandliving_roomsare filled; Wasaltarea_sqmuses the built-up area when the search card'scarpetAreais the plot; Wasaltدور(floor) maps toapartment(wastownhouse) andشاليه(chalet) toother(wasvilla); PropertyFinder district no longer falls back to a URL slug; PropertyFinder Arabic titles go totitle_ar;age_of_listing_daysfor Wasalt counts from the publish date. - The run stops collecting before the run timeout and saves what it has.
-
2026-10-01 — Default and prefilled
platformschanged from["bayut_sa"]to["wasalt", "pf_sa"], because Bayut.sa currently returns 0 rows. Runs that omitplatformsnow get Wasalt.sa + PropertyFinder.sa listings instead of an empty dataset. Inputs that namebayut_saexplicitly are unchanged; the Bayut fix is in progress.
Legal disclaimer
This actor extracts publicly available real estate listings from Saudi real estate platforms. Use of the data is governed by each platform's terms of service. The actor does not verify the legitimacy of REGA licenses or the accuracy of listing details. Users are responsible for compliance with applicable Saudi regulations, including REGA, Ejar, and Sakani requirements where relevant. No warranty is provided on data quality or freshness.
Data attribution: Listings sourced from sa.aqar.fm, bayut.sa, wasalt.sa, propertyfinder.sa. Each source retains copyright in its original listing content; we provide a structured derivative for research and intelligence purposes.