Airbnb Full-Year Price Scraper
Pricing
from $4.00 / 1,000 results
Airbnb Full-Year Price Scraper
Returns one row per calendar day for the next 12 months of any Airbnb listing, with the actual nightly price filled in. Unlike availability-only scrapers, this resolves real prices by calling Airbnb's booking API per day.
Pricing
from $4.00 / 1,000 results
Rating
5.0
(1)
Developer
Crikit
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
3
Monthly active users
8 days
Issues response
4 days ago
Last modified
Categories
Share
Get the real host-set nightly price for every bookable day of any Airbnb listing, for up to 24 months ahead. One row per calendar date, with availability flags, minimum-stay rules, instant-book status, and the actual booking-quote price (including any host or platform discount) populated for every bookable day.
This is the actor you reach for when you need real Airbnb pricing over a full year for revenue management, comp analysis, market research, or short-term-rental dashboards. It calls Airbnb's calendar API for availability and Airbnb's booking-quote API per window to resolve the exact price your guests see when they click "Reserve."
Why this exists
Other Airbnb calendar scrapers on Apify all use PdpAvailabilityCalendar, which is the obvious endpoint and which returns price: null for every day. They ship that null and call it done.
This actor uses Airbnb's StaysPdpBookItQuery with the right combination of fragment-include flags to unlock the full pricing payload. You get the same numbers a guest sees on the listing page: nightly rate, total, original price, discounted price, discount amount, instant-book eligibility, and host booking tips.
What you give it
| Field | Type | Required | Notes |
|---|---|---|---|
listingUrls | array of URLs | yes | Airbnb listing URLs like https://www.airbnb.com/rooms/18850420. Paste as many as you want; each is processed independently. |
currency | string | no, default USD | ISO-4217 currency code. Airbnb does the conversion server-side. |
adults | integer | no, default 2 | Guest count used in booking quotes. Some listings price per guest. |
monthsAhead | integer | no, default 12 | How many months of calendar to scrape (1–24). |
maxItems | integer | no | Optional hard cap on the total number of rows pushed across all listings. Each row is one calendar day billed at the per-row rate, so this is your cost ceiling. Leave empty for no cap. |
proxyConfiguration | object | no | Defaults to Apify Residential Proxy. Required for sustained throughput. |
Past calendar dates (days before today) are always filtered out, and every bookable day is always priced — there is nothing to configure for that.
What you get back
One row per calendar date per listing. The fields below are grouped by purpose.
The two fields you actually filter on
| Field | Type | Notes |
|---|---|---|
isBookable | boolean | True iff Airbnb returned a real bookable price for this day. This is the field to filter on. (available=true does NOT imply bookable; see "Important: available ≠ bookable" below.) |
notBookableReason | string | null | When isBookable=false, machine-readable reason: blocked_by_host, run_shorter_than_min_nights(...), no_checkin_eligible_day_in_run(...), no_checkin_anchor_covers_this_day(...), available_but_no_earlier_checkin_in_run, bookit_rejected:<msg>, bookit_returned_no_price, bookit_probe_failed:<err>. |
Identity & calendar
| Field | Type | Notes |
|---|---|---|
listingId, listingUrl, listingTitle | string | Identity. |
listingLatitude, listingLongitude | number | Coordinates. |
calendarDate | string | YYYY-MM-DD. |
available | boolean | Host's calendar marks this date open. Does not mean bookable — see warning below. |
bookable | boolean | Raw calendar API field. Less reliable than isBookable; kept for completeness. |
availableForCheckin, availableForCheckout | boolean | Per the calendar API. |
minNights, maxNights | integer | Min/max stay length anchored on this date. |
Pricing (populated when isBookable=true)
| Field | Type | Notes |
|---|---|---|
currency | string | ISO-4217. |
nightlyPrice, nightlyPriceFormatted | number, string | The per-night rate Airbnb's booking page shows for this window. |
originalPrice, originalPriceFormatted | number, string | Window total before any host discount. |
discountedPrice, discountedPriceFormatted | number, string | Window total after the discount. |
discountAmount | number | Absolute discount on the window. |
priceAfterDiscount, priceAfterDiscountFormatted | number, string | Subtotal after discount, before taxes. |
totalForWindow, totalForWindowFormatted | number, string | Top-line price for the priced window. |
priceWindowNights | integer | Number of nights the priced window covers. |
priceWindowCheckin, priceWindowCheckout | string | Exact [checkin, checkout] sent to Airbnb's booking API to produce this row's price. Multiple consecutive rows may share these when one BookIt call covers several stay nights. |
priceBreakdown | array | Itemized: per-night subtotal, discount lines, fees, taxes. |
priceQualifier, priceAccessibilityLabel | string | Display strings, e.g. "for 5 nights", "$5,046 for 5 nights, originally $6,182". |
integratedTip, promotionAnnouncement | string | Booking tips and promo banners. |
Bookability metadata
| Field | Type | Notes |
|---|---|---|
bookItAvailable | boolean | The raw availability.isAvailable from BookIt for the probed window. (Use isBookable for filtering; this is the unprocessed flag.) |
canInstantBook | boolean | Instant-book eligibility. |
unavailabilityMessage | string | Reason Airbnb gives when BookIt rejected the window. |
adults, scrapedAt | integer, string | Quote context. |
Important: available ≠ bookable
Airbnb's calendar marks a day available=true whenever the host hasn't blocked it — even when the day cannot actually be booked. Common reasons:
- Host's min-night > the run of open days: a 3-night-minimum listing with two open days between blocks reports both as
available=true, but no real guest can book them. We mark theseisBookable=falsewithnotBookableReason="run_shorter_than_min_nights(...)". - Day is open for staying but not for check-in: the last day of an open run can be a check-out day for someone who arrived earlier, but you can't start a new booking on it. The actor places windows so these days are priced only when an earlier anchor covers them.
- Host has a 99-night, weekly-only, or monthly-only rule: long-stay-only listings will show most days as
available=trueeven though only check-in-eligible anchors at the start of a long run can produce a booking.
Always filter on isBookable=true if you want days that have a real price. If you also want to understand WHY some available=true days aren't bookable, read notBookableReason.
Coverage you should expect
After this actor's window-builder anchors probes on availableForCheckin=true days, coverage on truly-bookable days is 100% across every listing we've audited. The variance below is in priced / available, not priced / bookable:
| Listing pattern | typical priced / available |
|---|---|
| Flexible short-stay (1–2 night min, plenty of open days) | 95–100% |
| Standard 2–3 night minimum, open runs of a week or more | 80–100% |
| Strict 5-night minimum or weekend-only restrictions | 50–70% |
| Mostly-blocked calendars with isolated 1–2 day gaps below the min-stay | 0–10% |
| 99-night-only minimum listings | 30–50% |
Recent ground-truth audit: 67 random ground-truth probes across 12 listings (Mountain View, NYC, Lisbon, Luxury NYC w/ 99-night min, Paris ×2, London ×2, Tokyo ×2, Sydney ×2). Zero false positives, zero false negatives. Each priced row was verified by re-querying the exact [priceWindowCheckin, priceWindowCheckout] window the actor used and confirming Airbnb still returns the same isAvailable=true plus a non-null price.
Pricing
Flat $0.008 per daily-price row. A full year of one listing is 365 rows = $2.92.
The leading competitor charges $0.003 per row plus $0.01 extra per priced date = $0.013 per priced day. They also return null prices for every day. We are 38% cheaper AND actually deliver the price.
| Workload | Rows | Cost |
|---|---|---|
| 1 listing, 12 months | 365 | $2.92 |
| 10 listings, 12 months | 3,650 | $29.20 |
| 100 listings, 12 months | 36,500 | $292.00 |
How it works under the hood
-
Availability grid. One call to
PdpAvailabilityCalendarreturns 12 months of day-level data (available,availableForCheckin,availableForCheckout,minNights,maxNights,bookable). -
Window construction (true per-day pricing). The actor walks the calendar finding contiguous available runs. For each run:
- Places an
M-night booking-quote window at everyavailableForCheckin=trueday, whereMis that day'sminNights. Each check-in-eligible day'snightlyPriceis the per-night rate of a minimum-length stay starting on that exact day — the same number Airbnb shows on its booking sidebar if you pick that check-in. ForminNights=1listings this collapses to a literal per-day price. - Stay-only and trailing days (open for staying but not check-in-eligible) inherit the full price object from the most-recent anchor whose stay range includes them (latest-anchor-wins), so every covered day carries a complete pricing record. Day-of-week price variation (e.g. a Friday check-in pricing higher than a Tuesday) surfaces directly because every check-in day gets its own quote.
- If the run has no eligible anchor, OR the anchor's
minNightsexceeds the remaining run, the days are correctly markedisBookable=falsewith a specificnotBookableReason. - Adaptive M+1 retry: when Airbnb rejects an
M-night probe with a minimum-stay message (common on weekend check-ins, where the effective minimum is higher than the listing's baseminNights), the actor automatically retries withM+1nights. - If the calendar reports the run as too short for
minNightsat an eligible anchor, the actor still pushes a speculativeminNights-long probe — Airbnb's calendar and BookIt occasionally disagree, and the speculative probe recovers a small set of real bookings the calendar would otherwise miss.
- Places an
-
Booking-quote probe. For each window, the actor calls
StaysPdpBookItQuerywith all five fragment-include flags set to true (includePdpMigrationBookIt{CalendarSheet,FloatingFooter,Nav,Sidebar}FragmentplusincludeOverviewMerchandisingTipsFragment). With those flags, the response carries the full booking-sidebar payload:structuredDisplayPricewithdiscountedPrice,originalPrice, per-night breakdown, plus availability, instant-book, and merchandising tips. (Without them, the response is the empty node skeleton, which is why competing scrapers ship null prices.) -
Row emission. One row per calendar date. Days covered by a successfully-priced window get the full pricing payload; days that aren't get
isBookable=falseand anotBookableReason. -
Rate-limit handling. Airbnb's API sits behind Akamai with per-IP rate limits. The actor uses Apify Residential Proxy with per-request session rotation: every API call gets a fresh upstream IP, so 429s don't cascade.
Limits to be aware of
- Calendar window cap. Airbnb's calendar endpoint silently clamps
count > 12to 12. The actor stitches multiple calls automatically whenmonthsAhead > 12. - Data freshness. Airbnb's calendar mutates as bookings happen in real time. The actor returns a snapshot at scrape time; if a date gets booked five minutes after your run, your dataset won't reflect that. For ongoing monitoring, schedule the actor on a cadence that matches your use case (hourly for pricing surveillance, daily for revenue tracking).
- Per-night pricing semantics.
nightlyPriceis the per-night rate of a minimum-stay starting on that calendar day — the same number Airbnb shows on its booking sidebar for that check-in. Because the actor anchors a fresh quote on every check-in-eligible day, real day-of-week variation surfaces directly; forminNights ≥ 2listings a stay-only day reports the rate of the most recent stay that covers it (which is exactly what a guest inside that booking would pay). - Currency conversion is server-side. Pass
currency=EURand Airbnb returns EUR prices.
FAQ
Why is this cheaper than the next-best competitor? They charge $0.003 per row plus $0.01 extra per priced row. A priced year is 365 × $0.013 = $4.75. We charge $0.008 flat per row = $2.92, and we actually return the price.
Does the actor return the same price I'd see if I clicked "Reserve" on the listing page? Yes. The booking-quote API the actor hits is the same one your browser hits when it renders the booking sidebar. Discounts, promotional rates, and instant-book status are what a guest would see.
Why are some available=true days unpriced?
Because available on Airbnb's calendar just means "host hasn't blocked it" — it doesn't mean a real booking can land there. Check isBookable and read notBookableReason to see why. Common reasons: surrounding run shorter than min-stay, no check-in-eligible day, or BookIt explicitly rejected the probed window.
Can I scrape multiple listings in one run?
Yes. Paste any number of URLs into listingUrls. The actor processes up to three listings at a time and fans each one out across many concurrent booking-quote calls, automatically scaling the fan-out so the total number of concurrent proxy sessions stays in a safe range (a single-listing run gets the full session budget, so it runs fastest).
Does this require my login or session cookie? No. Airbnb's public API key is hardcoded into every airbnb.com page; the actor uses that. No authentication, no PII.
Changelog
-
0.5: stability, cost-control, and speed pass.- True per-day pricing is now the only mode. The actor always anchors a booking quote on every check-in-eligible day (what was previously
pricingMode: 'perfect'). ThepricingMode,priceWindowNights,includePastDates,fetchPrices, andonlyAvailableDaysinputs were removed — they no longer existed in the running code, so the documentation was brought in line with reality.listingIdswas also removed; pass listings vialistingUrls. maxItemscost cap (restored). An optional hard ceiling on total rows pushed across all listings, so a large multi-listing run can't run away on cost.- Run-stability fix. A listing that errors out now records a schema-conforming marker row instead of pushing a row that the dataset validator rejects — the previous behavior could fail the entire run (and lose every other listing's data) on a single bad listing.
- Never-empty guarantee. Empty calendars, all-invalid input, and zero-result runs now emit a clear marker row instead of finishing with zero rows (which Apify scores as a failed daily health check).
- Faster single-listing runs. BookIt fan-out concurrency now scales to the number of listings in flight, so a single-listing run uses the full proxy-session budget (~2× the previous fixed concurrency) while multi-listing runs stay under the proxy pool's queueing threshold.
- Removed an unused dependency (smaller, faster builds) and pinned dependency versions for reproducible builds.
- True per-day pricing is now the only mode. The actor always anchors a booking quote on every check-in-eligible day (what was previously
-
0.3.6:pricingMode: 'perfect'— true per-day pricing.- Places an M-night booking-quote window at every
availableForCheckin=trueday, where M = the listing'sminNights. Each FCI day'snightlyPriceis the per-night rate for a minimum-length stay starting on that day — the same number Airbnb shows on the booking sidebar if you pick that checkin. - Adaptive M+1 retry: when Airbnb rejects an M-night probe with a minimum-stay error (it often does on weekend checkins where the effective minN > the base minN), the actor automatically retries with M+1 nights. This recovered every previously-rejected day in audit testing.
- Latest-anchor-wins propagation: stay-only days (non-FCI / trailing days) inherit the full price object from the most-recent anchor whose stay range includes them. So every day in a covered run gets the right price with full pricing metadata, not just FCI days.
- Coverage at parity or above
automode: on the user-flagged Mountain View listing, perfect mode now prices 63/63 available days (auto prices 62) while ALSO revealing the full day-of-week structure (Mon $1473 trough → Fri $2334 peak, etc). - Ground truth: 6/7 priced rows exactly match direct BookIt re-probes across 4 listings in 4 currencies (the one off-by-$2.76 row reflects live host-price changes between the scrape and the verification probe — Airbnb's data is mutable).
- Cost: roughly 2x
automode (one window per FCI day vsauto's tiled non-overlapping windows). Worth it whenever day-of-week pricing matters.
- Places an M-night booking-quote window at every
-
0.2.4: speed pass + sliding-window pricing.- 2-11x faster on single-listing runs (typical 12-month run drops from ~63s to ~30s; the user-flagged Mountain View listing went from 147s to 13s).
- 3.5x faster on multi-listing runs via tighter retry budget (3 attempts × 12s timeout, was 4 × 20s) — stops one slow listing from starving the others.
- Sliding-window pricing (the user-requested feature): an 8-day open run on a 3-night-min listing now produces three 3-night windows (days 1-3, 4-6, 6-8 with overlap), not one 5-night + one 3-night. Per-night prices are derived from windows whose stay length matches the host's
minNightsinstead of a fixed 5-night blend, giving materially better day-by-day resolution. Controlled bypricingMode(auto/fast/accurate/precise) andpriceWindowNightsoverride. - Past-date filter: rows for dates before today are now suppressed by default (Airbnb's calendar returns the full calendar month containing today). Set
includePastDates=trueto keep them. - Currency fix: CAD/AUD/MXN/SGD/HKD/NZD/BRL listings no longer have
currency: "USD"written into rows when the$symbol appears in price strings. Detection now recognises 2-letter dollar prefixes (CA$, AU$, etc.) and trusts the input currency as the authoritative answer. - Calendar + title fetched in parallel: shaves ~3-5s off every listing's wall time.
- Calendar pagination is now parallel when
monthsAhead > 12. - Tail-slide windows: when an available run is shorter than the ideal window length, a backward-shifted
minNightswindow covers the tail without leaving days unpriced. - Higher worker concurrency (16 BookIt workers per listing, 3 parallel listings) with a calibrated total cap of ~48 concurrent calls — enough to saturate Airbnb's BookIt latency without choking the Apify residential proxy pool.
- Batch
Actor.pushDatafor ~10x less I/O overhead.
-
0.1.10: addedpriceWindowCheckinandpriceWindowCheckoutto every priced row so customers (and our audit tooling) can reconstruct the exact booking that produced the price. -
0.1.9: speculative-probe fallback for calendar/BookIt disagreement on min-stay edges. -
0.1.8: addedisBookable(computed) andnotBookableReasonfields. Dataset overview view now surfaces them so customers can see whichavailable=truedays are not actually bookable, and why. -
0.1.7: availability-aware window builder. Windows now anchor onavailableForCheckin=truedays inside contiguous available runs; previously windows could start on blocked days, stranding bookable days with null prices. -
0.1.3: prefill listing changed to a higher-coverage example. -
0.1.2: proxy-undefined guard, leading-zero listing-ID normalization, permanent-error short-circuit on bad IDs. -
0.1.1: initial release — calendar + per-window booking-quote pipeline, residential-proxy rotation, multi-listing concurrency.
