DEV Community

Cover image for Bayut API in Python: Dubai Rental Yields Often Differ More by Building Than by Area
Happy Endpoint
Happy Endpoint

Posted on Originally published at Medium

Bayut API in Python: Dubai Rental Yields Often Differ More by Building Than by Area

Ask which Dubai area has the best rental yield and you get an area for an answer: JVC, Arjan, Dubai Production City. I wanted to know how much the building inside the area changes that answer, so I took every one-bedroom flat for sale and for rent on Bayut and worked out the yield building by building.

In many areas, the building changes it more than the area does. Inside Jumeirah Village Circle (JVC), the gross asking yield on a one-bedroom runs from 6.0% at Hadley Heights to 9.0% at Alcove. Across the 13 areas with enough buildings to compare, the area medians run only from 5.4% (Dubai Harbour) to 7.2% (Dubai Production City). In 7 of those 13 areas, the gap between the best and the worst building is wider than the gap between areas; in the other 6, the area makes the bigger difference.

The data

The Bayut API returns Bayut search results as JSON. /search-property takes a purpose (for-sale or for-rent), location_ids, rooms, property_type, completion_status and rent_frequency, and returns 25 listings a page with price, rooms, area, completionStatus, rentFrequency and a location array that runs from the country down to the building. The last entry of that array has "type": "condo-building" when the listing is pinned to a building. /autocomplete turns a building name into its location ID.

The data comes from a full copy of Bayut's listings that is taken once a day, made of the records /search-property returns. I used the copy of 3 November 2026, which holds 196,162 Dubai apartment listings. That is far more than a few calls can page through, so the code below shows how to pull a slice of it live: three buildings in 14 calls. For sale I kept the 37,949 completed flats with a price shown; for rent, the 93,474 yearly rentals. I dropped 94 sale and 159 rent listings outside AED 200,000 to 50 million (sale), AED 15,000 to 2 million a year (rent) or 15 to 1,000 square metres. Most sit above the price caps; a few are typos, such as a rental listed at 0.12 square metres.

For each building and bedroom count I took the median asking price and the median asking rent, and kept the buildings with at least 10 listings on each side. For one-bedroom flats that left 380 buildings in 45 areas, resting on 7,921 sale listings and 17,135 rentals.

The code

This compares three JVC buildings. It looks each one up with /autocomplete, pages through every completed one-bedroom flat for sale and every yearly one-bedroom rental in it, and divides the median rent by the median price. Put your RapidAPI key in RAPIDAPI_KEY and it runs exactly as shown.

import json
import os
import statistics

import requests

HOST = "uae-real-estate3.p.rapidapi.com"  # Bayut API on RapidAPI
BASE = os.environ.get("API_BASE", "https://" + HOST)


def headers():
    if "API_BASE" in os.environ:
        return json.loads(os.environ.get("API_HEADERS", "{}"))
    return {"x-rapidapi-host": HOST, "x-rapidapi-key": os.environ["RAPIDAPI_KEY"]}


def get(path, **params):
    r = requests.get(BASE + path, params=params, headers=headers(), timeout=60)
    r.raise_for_status()
    return r.json()["data"]


def building_id(name, area="Jumeirah Village Circle"):
    """Bayut location ID of a building, from /autocomplete."""
    for loc in get("/autocomplete", query=name)["locations"]:
        if loc["type"] == "condo-building" and area in loc["path"]:
            return loc["externalID"]
    raise ValueError("no building called " + name)


def prices(location_id, purpose, **filters):
    """Asking prices of every 1-bedroom apartment listed in one location, all result pages."""
    out, page = [], 1
    while True:
        data = get("/search-property", purpose=purpose, location_ids=location_id,
                   property_type="apartments", rooms="1", page=page, **filters)
        out += [p["price"] for p in data["properties"]]
        if page >= data["totalPages"]:
            return out
        page += 1


