{"description":"Searches Airbnb homes for a destination, dates and number of guests like the site's own search: listing name and type, total price for the stay (and the original price when discounted), rating and reviews, bedrooms and beds, badges such as Guest favorite or Superhost, coordinates and the listing link.","effect":"read","id":"airbnb.com/search-stays","keywords":["airbnb","vacation rental","apartment","holiday home","stay","travel","lodging","ferienwohnung","unterkunft","urlaub"],"output":{"schema":{"properties":{"checkin":{"type":"string"},"checkout":{"type":"string"},"currency":{"type":"string"},"location":{"type":"string"},"stays":{"items":{"properties":{"badges":{"items":{"type":"string"},"type":"array"},"details":{"items":{"type":"string"},"type":"array"},"id":{"type":"string"},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"name":{"type":["string","null"]},"original_price":{"type":["number","null"]},"price":{"description":"Price as shown, see price_basis (usually the total for the stay incl. taxes)","type":["number","null"]},"price_basis":{"description":"'total' or 'night'","type":["string","null"]},"rating":{"type":["number","null"]},"reviews":{"type":["integer","null"]},"type":{"description":"e.g. 'Apartment in Santa Maria Maior'","type":["string","null"]},"url":{"format":"uri","type":"string"}},"type":"object"},"type":"array"}},"required":["location","stays"],"type":"object"},"value":"{location: params.location, checkin: params.checkin, checkout: params.checkout, currency: params.currency, stays: steps.search[0].stays}"},"params":{"additionalProperties":false,"properties":{"adults":{"default":2,"maximum":16,"minimum":1,"type":"integer"},"checkin":{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"},"checkout":{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"},"currency":{"default":"EUR","enum":["EUR","USD","GBP","CHF"],"type":"string"},"location":{"description":"City or area, e.g. 'Lisbon', 'Paris, France', 'Brooklyn, NY'","maxLength":80,"minLength":2,"type":"string"},"price_max":{"description":"Maximum price per night in the chosen currency","minimum":1,"type":"integer"}},"required":["location","checkin","checkout"],"type":"object"},"provenance":{"method":"browser-inspect","notes":"spikes/airbnb.md. script#data-deferred-state-0 holds niobeClientData[0] = StaysSearch. Listing ids in it are base64 GraphQL ids ('DemandStayListing:<id>'), so the numeric id comes from mapResults.staysInViewport[].listingId, which pairs 1:1 by position with mapResults.mapSearchResults (verified on all 20). Price primaryLine: discountedPrice/originalPrice when discounted, else price; qualifier 'total'. v2 (2026-11-07): Airbnb serves three price-line shapes (A/B): QualifiedDisplayPriceLine (price), DiscountedDisplayPriceLine (discountedPrice/originalPrice) and OrderedDisplayPriceLine (orderedComponents[] with discountedPrice/originalPrice/qualifier parts, no top-level price). v1 read only the first two, so a session that gets the ordered variant (17 of 20 in Victor's browser, Paris) had price null. locale=en pins number formatting. v1 pinned in search-stays.v1.json.","recorded_at":"2026-11-07T12:56:00+01:00","recorded_by":"C4"},"requires_login":false,"schema":"https://wield.run/schema/recipe/v1.json","site":{"country":"US","id":"airbnb.com","language":"en","login_url":"https://www.airbnb.com/login","name":"Airbnb","origin":"https://www.airbnb.com","origins":["https://www.airbnb.com"]},"steps":[{"description":"Server-rendered search page; the result data sits in script#data-deferred-state-0 (pure JSON). The one-item foreach turns 'Paris, France' into Airbnb's 'Paris--France' path slug.","expect":{"content_type":"html","status":[200]},"extract":{"embedded_json":{"selector":"script#data-deferred-state-0","vars":{"stays":"let $ss = niobeClientData[0][1].data.presentation.staysSearch in map(&(let $p = @ in {id: $p[1].listingId, name: $p[0].nameLocalized.localizedStringWithTranslationPreference || $p[0].subtitle || `null`, type: $p[0].title || `null`, rating: ($p[0].avgRatingLocalized && to_number(split($p[0].avgRatingLocalized, ' ')[0])) || `null`, reviews: (contains($p[0].avgRatingLocalized || '', '(') && to_number(replace(replace(split($p[0].avgRatingLocalized, ' (')[1], ')', ''), ',', ''))) || `null`, price: ($p[0].structuredDisplayPrice.primaryLine.discountedPrice || $p[0].structuredDisplayPrice.primaryLine.price || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?discountedPrice].discountedPrice | [0]) || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?price].price | [0])) && to_number(trim(replace(replace(replace(replace(replace(replace(replace(replace(($p[0].structuredDisplayPrice.primaryLine.discountedPrice || $p[0].structuredDisplayPrice.primaryLine.price || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?discountedPrice].discountedPrice | [0]) || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?price].price | [0])), ' ', ''), ' ', ''), 'EUR', ''), 'US$', ''), '$', ''), '€', ''), '£', ''), ',', ''))) || `null`, original_price: ($p[0].structuredDisplayPrice.primaryLine.originalPrice || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?originalPrice].originalPrice | [0])) && to_number(trim(replace(replace(replace(replace(replace(replace(replace(replace(($p[0].structuredDisplayPrice.primaryLine.originalPrice || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?originalPrice].originalPrice | [0])), ' ', ''), ' ', ''), 'EUR', ''), 'US$', ''), '$', ''), '€', ''), '£', ''), ',', ''))) || `null`, price_basis: $p[0].structuredDisplayPrice.primaryLine.qualifier || ($p[0].structuredDisplayPrice.primaryLine.orderedComponents[?qualifier].qualifier | [0]) || `null`, details: $p[0].structuredContent.primaryLine[].body || `[]`, badges: $p[0].badges[].text || `[]`, latitude: $p[0].demandStayListing.location.coordinate.latitude || `null`, longitude: $p[0].demandStayListing.location.coordinate.longitude || `null`, url: join('', ['https://www.airbnb.com/rooms/', $p[1].listingId])}), zip($ss.mapResults.mapSearchResults || `[]`, $ss.mapResults.staysInViewport || `[]`))"}}},"foreach":{"as":"loc","in":"[{slug: replace(replace(trim(params.location), ', ', '--'), ' ', '-')}]","max":1},"id":"search","parse":"html","request":{"headers":{"Accept":"text/html"},"method":"GET","query":{"adults":"{{params.adults}}","checkin":"{{params.checkin}}","checkout":"{{params.checkout}}","currency":"{{params.currency}}","locale":"en","price_max":"{{params.price_max}}"},"url":"/s/{{loc.slug | urlencode}}/homes"}}],"task":"Search Airbnb stays for a place and dates","tos":{"notes":"Airbnb's terms prohibit scraping. One user-initiated search at a time from the user's own browser (1 request). Booking stays on airbnb.com.","reviewed":false},"verify":{"checks":["length(output.stays) > `5`","output.stays[0].price > `0`","starts_with(output.stays[0].url, 'https://www.airbnb.com/rooms/')","length(output.stays[?rating != `null`]) > `0`","length(output.stays[?price == `null`]) <= `2`"],"example_params":{"adults":2,"checkin":"2026-12-04","checkout":"2026-12-07","location":"Lisbon"},"max_ms":6000},"version":2}