Airbnb Calendar & Date-Specific Nightly Price avatar

Airbnb Calendar & Date-Specific Nightly Price

Pricing

from $8.00 / 1,000 price quotes

Go to Apify Store
Airbnb Calendar & Date-Specific Nightly Price

Airbnb Calendar & Date-Specific Nightly Price

Per-date Airbnb availability plus the real bookable nightly price for those dates, in the currency you request (USD/EUR/GBP/TRY), with per-night breakdown and an explicit capacity flag. Airbnb's calendar returns price:null; this fetches the actual quote. Pay only for delivered data.

Pricing

from $8.00 / 1,000 price quotes

Rating

0.0

(0)

Developer

MaviLinkLabs

MaviLinkLabs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Airbnb Calendar & Real Date-Specific Price Scraper

Get per-date availability for one or many Airbnb listings and the real bookable nightly price for those dates — for an exact date range or months ahead, in the currency you request.

Airbnb's calendar tells you whether a date is free, but its calendar response returns price: null. The real price for a specific date comes from a separate booking quote. This actor fetches that quote and returns it as a structured, honest record.

What it does

  • Per-date availability calendar — up to 12 months, with available, check-in / check-out eligibility, and each date's own minNights / maxNights.
  • Real, date-specific nightly price — for available windows it asks Airbnb's own booking engine for the price quoted for those exact dates, rather than the null the calendar returns. What you get is the total Airbnb displays for that window — which may or may not include tax, depending on the response (see Honest limits; every quote reports which via taxScope) — not a final checkout total.
  • Exact date range OR months ahead — set startDate + endDate for a specific window, or use calendarMonths to look a number of months into the future.
  • One stay in, one quote out — if you ask for one specific stay (startDate + endDate), you get exactly one quote for exactly that stay, and you are charged for exactly that one quote. The actor does not add sampled side-quotes you did not ask for. See Asking for one stay vs. asking for a price curve below.
  • Two pricing modes:
    • sampled (default) — a handful of quotes spread across months (one per month first), giving a low-cost price curve across the horizon.
    • allAvailableDates — price every eligible check-in date; requires maxPricedDates as an explicit cost budget.
  • Controlled cost, no silent truncation — in allAvailableDates mode the budget is enforced by onCostLimitExceeded: error (default: price nothing for that listing, 0 quote charge, status: "cost-limit-exceeded") or truncate (price the first N chronologically and flag exactly how many dates were omitted).
  • Requested currency — every price is returned in the ISO currency you set (USD, EUR, GBP, TRY, ...), not whatever the listing happens to use.
  • Multiple listings per run — pass a list of room URLs or IDs.
  • Min-stay aware quotes — each quote window respects that date's own minimum-nights rule (or your fixed quoteNights), so quotes don't fail on min-stay mismatches.
  • Explicit guest-capacity handling — you set adults; the actor reads the listing's maxGuests and reports requestedAdults, effectiveAdults, and adultsReducedToFitCapacity. If your guest count exceeds capacity, it re-quotes at the fitting count instead of returning no price — and flags that it did.
  • Structured price breakdownnightlyBase, nights, accommodationSubtotal, subtotal, fees[], discount, taxes, totalPrice, and currency, each read from Airbnb's own price-detail lines instead of being derived by dividing a rounded total. accommodationSubtotal is the accommodation line on its own; subtotal is the pre-tax total; totalPrice is what the lines add up to. Three different numbers, three separate fields — no field is ever used with two meanings.
  • Cent-accurate total — Airbnb's headline price is rounded up for display (a $305.75 stay shows as "$306"). priceRaw / priceTotal keep that displayed value, while priceBreakdown.totalPrice — and the perNight average derived from it — carry the exact figures from the price-detail lines.
  • Long stays are priced as long stays — when Airbnb quotes by the month or week instead of by the night, that line is read as the accommodation (never as a fee) and the period is named. If the window you asked for is not one such period (a 46-night stay priced monthly), the actor reports the monthly rate and withholds the window totals instead of passing a monthly figure off as a 46-night one. See Long stays below.
  • The tax scope is reported, not assumed — Airbnb's response for the same listing and window is not always the same: sometimes it itemizes a Taxes line, sometimes it bundles one Taxes and fees line, sometimes it declares the total is before taxes. Every quote says which one it got via taxScope and totalIncludesTaxes, so a total is never silently mixed up with a pre-tax one.
  • cancellationPolicy and canInstantBook — read from the live listing response, when a quote request is made (see limits below).
  • Pay only for successfully delivered events — calendars and quotes are charged only when real data was delivered.

