Beginner
10 min

Airbnb Occupancy Rates by City

Pull real occupancy data with percentile breakdowns for any market worldwide. Compare average hosts to top performers and benchmark your own property.

1

Find Market IDs

Search for any city using the /markets/search endpoint. The response includes the full_name, country, region, and locality fields that you need to construct the market object used in all subsequent calls.

Python

import requests

API_KEY = "your_api_key"
BASE_URL = "https://api.airroi.com/v1"
headers = {"X-API-KEY": API_KEY}

# Search for a market
response = requests.get(
    f"{BASE_URL}/markets/search?query=nashville",
    headers=headers
)
results = response.json()

market = results[0]
print(f"Market: {market['full_name']}")
print(f"Country: {market['country']}")
print(f"Region: {market['region']}")
print(f"Locality: {market['locality']}")
print(f"Active listings: {market['active_listings_count']:,}")

# Save the market object for subsequent calls
market_obj = {
    "country": market["country"],
    "region": market["region"],
    "locality": market["locality"]
}

2

Pull Occupancy Metrics

Call /markets/metrics/occupancy with your market object and num_months: 12 to get monthly occupancy data. Each month includes the market average (avg) and percentiles (p25, p50, p75, p90) so you can see how occupancy is distributed across all listings.

Python

# Pull 12 months of occupancy data with percentiles
payload = {
    "market": market_obj,
    "num_months": 12
}

response = requests.post(
    f"{BASE_URL}/markets/metrics/occupancy",
    json=payload,
    headers={**headers, "Content-Type": "application/json"}
)
occupancy_data = response.json()

print(f"{'Month':<12} {'Avg':>6} {'p25':>6} {'p50':>6} {'p75':>6} {'p90':>6}")
print("-" * 48)
for month in occupancy_data:
    print(f"{month['date']:<12} "
          f"{month['avg']:>5.0%} "
          f"{month['p25']:>5.0%} "
          f"{month['p50']:>5.0%} "
          f"{month['p75']:>5.0%} "
          f"{month['p90']:>5.0%}")

3

Average vs Top Performers

Compare the market-wide average occupancy against p90 (top 10% performers). The spread between them reveals how much room there is to outperform. A large spread means top hosts are doing something materially different — better pricing, more reviews, professional photography, or superior amenities.

Python

# Compare average vs top performers
import statistics

avg_occupancies = [m["avg"] for m in occupancy_data]
p90_occupancies = [m["p90"] for m in occupancy_data]

overall_avg = statistics.mean(avg_occupancies)
overall_p90 = statistics.mean(p90_occupancies)
spread = overall_p90 - overall_avg

print(f"Market average occupancy: {overall_avg:.0%}")
print(f"Top 10% (p90) occupancy: {overall_p90:.0%}")
print(f"Spread: {spread:.0%}")
print()

if spread > 0.25:
    print("Large spread — top performers significantly outpace the average.")
    print("This suggests room for optimization if you can match")
    print("what the top 10% are doing (better listing, pricing, reviews).")
elif spread > 0.15:
    print("Moderate spread — top hosts do noticeably better.")
    print("Focus on pricing strategy and listing quality to move up.")
else:
    print("Narrow spread — the market is fairly uniform.")
    print("Occupancy is less about skill and more about market conditions.")

4

Filter by Bedrooms

Add a filter parameter with bedrooms: { eq: 2 } to see how property size affects occupancy. Compare 1-bedroom, 2-bedroom, and 3-bedroom properties to understand which segment has the strongest demand in your target market.

Python

# Filter by bedrooms to see how property size affects occupancy
bedroom_counts = [1, 2, 3]
bedroom_data = {}

for br in bedroom_counts:
    payload = {
        "market": market_obj,
        "filter": {"bedrooms": {"eq": br}},
        "num_months": 12
    }

    response = requests.post(
        f"{BASE_URL}/markets/metrics/occupancy",
        json=payload,
        headers={**headers, "Content-Type": "application/json"}
    )
    bedroom_data[br] = response.json()

# Compare annual average occupancy by bedroom count
print(f"{'Bedrooms':<10} {'Avg Occ':>8} {'p50 Occ':>8} {'p90 Occ':>8}")
print("-" * 36)
for br, data in bedroom_data.items():
    avg = statistics.mean([m["avg"] for m in data])
    p50 = statistics.mean([m["p50"] for m in data])
    p90 = statistics.mean([m["p90"] for m in data])
    print(f"{br} BR{'':<6} {avg:>7.0%} {p50:>7.0%} {p90:>7.0%}")

5

Seasonal Stability

Compare cities with stable year-round occupancy against highly seasonal markets. Calculate the coefficient of variation (standard deviation / mean) as a stability metric. A CV below 0.15 indicates a stable market, while above 0.30 signals high seasonality where you should plan for income gaps.

