Airbnb Scraper — Listings, Prices & Photos avatar

Airbnb Scraper — Listings, Prices & Photos

Pricing

from $1.25 / 1,000 listings

Go to Apify Store
Airbnb Scraper — Listings, Prices & Photos

Airbnb Scraper — Listings, Prices & Photos

Scrape Airbnb listings: prices, photos, ratings, coordinates, room details. Price split into list rate, discounts and taxes so it reconciles. Market percentiles and price changes. No host data.

Pricing

from $1.25 / 1,000 listings

Rating

0.0

(0)

Developer

Daniel

Daniel

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

24 days ago

Last modified

Share

Scrape Airbnb search results for any location: nightly prices, photos, ratings, review counts, coordinates, room details and availability. Fast, priced per listing, and no scraping infrastructure to run.

Where it differs from other Airbnb scrapers is the price. Airbnb's headline figure hides what is inside it, and most exports pass that figure straight through. This one takes the stay apart.

What you get

Listing data — name, property type, neighborhood, bedrooms, beds, baths, coordinates, rating, review count, Guest Favorite badge, photo URLs, direct link.

Prices that reconcile — every row breaks the stay into list rate, discounts, taxes and final total, so base − discounts + taxes = total holds on every line. This matters more than it sounds. A Barcelona listing in our own test data advertises €221.97/night and charges an effective €148.36 after a long-stay discount — a third less. An export carrying one "price" field is quietly telling you one of those two numbers and not saying which. You get pricePerNight (what the host advertises) and effectiveNightlyRate (what a guest pays) as separate fields, plus a totalIncludesTaxes flag because some markets, Amsterdam among them, fold tourist tax into the total without itemising it.

Multi-unit inventory — professional operators running several units of one property carry an inventory line instead of a room count. Most exports drop it, or worse, mis-read "3 apartments available" as a bedroom count. Here it becomes unitsAvailable plus the raw wording, which also carries scarcity ("1 apartment left").

It separates markets sharply. In our own test runs, the first 50 results for Barcelona returned 23 multi-unit properties — 22 Rental unit and one Serviced apartment. The identical query against Porto, Austin and Mexico City returned none at all: those results were private apartments, condos and lofts. If you benchmark a listing against "comparable" ones without that distinction, you may be pricing an owner's spare flat against a professional operator's building.

Market position — where each listing's rate sits in the market (percentile) and how far it is from the median.

What changed since your last run — price moves in currency and percent, new reviews, and a new / changed / unchanged status. Delisted properties are counted in the summary.

Occupancy and revenue estimates — reviews per month, estimated occupancy, estimated monthly revenue.

Market summary — median, 25th and 75th percentile rates, min/max, average rating, Guest Favorite share, new and removed listing counts, median price movement. Delivered nested on every row and under the MARKET_SUMMARY key, so a single dataset call is enough for no-code integrations.

Also included, at no extra charge

Market position — each listing's price percentile and distance from the market median, plus a market summary with median, quartiles, average rating and Guest Favorite share. You pay for listings; the aggregates come with them.

Run-to-run changes — run the same search again and every row reports what moved: price change in currency and percent, new reviews, and a new / changed / unchanged status. Delisted properties are counted in the summary. Nothing to configure; it keys off the search you already ran.

Occupancy estimates — derived from review growth between runs, so they appear from the second run onwards. See the section below for the method and its assumptions.

Who uses this

  • Developers and data teams — a clean, per-listing feed to load straight into your own pipeline.
  • Short-term rental hosts and managers — see where your rate sits against comparable listings, and catch competitors repricing.
  • Investors and analysts — measure ADR, price dispersion and booking pace before committing to a market.
  • Researchers — reproducible market snapshots with the aggregate math already done.

Sample output

{
"listingId": "652910731756745793",
"name": "Chic 1-BR by Rua Augusta Arch",
"roomType": "Condo",
"neighborhood": "Santo António",
"bedrooms": 1,
"beds": 4,
"baths": 1.5,
"lat": 38.70767,
"lng": -9.13672,
"rating": 4.92,
"reviewCount": 198,
"pricePerNight": 92.89,
"effectiveNightlyRate": 89.04,
"basePrice": 278.66,
"discountTotal": 11.53,
"taxes": 56.09,
"totalPrice": 323.22,
"nights": 3,
"currency": "USD",
"totalIncludesTaxes": true,
"isGuestFavorite": true,
"unitsAvailable": null,
"availabilityNote": null,
"photoCount": 5,
"photos": [
"https://a0.muscache.com/im/pictures/miso/Hosting-652910731756745793/original/3cc7538b.jpeg",
"https://a0.muscache.com/im/pictures/miso/Hosting-652910731756745793/original/31311278.jpeg"
],
"url": "https://www.airbnb.com/rooms/652910731756745793",
"pricePercentile": 87.5,
"priceVsMarketMedianPct": 39.99,
"status": "changed",
"priceChange": 10,
"priceChangePct": 6.5,
"reviewCountChange": 2,
"daysSincePreviousRun": 7,
"reviewsPerMonth": 8.57,
"estimatedOccupancy": 46.7,
"estimatedMonthlyRevenue": 2288.26,
"occupancyBasis": "review_delta",
"market": {
"listingCount": 36,
"priceMedian": 122.9,
"priceP25": 116.03,
"priceP75": 161.34,
"ratingAvg": 4.79,
"guestFavoriteShare": 38.89,
"newListings": 10,
"removedListings": 10,
"medianPriceChangePct": 0,
"avgEstimatedOccupancy": 61.2
},
"scrapedAt": "2026-08-10T03:59:30.643Z"
}