Asking for one stay vs. asking for a price curve

These are two different questions, and the actor bills them differently.

One stay — you give startDate + endDate and want the price of that stay:

{ "listings": ["..."], "startDate": "2026-09-01", "endDate": "2026-09-05" }

You get one quote for 2026-09-01 → 2026-09-05 and are charged for one price-quote event. The actor treats this as an explicit stay when all of the following hold:

  • both startDate and endDate are set, and
  • pricingMode is sampled (the default), and
  • quoteNights equals the number of nights in the range or is 0 (the default, "use the date's own minimum-nights rule").

In that case no sampled calendar windows are quoted at all — only the stay you asked for.

A price curve — you want many dates priced, not one stay. Use one of:

  • pricingMode: "allAvailableDates" with maxPricedDates — prices every eligible check-in date in the window. This is never treated as an explicit stay, in or out of a date range.
  • calendarMonths without startDate/endDate — sampled quotes spread across the months ahead (one per month first), up to maxQuotesPerListing.
  • startDate/endDate plus a quoteNights that differs from the range length — e.g. a 30-day window with quoteNights: 3 asks "what does a 3-night stay cost across this window", so sampling stays on and you additionally get the whole-window quote.

Known consequence — read this if you use a wide range. sampled + a wide startDate/endDate + quoteNights: 0 is an explicit stay, so a 90-day range returns one quote for a single 90-night stay, not four sampled windows inside it. No calendar sampling happens at all on that path — the single exact quote is the entire price output for the listing.

And if Airbnb will not price that long stay, you get zero quotes for the listing. Very long stays are frequently above a listing's maxNights, or simply not offered, and the actor never invents a price it did not receive: the run then delivers the availability calendar and no price quotes (you are charged for the calendar, and for zero price-quote events). The run log names the window and the reason. If you wanted prices across the span rather than one long stay, use pricingMode: "allAvailableDates" with maxPricedDates, or calendarMonths without a range, or set a quoteNights that differs from the span.

This is documented here as current behavior, not defended as the right default. Open product decision for the next release: whether a wide range + quoteNights: 0 should keep meaning "one long stay" or should fall back to a sampled price curve when the long stay is unpriceable. Behavior is unchanged in this version.

maxQuotesPerListing is a hard cap. In sampled mode, every delivered and charged quote — including the direct quote for your exact window — counts against it. maxQuotesPerListing: 4 with a date range delivers at most 4 quotes, never 5. (In allAvailableDates mode the budget is maxPricedDates; maxQuotesPerListing does not apply there.)