Python

# Compare seasonal stability across markets
import statistics

cities_to_compare = [
    {"query": "austin", "label": "Austin (year-round)"},
    {"query": "park city", "label": "Park City (seasonal)"},
]

for city_info in cities_to_compare:
    # Search market
    search = requests.get(
        f"{BASE_URL}/markets/search?query={city_info['query']}",
        headers=headers
    ).json()

    if not search:
        continue

    m = search[0]
    payload = {
        "market": {
            "country": m["country"],
            "region": m["region"],
            "locality": m["locality"]
        },
        "num_months": 12
    }

    data = requests.post(
        f"{BASE_URL}/markets/metrics/occupancy",
        json=payload,
        headers={**headers, "Content-Type": "application/json"}
    ).json()

    monthly_avg = [d["avg"] for d in data]
    mean_occ = statistics.mean(monthly_avg)
    std_occ = statistics.stdev(monthly_avg)
    cv = std_occ / mean_occ  # Coefficient of variation

    print(f"{city_info['label']}:")
    print(f"  Mean occupancy: {mean_occ:.0%}")
    print(f"  Std deviation:  {std_occ:.0%}")
    print(f"  CV (stability): {cv:.2f}")
    print(f"  Verdict: {'Stable' if cv < 0.15 else 'Seasonal' if cv < 0.30 else 'Highly seasonal'}")
    print()

6

Benchmark Your Property

If you have an active listing, pull its occupancy via /listings/metrics/all and compare it month by month against the market percentiles. See exactly where you rank: below p25 (underperforming), between p25 and p75 (average), above p75 (strong), or above p90 (exceptional).

Python

# Benchmark your listing against market percentiles
listing_id = "your_listing_id"  # Your Airbnb listing's AirROI ID

response = requests.get(
    f"{BASE_URL}/listings/metrics/all?id={listing_id}&num_months=24",
    headers=headers
)
listing_metrics = response.json()

# Compare listing occupancy vs market percentiles
print(f"{'Month':<12} {'Your Occ':>8} {'Mkt Avg':>8} {'Mkt p75':>8} {'Mkt p90':>8} {'Rank':>14}")
print("-" * 56)

for listing_month in listing_metrics[-12:]:
    date = listing_month["date"]
    my_occ = listing_month["occupancy"]

    # Find matching market month
    market_month = next(
        (m for m in occupancy_data if m["date"] == date), None
    )
    if not market_month:
        continue

    # Determine rank
    if my_occ >= market_month["p90"]:
        rank = "Exceptional"
    elif my_occ >= market_month["p75"]:
        rank = "Strong"
    elif my_occ >= market_month["p25"]:
        rank = "Average"
    else:
        rank = "Below avg"

    print(f"{date:<12} {my_occ:>7.0%} {market_month['avg']:>7.0%} "
          f"{market_month['p75']:>7.0%} {market_month['p90']:>7.0%} "
          f"{rank:>14}")

Continue Learning

Keep exploring the AirROI API with these related tutorials.

Frequently Asked Questions

Average Airbnb occupancy rates vary significantly by city, season, and property type. National averages typically fall between 50-65%, but top-performing markets like Nashville, Austin, and Miami often see 70-80%+ average occupancy. Use the AirROI API to pull exact, current figures for any specific market.

Percentiles show how occupancy is distributed across all listings in a market. p25 means 25% of listings have this occupancy or lower (bottom quartile). p50 is the median. p75 means only 25% of listings perform better. p90 represents the top 10% of performers. The spread between p25 and p90 shows how much the best hosts outperform the average.

Typically, 1-bedroom and 2-bedroom properties have the highest occupancy rates because they serve the largest traveler segment (couples and small families). 4+ bedroom properties often have lower occupancy but higher nightly rates and total revenue. Use the bedroom filter to compare how occupancy shifts by property size in your target market.

A good occupancy rate depends on your market and strategy. Generally, above the market p50 (median) is solid, above p75 is strong, and above p90 is exceptional. However, some hosts intentionally target lower occupancy with higher rates to maximize revenue per guest while reducing wear and tear.

Calculate the coefficient of variation (standard deviation / mean) of monthly occupancy over 12 months. A CV below 0.15 indicates a stable, year-round market (like Austin or Miami). A CV above 0.30 indicates high seasonality (like ski resorts or beach towns). This tutorial shows you exactly how to calculate this.

The /markets/metrics/occupancy endpoint supports filtering by bedrooms, bathrooms, and other property attributes. For more advanced filtering by amenities or property type, use the /listings/search/market endpoint with filters and then aggregate the occupancy data from individual listings.

Market-level occupancy metrics are updated monthly. The data reflects actual booking patterns observed across all active listings in the market. For the most recent month, data becomes available shortly after the month closes.

Ready to Build?

Get your API key and start making calls in minutes.
made with