Input

FieldDefaultNotes
locationLisbon, PortugalUse a City, Country form.
checkIn / checkOutnonePass these. See the note below.
adults2Guest count used for pricing.
maxListings50Caps both results and cost. Maximum 270.
currencyUSDAll prices come back in this currency.
trackChangestrueStores a snapshot so the next run can report changes.
reviewRate0.5Occupancy model — share of stays leaving a review.
avgStayNights3.5Occupancy model — average nights per booking.

The defaults run as-is and return a usable Lisbon market scan without editing anything.

Always pass check-in and check-out dates. Without them Airbnb picks a different date window for each listing — one priced for a 5-night August stay, the next for a 5-night September stay. The rates then are not comparable to one another, and the percentiles built from them are meaningless. The Actor warns you when dates are missing.

Pricing

Pay per event, $1.25 per 1,000 listings. A 50-listing scan costs $0.06.

Photos, the price breakdown, market percentiles, change tracking and occupancy estimates are all included. You pay per listing, and for nothing else.

How the occupancy estimate works

Airbnb does not publish occupancy, so every tool in this space infers it. This one measures review growth between your runs:

bookings = new reviews ÷ reviewRate
booked nights = bookings × avgStayNights
occupancy = booked nights ÷ days elapsed

Both assumptions are inputs, not hidden constants — if you have better figures for your market, set them and the numbers move with you.

What this means in practice:

  • The first run cannot report occupancy. There is no history to measure against yet. Those fields come back null with occupancyBasis: "insufficient_history".
  • Runs less than 3 days apart are rejected for occupancy. Over a short window a single review would imply a fully booked month. The listing data still comes back normally.
  • Weekly runs give the cleanest signal. Review pace is noisy day to day and settles over a week or more.

Deliberate design choice: an occupancy number derived from a lifetime review count and a guessed listing age would be available on run one, and would be fiction. This returns nothing until it can measure something real.

Change tracking

Snapshots are keyed by market slice — location, dates, guest count and currency together. Run the same configuration again and you get the deltas. Change any of those and you are tracking a different market, so the comparison restarts.

This is what makes the Actor worth scheduling: set it weekly and you accumulate a price and booking-pace history for your market instead of one disconnected export.

Use it from an AI agent (MCP)

This Actor works as a tool for AI agents through the Apify MCP server — no extra setup on your side. An agent connected to it can find this Actor with search-actors, read its parameters with fetch-actor-details, and run it with call-actor.

The input schema is written to be read by a model, not just by a person: date formats are stated explicitly, cost-bearing parameters say that they bear cost, and every field that stays empty on a first run says so. An agent should get a usable call right the first time.

A minimal call needs nothing but a location:

{ "location": "Lisbon, Portugal" }

A precise one pins the dates so the rates are comparable:

{
"location": "Lisbon, Portugal",
"checkIn": "2026-09-15",
"checkOut": "2026-09-18",
"maxListings": 50,
"currency": "EUR"
}

Bad input fails fast with a message that says how to fix it, rather than burning a run on a meaningless window.

Limits, stated plainly

  • 270 listings per market slice, maximum. That is Airbnb's own pagination ceiling for a search, not a limitation added here. For a large city, that is the top-ranked slice, not every property in town. To go deeper, run several narrower searches — by neighborhood, by date window, or by guest count.
  • Adjacent result pages overlap. The Actor fetches a spare page to absorb it, but very small or very specific markets may still return fewer listings than requested.
  • Percentiles are built on the list rate, not the effective one, because that is the number a host sets and competitors compare against. effectiveNightlyRate is there if you would rather rank by what guests pay.
  • neighborhood is whatever Airbnb puts in the headline, which for some listings is the city rather than a district. Check headlineCoverage in the market summary to see how much of the run carried a headline at all.
  • Occupancy is an estimate, not reported data. It is only as good as the two assumptions above.
  • No availability calendar. This reads search results, so a listing missing from results is not proof it is booked — it may simply rank lower.

Data and privacy

This Actor returns no personal data. Host names, host IDs, profile photos and profile links are dropped before anything is written, deliberately and by design. What comes back is commercial fact about an accommodation: type, size, location, price, rating, review count.

It reads only publicly visible search results, logged out. It does not sign in, does not bypass any technical restriction, and does not republish listing photos or description text — only extracted facts.

FAQ

Does it work for any city? Any market Airbnb recognises. Use a City, Country form. If a location returns nothing, the run fails with a clear message rather than charging you for an empty result.

Why is bedrooms sometimes empty? Shared rooms and hotel rooms are listed by Airbnb without a bedroom count. beds is still populated.

Can I run this on a schedule? Yes, and it is built for it. Use Apify Schedules with the same input and each run reports what changed since the last.

Do I need a proxy? No. Proxy is optional and set to automatic by default. If your proxy is unavailable the run continues rather than failing.

Can I get the data into Sheets, Make or Zapier? Yes. Every row is the same shape and carries the market aggregates nested under market, so one dataset read gives you both the listings and the market context.