Honest limits (please read)

  • Live quote, not a fixed price. Prices are the live quote at scrape time. Airbnb prices are dynamic and change through the day — re-run for a fresh quote. This actor does not claim a permanent or forever-exact price.

  • Taxes: whatever Airbnb prints, plus a label for what it means. The actor never calls the checkout endpoint and never estimates a tax. It reports the tax lines that are in the response, and taxScope states which situation produced the numbers:

    taxScopemeaningtaxestaxesAndFeesCombinedtotalIncludesTaxes
    taxes-itemizeda separate Taxes line was in the responseamountnulltrue or false
    taxes-and-fees-combinedAirbnb printed one Taxes and fees linenullamounttrue or false
    taxes-itemized-and-combinedboth shapes arrived in the same responseamountamounttrue or false
    ambiguousa tax line exists but the lines do not reconcile with the totalas readas readnull
    before-taxes-declaredno tax line; Airbnb's own total says "before taxes"nullnullfalse
    unclassified-linesno tax line was recognized, but the response carries extra line(s) that were passed through unclassified in fees[] (e.g. VAT, Sales tax, Resort fee)nullnullnull
    no-tax-lineno tax line, no declaration, and no extra line of any kindnullnullnull
    not-classified-localenon-English locale: labels not classified at allnullnullnull
    no-price-detailsthe response carried no price-detail lines; the whole breakdown is nullnullnullnull

    totalIncludesTaxes is decided arithmetically whenever a tax line is present: true if the total equals the sum of all lines, false if it equals the sum without the tax terms, and null (with taxScope: "ambiguous") if neither matches. It is never inferred from wording alone.

    taxesDeferred is true exactly when no tax figure of any kind was isolated (taxes and taxesAndFeesCombined are both null). It does not by itself mean Airbnb charges no tax — read taxScope for that: no-tax-line is the only value that says the response really had nothing extra, while unclassified-lines says extra lines were there and we refused to guess what they were.

    A bundled Taxes and fees line is not split — guessing the tax share of it would be inventing a number, so it is reported as its own field and never as taxes.

  • Whether a total includes tax depends on the response, not on us. The same listing and window can return a tax-inclusive total on one request and a before taxes total on another; we have observed both and do not claim to know why. Read totalIncludesTaxes on the quote rather than assuming.

  • priceBreakdown.fees[] is a passthrough, not a classification. Fee lines are taken from Airbnb's own price-detail line items as {label, amount} with the label exactly as Airbnb localized it (e.g. "Resort fee"). The actor does not decide what a fee means, and it never estimates a fee that Airbnb did not print. A recognized tax line is never put in fees[]. The one exception is a non-English locale, where labels are not classified at all: then every additive line stays in fees[] unclassified and taxScope is not-classified-locale.

  • Unclassifiable prices stay null. If a response does not carry the price-detail lines (or their stay length disagrees with the window that was requested), the breakdown fields are null rather than a plausible-looking guess. On hotel-style listings, where the headline price is read from the display components rather than a flat price field, that price is additionally cross-checked against the price-detail lines: it must be the ceiling of their sum. If it is not, no quote is delivered and none is charged for that window — the mismatch is logged instead of shipping a number we cannot stand behind.

  • Room type / rate plan is Airbnb's default, not a choice you make. The actor does not send a selectedRatePlanId, so Airbnb quotes whatever room type and rate plan it serves by default for that listing and window. Some listings (hotels in particular) label their own breakdown "Price may vary by room type", and the actor passes that reality through rather than hiding it: the quote is the default-room price, not the cheapest or a specific room. Selecting a rate plan is not supported in this version and no field claims otherwise.

  • maxGuests, cancellationPolicy and canInstantBook are read from the booking-quote response (the listing's PDP sidebar), not from the calendar. That means they are populated only when at least one price quote is requested for that listing. If a listing has no priceable dates in the selected window, or you run with enrichPrices: false, these fields stay null. This is deliberate: the actor does not fire an extra request (and an extra charge) just to fill them.

  • When capacity is reduced (adultsReducedToFitCapacity: true), the quoted price is for the reduced guest count that fits the listing, not the number of adults you requested. The reduction is always flagged on the quote (requestedAdults vs effectiveAdults), never hidden.

  • On hotel / multi-room listings, maxGuests describes the default room, not the listing. Airbnb's own response can report maxGuestCapacity: 1 for a hotel whose booking form happily accepts — and prices — three guests. The number is passed through because it is real, but the claim is lowered honestly: maxGuestsReliable is false, maxGuestsScope is "default-room" (versus "listing"), and maxGuestsCaveat states why. Do not treat it as the listing's guest limit.

  • A host discount on your dates does not confuse the breakdown. Airbnb sometimes prints the accommodation line itself as a discounted line (2 nights × $190.91$381.81, with a struck-through $448.11 and no minus sign). That is a stay charged at a discounted rate, not a deduction: it is reported as nightlyBase / accommodationSubtotal, the struck-through original goes to accommodationOriginalSubtotal / accommodationDiscount, and only a line that really carries a minus is ever subtracted.

  • Availability and price come from Airbnb's public web responses; if Airbnb changes its response format the actor may need an update.

Input

{
"listings": ["https://www.airbnb.com/rooms/14926879", "48819442"],
"startDate": "2026-09-01",
"endDate": "2026-09-30",
"pricingMode": "sampled",
"maxQuotesPerListing": 6,
"quoteNights": 0,
"adults": 2,
"currency": "EUR"
}

Key inputs:

  • listings (required) — Airbnb room URLs or plain listing IDs.
  • startDate + endDate — optional exact ISO window (YYYY-MM-DD). Provide both or neither. When set, calendarMonths is ignored and emitted days[] are filtered to that window. endDate must be after startDate and within the 12-month availability horizon. The window itself is always quoted directly (marked quoteSource: "exact-range-direct"), because Airbnb's availability calendar can report a window as unavailable that the booking endpoint still prices happily. That quote is skipped when the same window was already quoted, counts against maxQuotesPerListing, and — like every quote — is charged only if a price actually came back. With the default quoteNights: 0 this is an explicit stay: it is the only quote you get and the only one you pay for (see Asking for one stay vs. asking for a price curve).
  • calendarMonths (1–12, default 3) — months of availability to fetch when no exact range is given.
  • pricingModesampled (default) or allAvailableDates.
  • maxPricedDatesrequired when pricingMode = allAvailableDates; the per-listing cost budget. It has no default on purpose, so cost is a contract rather than a surprise.
  • onCostLimitExceedederror (default) or truncate.
  • maxQuotesPerListing (default 4) — hard cap on quotes delivered and charged per listing in sampled mode; spread one-per-month first. The exact-range direct quote counts against it too, so the cap is never exceeded by one.
  • quoteNights (default 0) — stay length for sampled quotes; 0 uses each date's own minimum-nights rule. Together with startDate/endDate it also decides whether your request is one explicit stay or a price curve — see the section above.
  • adults (default 2) — guest count for quotes.
  • currency (default USD) — ISO 4217 currency code for all prices. Case and spacing do not matter (usd, " try "), and every record reports the normalized code that was actually used. Anything that is not a real 3-letter currency code — a country code like TR, a symbol like $, a name like US Dollar, or an empty value — stops the run before any request is made and before anything is charged, rather than letting Airbnb price in a currency of its own choosing and labelling the result wrongly. There is no "no currency" mode: omit the field to take the default.
  • marketCountry (default US) — ISO 3166-1 alpha-2 country the requests exit from. Airbnb prices the market you ask from, so the same listing and dates can return a different nightly rate or an extra tax line from a different country. Pinning it fixes the country dimension only — it does not make a price permanently reproducible: prices are still live and change over time, and the city, the exit IP and whatever experiment Airbnb serves are not pinned. US is an arbitrary but fixed default (Airbnb's largest single market); a fixed default beats a random one, but it is not "the real price" — set marketCountry to whichever market you actually want priced. Independent of currencycurrency picks the money, marketCountry picks the market (EUR + US is a valid pair). An invalid code stops the run before anything is spent. If your proxyConfiguration already pins apifyProxyCountry, that explicit pin wins, is logged, and is what gets reported.
  • locale (default en) — language for localized strings (en, de, tr, en-GB). A value that is not a language tag at all stops the run before anything is requested or charged; valid tags are passed through unchanged.
  • proxyConfiguration — Apify Proxy with residential groups is the default.

Output (one item per listing)

{
"listingId": "14926879",
"url": "https://www.airbnb.com/rooms/14926879",
"status": "ok",
"currency": "EUR",
"marketCountry": "US",
"calendarMonths": 3,
"daysTotal": 30,
"daysAvailable": 12,
"availabilityRate": 0.4,
"firstAvailableCheckin": "2026-09-03",
"dateRange": { "startDate": "2026-09-01", "endDate": "2026-09-30" },
"pricingMode": "sampled",
"maxGuests": 4,
"maxGuestsSource": "sidebar",
"cancellationPolicy": { "id": 44, "name": "Firm", "tooltip": "Free cancellation before ..." },
"canInstantBook": true,
"days": [
{ "date": "2026-09-03", "available": true, "availableForCheckin": true, "availableForCheckout": true, "minNights": 2, "maxNights": 365 }
],
"quotesAttempted": 1,
"quotes": [
{
"checkIn": "2026-09-03",
"checkOut": "2026-09-05",
"nights": 2,
"currency": "EUR",
"requestedAdults": 2,
"effectiveAdults": 2,
"adultsReducedToFitCapacity": false,
"maxGuests": 4,
"maxGuestsReliable": true,
"maxGuestsScope": "listing",
"maxGuestsCaveat": null,
"maxGuestsSource": "sidebar",
"capacityModel": "requested",
"priceRaw": "€284",
"priceQualifier": "for 2 nights",
"priceTotal": 284,
"perNight": 141.99,
"priceIsPeriodRate": false,
"pricePeriod": null,
"priceCoversRequestedWindow": true,
"priceSource": "primaryLine",
"quoteSource": "calendar-candidate",
"priceBreakdown": {
"nightlyBase": 129.99,
"accommodationRate": 129.99,
"accommodationRatePeriod": "night",
"nights": 2,
"accommodationSubtotal": 259.98,
"accommodationOriginalSubtotal": null,
"accommodationDiscount": null,
"subtotal": 271.98,
"fees": [{ "label": "Resort fee", "amount": 12.00 }],
"discount": null,
"taxes": 11.99,
"taxesAndFeesCombined": null,
"taxesDeferred": false,
"totalIncludesTaxes": true,
"taxScope": "taxes-itemized",
"totalPrice": 283.97,
"currency": "EUR",
"breakdownAnomaly": null
}
}
],
"scrapedAt": "2026-08-09T00:00:00.000Z"
}

The breakdown always adds up, so you can check it yourself:

subtotal = accommodationSubtotal + sum(fees) - discount # the pre-tax total
totalPrice = subtotal + (taxes + taxesAndFeesCombined, only when totalIncludesTaxes is true)

Field meanings, so none of them can be mistaken for another:

fieldmeaning
nightlyBasethe per-night rate read from Airbnb's "N nights × rate" line (never a rounded total divided by nights). null on a long stay, where Airbnb prints no nightly rate — see Long stays below
accommodationRate / accommodationRatePeriodthe same rate together with the period one unit of it buys: "night", or "month" / "week" on a long stay. nightlyBase is the night-only view of it and stays null for any other period, so a monthly figure can never be read as a nightly one
accommodationSubtotalthe amount of that accommodation line on its own, before fees, discounts and taxes. null when the line is not readable — never a guess. (It equals nightlyBase × nights up to Airbnb's own cent rounding; the printed line amount is what is reported.)
accommodationOriginalSubtotalwhen the host discounts those dates, Airbnb prints the stay line with a struck-through original (e.g. $448.11$381.81). This is that original. null when Airbnb prints none — the actor makes no discount claim it cannot see.
accommodationDiscountaccommodationOriginalSubtotal − accommodationSubtotal, reported for information only. It is not part of the arithmetic below, because the accommodation amount is already the discounted one.
discounta separate, explicitly negative discount line (e.g. Special offer −$40.05). Only a line that really carries a minus is subtracted.
subtotalthe pre-tax total: accommodation + fees − discount
taxes / taxesAndFeesCombinedthe tax figures actually printed, kept apart (see taxScope)
totalPricethe exact total of the price-detail lines; totalIncludesTaxes says whether tax is inside it
priceTotal / priceRawAirbnb's displayed headline price, which Airbnb rounds up to the whole unit
perNight (on the quote, not in priceBreakdown)the average cost of one night of this window, containing exactly what totalPrice contains. It is totalPrice ÷ nights — the exact total, not the rounded headline — and null when there is no exact total to divide (including a long stay whose window is not one period)
priceIsPeriodRate / pricePeriod / priceCoversRequestedWindow (on the quote)whether Airbnb's displayed headline is a rate per month/week rather than the total for your window — see Long stays

The one exception to the arithmetic above is taxScope: "ambiguous": there Airbnb's own lines did not reconcile with the total it printed, and reporting that fact is the point of the value — no number is bent to make the sum work.

Prices are never negative. Money cannot be negative, so a negative value anywhere in the breakdown is a classification error, not a price. Every money field is checked — nightlyBase, accommodationRate, accommodationSubtotal, accommodationOriginalSubtotal, accommodationDiscount, subtotal, discount, taxes, taxesAndFeesCombined, totalPrice and every fees[].amount. Each offending field is reported as null (a fee keeps its label, which is real observed data), the run logs it loudly naming the exact fields, and the quote carries breakdownAnomaly: "negative-total" when a total was affected, "negative-money" when only other fields were. When breakdownAnomaly is set, the arithmetic identities above no longer hold — that is the point of the flag. You may get no number; you will not get a negative one.

breakdownAnomaly is null on a healthy quote. Its other values, most severe last: "long-stay-unreconciled" (a period-priced response whose own lines do not add up), "period-rate-window-mismatch" (the response is priced per period and your window is not one period — see Long stays), "negative-money" and "negative-total".

Long stays (monthly / weekly pricing)

On a long stay Airbnb stops printing "N nights × rate" and prices the accommodation by the period instead, with a single line such as Average monthly price $1,922.48. When it does that, every figure in the response is a per-period figure — the accommodation line, the discount lines and Airbnb's own Price after discount total alike. That matters, because a monthly total is not a 46-night total.

  • accommodationRate carries the printed rate and accommodationRatePeriod says "month" (or "week"). These two are a direct read of what Airbnb printed and are always reported.
  • nightlyBase stays null. Airbnb printed no per-night rate, and the actor does not manufacture one by dividing the monthly rate — the same rule that keeps nightlyBase off the rounded display total.
  • The period line is not a fee. It is the accommodation charge, so fees[] does not carry it and taxScope is free to report no-tax-line when the response really has no tax line.
  • Lines whose label merely mentions the period (Monthly stay discount, Airbnb monthly stay savings) are still discounts and are still subtracted.

When the window is exactly one period (28–31 nights for monthly, 7 for weekly) the period figure is the window figure, and the full breakdown is published as usual — accommodationSubtotal, subtotal, totalPrice and perNight all mean what they always mean.

When the window is not one period — a 46-night stay priced monthly, or a 4-night stay carrying a monthly line — the window-scoped fields are withheld rather than guessed:

withheld (null)accommodationSubtotal, accommodationOriginalSubtotal, accommodationDiscount, subtotal, discount, taxes, taxesAndFeesCombined, totalPrice, every fees[].amount, and perNight
still reportedaccommodationRate + accommodationRatePeriod (the rate Airbnb printed), the fee labels, priceRaw / priceTotal verbatim, and the raw lines in quote.breakdown
flagbreakdownAnomaly: "period-rate-window-mismatch", plus a loud line in the run log

No window total is ever computed from the rate. Airbnb did not publish one for that window, so neither does the actor — not rate × nights ÷ 30, not by any other arithmetic. You get the real monthly rate and the honest statement that it is not your window's total; the multiplication, with all the assumptions it carries, is yours to make or not.

The displayed headline price is labelled too. priceRaw / priceTotal are whatever Airbnb showed — on a long stay that is a rate, e.g. "$1,340" displayed as monthly. priceRaw is never rewritten; three additive fields on the quote say what it means:

fieldmeaning
priceIsPeriodRatetrue when the headline is a rate for a period rather than the total for the requested window
pricePeriod"month" / "week", or null on an ordinary stay
priceCoversRequestedWindowwhether one such period spans the window you asked for

Why length and nothing else decides this: the same listing quoted at 30 nights (correct) and at 46 nights (wrong) returns byte-identical scope wording — qualifier monthly, headline "… monthly, originally …", highlight label "… per month" — and the lines reconcile perfectly in both, because all of them are monthly. No text and no arithmetic check can tell the two apart. What separates them is that 30 nights fit inside one month and 46 do not. The bands are calendar facts, not tuned values: a calendar month is never shorter than 28 or longer than 31 days (and 28 is also the shortest stay Airbnb prices monthly), and a week is exactly 7.

Billing: these quotes are delivered and charged, like any other. Airbnb returned a real, bookable market price — a monthly rate is precisely the answer for a monthly rental — and the record no longer claims it is anything else. Refusing to deliver would return nothing at all for the entire long-stay segment, which is worse than returning a correctly labelled rate. The rule stays what it always was: a quote is charged when, and only when, a usable price was delivered.

marketCountry on the record is the country actually used, not the one asked for: it is read back off the proxy that minted the requests. It is null — never a guessed code — when no exit country could be pinned (custom proxy URLs, no Apify Proxy, or a local run).

quotesAttempted vs quotes. quotesAttempted counts every window the actor asked Airbnb about; quotes[] holds only the ones that came back with a usable price. When the two differ, the missing windows are named in the run log with the reason — and the difference costs you nothing: only the entries in quotes[] are charged.

In allAvailableDates mode, when a listing has more eligible dates than maxPricedDates, the record carries cost-budget meta: either status: "cost-limit-exceeded" with plannedQuoteCount and maxPricedDates (under onCostLimitExceeded: "error"), or pricedDatesTruncated: true with pricedDatesOmitted and eligibleDatesTotal (under "truncate").

Use cases

  • Competitor rate research — real nightly prices per date for a set of listings you choose.
  • Occupancy analysis — availability rate per listing per month for market studies.
  • STR pricing input — a real price curve plus availability as raw data for your own pricing work.
  • Change tracking — put it on an Apify Schedule to re-pull price and availability for the same listings over time.

Pricing — pay only for delivered data

Pay-per-event billing:

  • calendar — charged once per listing, only when calendar days were actually delivered.
  • price-quote — charged only per successfully delivered price quote.

Failed listings, blocked requests, and empty results are never charged. When onCostLimitExceeded: "error" stops a listing, no quote events are charged for it.

What counts as a "successfully delivered price quote". A quote is delivered — and charged — only when it carries a real, readable price: a price value from Airbnb's response that parses to a positive number and whose source is named on the quote (priceSource). Airbnb sometimes answers with a price block that contains no usable amount (the dates were just booked, the stay length is not offered, the number could not be verified against the price-detail lines). Those attempts are not delivered and not charged, on every quote path. They still appear in quotesAttempted, and each one is logged with its window and the reason, so a listing that returns no prices costs you the calendar event and nothing in price-quote events.

You are never charged for quotes you did not ask for:

  • asking for one stay (startDate + endDate, default settings) costs one price-quote event per listing;
  • in sampled mode the total number of charged quotes per listing never exceeds maxQuotesPerListing;
  • in allAvailableDates mode it never exceeds maxPricedDates.

FAQ

Do I need an Airbnb login or API key? No. The actor uses Airbnb's public, unauthenticated web endpoints.

Which proxies? Apify Proxy with residential groups is the default configuration.

I gave a date range and only got one quote — where are the others? That is the intended behavior: a startDate + endDate with the default quoteNights: 0 is read as one explicit stay, so you get (and pay for) exactly that stay. To price many dates, use pricingMode: "allAvailableDates" with maxPricedDates, or drop the range and use calendarMonths, or set a quoteNights different from the length of your range. See Asking for one stay vs. asking for a price curve.

Why does subtotal include the fees? Because subtotal is the pre-tax total (accommodation + fees − discount). If you want the accommodation line on its own, use accommodationSubtotal, which is reported separately on every quote.

Can I pick a specific room type or rate plan? No. The actor quotes whatever room type and rate plan Airbnb serves by default for that listing and window; some listings even print "Price may vary by room type" in their own breakdown. See "Honest limits".

Why is taxes null on some quotes? Because that response had no separate tax line. Check taxScope: no-tax-line means Airbnb printed none, before-taxes-declared means Airbnb's own total is stated before taxes, and taxes-and-fees-combined means the tax was bundled into one Taxes and fees line that we refuse to split — the amount is in taxesAndFeesCombined. The actor never calls the checkout endpoint, so it only ever reports what the listing response contains.

Why did the same listing and dates return a different total than before? Airbnb's own response varies: we have seen the same listing/window come back with an itemized tax line on one run and with no tax line at all on another, which changes the total by exactly that line (e.g. $283.97 vs $305.75). We do not claim to know what drives it. Each quote reports taxScope and totalIncludesTaxes so you can tell which one you received, and a live re-run is always the current answer.

Why does priceTotal differ from priceBreakdown.totalPrice by a few cents? priceTotal is Airbnb's displayed headline price, which Airbnb rounds up to the whole unit. priceBreakdown.totalPrice is the exact sum of the price-detail lines. Both are returned; use the breakdown when you need cents.

The listing page shows a struck-through price — where is it in the output? In accommodationOriginalSubtotal (the pre-discount stay amount Airbnb printed) and accommodationDiscount (the difference). accommodationSubtotal, subtotal and totalPrice are already the discounted amounts, so the original is reported beside them rather than folded into them. If Airbnb prints no original, both fields are null.

maxGuests says 1 but the listing clearly sleeps more — why? That is a hotel / multi-room listing, where Airbnb reports the capacity of the default room. Check maxGuestsScope: "default-room" means exactly this, maxGuestsReliable is false, and maxGuestsCaveat spells it out.

Why are maxGuests / canInstantBook null on some listings? They are read from the booking-quote response, so they are filled only when at least one quote is requested for that listing. See "Honest limits".

Is scraping Airbnb legal? The actor only accesses publicly available data. You are responsible for using the data in compliance with applicable laws and Airbnb's terms.