for name in ["Alcove", "Tower 108", "Hadley Heights"]:
    loc = building_id(name)
    sale = prices(loc, "for-sale", completion_status="completed")  # ready flats, no off-plan
    rent = prices(loc, "for-rent", rent_frequency="yearly")        # annual rents only
    s, r = statistics.median(sale), statistics.median(rent)
    print("%-15s %3d for sale, median AED %9s | %3d to rent, median AED %6s a year | yield %.1f%%"
          % (name, len(sale), format(s, ",.0f"), len(rent), format(r, ",.0f"), r / s * 100))
Enter fullscreen mode Exit fullscreen mode

It made 14 calls and printed:

Alcove           10 for sale, median AED   797,500 |  22 to rent, median AED 72,500 a year | yield 9.1%
Tower 108        35 for sale, median AED   900,000 |  74 to rent, median AED 65,000 a year | yield 7.2%
Hadley Heights   27 for sale, median AED 1,250,000 |  44 to rent, median AED 75,000 a year | yield 6.0%
Enter fullscreen mode Exit fullscreen mode

That run was a day after the snapshot, and it lands within a listing or two and a tenth of a point of it: the snapshot had Alcove at 10 for sale and 23 to rent and a 9.0% yield, Tower 108 at 7.2% and Hadley Heights at 6.0%.

Look at the two ends. The median one-bedroom for sale is 871 sq ft at Alcove and 876 sq ft at Hadley Heights, practically the same flat. Hadley Heights asks 57% more for it. Its tenants pay AED 75,000 a year against Alcove's AED 72,000. Rent hardly notices the building; the asking price notices it a lot. That is where the whole spread comes from.

JVC, building by building

Inside JVC, a 1-bed yields 9.0% or 6.0%, depending on the building

79 JVC buildings had at least 10 one-bedroom flats on each side. Their median is 7.0%, and 42 of them sit within half a point of it. The tails are the interesting part: 3 buildings ask 8% or more, and 20 ask less than 6.5%. Pick the wrong end of the same community and you give up three points of gross yield, the difference between a payback of 11 years and one of 17.

Alcove's figure rests on 10 sale listings, the minimum I allowed, so treat the very top of the chart as a lead to check, not a fact. The bottom of the chart is better supported: Binghatti Grove has 82 one-bedroom flats for sale and still comes out at 6.0%.

Cheaper per square foot, higher yield

The cheaper the building per sq ft, the higher the yield

Across all 380 buildings, the pattern behind JVC holds city-wide. Group the buildings by their median asking price per square foot and the median yield falls band by band, from 7.9% in buildings asking under AED 1,000 per sq ft to 5.6% in those asking AED 2,500 or more.

Rents do rise with price, just not as fast. From the cheapest band to the dearest, the median building's asking price goes from AED 911 to AED 3,054 per sq ft, 3.4 times as much. Its asking rent goes from AED 73.7 to AED 173.3 per sq ft a year, 2.4 times as much. A building that is expensive per square foot is mostly expensive to buy, not to rent.

Area by area

These are the 13 areas with at least 8 qualifying buildings, ranked by the median of their building yields:

Area Buildings Median building yield Lowest building Highest building Median building's 1-bed asking price
Dubai Production City 8 7.2% 6.3% 8.1% AED 892,500
Arjan 14 7.0% 5.5% 8.2% AED 1,195,000
JVC 79 7.0% 6.0% 9.0% AED 1,000,000
JVT 8 6.8% 6.0% 8.1% AED 1,087,500
Al Furjan 11 6.7% 6.3% 7.9% AED 980,000
Business Bay 54 6.2% 4.6% 8.2% AED 1,525,000
Sobha Hartland 11 6.1% 5.7% 6.8% AED 1,425,000
Dubai Marina 37 6.0% 4.5% 7.2% AED 1,600,000
Dubai Hills Estate 20 5.9% 5.4% 6.5% AED 1,650,000
Dubai Healthcare City Phase 2 8 5.8% 5.0% 6.6% AED 1,275,000
Downtown Dubai 33 5.7% 4.8% 7.1% AED 2,090,000
Dubai Creek Harbour 11 5.4% 4.9% 6.4% AED 1,900,000
Dubai Harbour 8 5.4% 4.3% 5.9% AED 2,737,500

The area ranking looks familiar: the cheaper inland suburbs yield most, the waterfront and Downtown least. But read across the rows instead of down the column.

In 7 of 13 areas, buildings differ more than areas do

The 13 area medians span 1.83 points. Inside Business Bay alone the buildings span 3.57, from 4.6% at SOL Bay to 8.2% at Ontario Tower. JVC spans 3.03, Dubai Marina 2.73 and Arjan 2.69. Seven areas have a wider gap inside them than the gap between all 13; Dubai Production City only just, at 1.85. Dubai Hills Estate and Sobha Hartland are the tightest, at about 1.1 points each.

So the area is a decent first filter for yield, and a poor last one.

How this compares with registered figures

Everything above is asking prices and asking rents. Signed rents and registered sale prices are a different cut, and a useful check. Across all of JVC, with no building filter, the snapshot gives a one-bedroom asking yield of 6.7% (median asking rent AED 70,000, median asking price AED 1,050,000, taken over all JVC listings rather than building by building, which is why the table shows AED 1,000,000). The JVC page on bayutapi.dev, built from registered rental contracts and resale transactions from November 2025 to October 2026, puts the gross yield on a ready one-bedroom flat at 6.9%. That page is the place for registered sale prices, sales volumes and yields by area. What listings add is the building.

Pitfalls in the Bayut data

Most flats for sale are not built yet. Of the 93,268 Dubai apartments for sale on 3 November, 55,223 (59.2%) were under-construction: 34,964 sold new by developers and 19,999 resales of off-plan units. Nobody rents those out yet. Use completion_status=completed on the sale side, or the yield compares today's rents with launch prices.

price on a rental means whatever rentFrequency says. 9.0% of the Dubai apartment rentals were not yearly: 8,685 monthly, 385 daily and 191 weekly. A monthly one-bedroom has a median price of AED 11,900, a yearly one AED 79,990. Filter with rent_frequency=yearly or convert before you take a median.

area is in square metres, with float noise. The first Alcove listing came back as 80.91854784. Multiply by 10.7639 for square feet.

The same flat is often listed more than once. Several agents advertise the same unit. Counting listings with the same building, bedroom count, size to the square metre and price as repeats, 33% of the one-bedroom rentals in buildings and 17% of the one-bedroom sale listings were extra copies. The medians are robust to it: deduplicated, the median building's yield moved by 0.1 points, and only 6 of the 380 buildings moved by more than half a point. Totals are another matter. total counts listings, not flats.

Per square foot can disagree with per flat. Dividing median rent per sq ft by median price per sq ft is the usual way to correct for size. In JVC's Dana Tower it gives 11.3%, against 7.9% from the median prices, because the flats for sale (950 sq ft) are much bigger than the flats to rent (689 sq ft), and big flats are cheaper per square foot. Within one building and one bedroom count I trust the per-flat figure more. Check both.

Not every listing names a building. 4,202 apartment listings stopped at a district or community, with no condo-building entry at the end of location. Group by the last location entry without checking its type and those get pooled into a fake building named after the district.

Bigger flats yield less, in almost every building. The building median was 7.4% for studios (170 buildings), 6.4% for one-bedrooms, 5.7% for two-bedrooms (268) and 5.2% for three-bedrooms (62). Compare yields within one bedroom count, never across them.

These are gross yields on asking figures. They leave out service charges, which also differ by building, and vacancy, agency fees and the discount between asking and agreed prices. Use them to rank buildings, then check the ones you like.

Where to go from here

The next step is service charges per building, to turn the gross ranking into a net one, and running the same snapshot every month to see which buildings hold their yield. The Bayut API is on RapidAPI, with Python examples in the GitHub repo and an overview of every endpoint in the Bayut API article on LinkedIn.

If you would rather have every Bayut listing with its price history as a file, that is the Bayut listings dataset. For anything else, get in touch.

Top comments (0)