# Airbnb Listing Details - Amenities, Host & Ratings (`sumitr_mardy/airbnb-listing-details`) Actor

Extract public Airbnb listing details with amenities, photos, host profile information and six numeric category ratings. One consistent schema with star distribution and plain-text descriptions. No prices, guest review texts or host contact data.

- **URL**: https://apify.com/sumitr_mardy/airbnb-listing-details.md
- **Developed by:** [Sumitr Mardy](https://apify.com/sumitr_mardy) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Airbnb Listing Details Scraper

Export public Airbnb listing details: **amenities, photos, host profile fields, six category ratings and the star distribution**. Pass listing ids or room URLs and receive one consistent, never-null row per unique listing.

This independent actor is **not affiliated with or endorsed by Airbnb**.

**No prices are returned.** The public server-rendered room page does not contain the booking-box price. Currency, dates and guest inputs do not change this. Use [Airbnb Search Scraper](https://apify.com/sumitr_mardy/airbnb-search-scraper) for search prices, then pass its listingId values here to enrich those results.

### Quick start

```json
{"listings":["27349246","7743405"],"language":"en","currency":"USD"}
```

Country domains and subdomains work, for example https://www.airbnb.co.uk/rooms/27349246. Inputs are normalized to the canonical Airbnb.com room URL. Query strings in pasted room URLs are ignored.

### Input

| Field | Default | Behavior |
|---|---|---|
| listings | Required | Numeric id strings or public Airbnb room URLs. Up to 5,000, deduplicated by id. Use strings for long ids to avoid JavaScript number rounding. |
| currency | USD | Passed through to the public page; does not add prices. |
| language | en | Sent as accept-language. English is recommended for parsing overview counts. |
| checkIn, checkOut | Empty | Optional YYYY-MM-DD pair, check-out after check-in. Passed through; no price output. |
| adults | Empty | Optional 1–16 adults, passed through; no price output. |

The daily Store example requests only two Lisbon listings. Two listings are fetched concurrently. Writes and charges are serialized to honor the global event spending cap.

### Output

One row per unique listing, including one free row when it fails. All keys are present, never null. Missing strings are "", numbers 0, booleans false and arrays \[]. Missing numeric values do not imply a verified zero.

| Fields | Meaning |
|---|---|
| inputIndex, input, listingId, url | Original position/value, normalized id and canonical room URL. |
| name, propertyType, summaryTitle | Listing title, sharing/property type and public overview title. |
| guests, bedrooms, beds, baths | Public capacity and parsed overview counts; baths can be fractional. |
| latitude, longitude, isExactLocation | Public coordinates and precision flag. Respect approximate locations. |
| city, breadcrumbs | Public localized location and SEO breadcrumb labels joined with >. |
| rating, reviewsCount | Overall numeric rating and listing rating count. |
| ratingCleanliness, ratingAccuracy, ratingCheckin | Numeric category ratings. |
| ratingCommunication, ratingLocation, ratingValue | Remaining numeric category ratings. |
| ratingDistribution | Object with all five keys, "1" through "5". Fractions from 0 to 1, not percentages or review counts. Missing data uses five zeros. |
| isGuestFavorite, isNew | Public quality flags. New listings can lack category ratings/distribution even if they have one overall rating. |
| hostName, hostId, isSuperhost, hostPhoto | Public host profile fields. hostId is decoded from DemandUser, not an unrelated contextual id. |
| hostRatingCount | Host rating count supplied by the page; distinct from listing reviewsCount. |
| description | Plain text with line breaks; HTML tags removed and entities decoded. |
| amenities, amenitiesUnavailable | Available and explicitly unavailable amenity titles. |
| houseRules, safety, highlights | Public labels from those sections. |
| photos | Deduplicated media-tour URLs, falling back to hero media if needed. |
| status, subStatus, error, scrapedAt | Result status, machine-readable reason, error and UTC ISO timestamp. |

### Pricing and statuses

One **listing** event per saved successful detail row. FREE $0.002, BRONZE $0.0015, SILVER $0.0012, GOLD and above $0.001 ($2 / $1.50 / $1.20 / $1 per 1,000 listings). Standard Actor start fee is $0.00005 per GB, minimum one event.

Failed rows have no listing charge; the start fee still applies. No extra dataset-item event. The actor saves each row before charging and respects your event spending cap.

| status / subStatus | Listing charge |
|---|---|
| ok / listing | Yes |
| failed / invalid_input | No |
| failed / not_found | No; HTTP 404 or 410 |
| failed / redirected | No; any 3xx, not followed |
| failed / http_CODE, blocked, parse_error, network_error | No |
| failed / free_work_limit | No; internal unpaid-work guard |
| failed / cost_limit_reached | No; event spending cap reached |

### Honest limits

- **No prices, calendars, guest review texts or host contact data.** Only public listing-page fields.
- No login, cookies, API key extraction or private booking API. Collection uses plain HTTP, not a browser or fingerprint spoofing.
- Field layout and availability depend on Airbnb's public page. Missing fields keep stable sentinels; absent pdpPresentation yields a free parse_error.
- English overview labels are used for bed/bath/guest count parsing. Other languages can return those counts as 0 when labels differ; explicit personCapacity still supplies guests when present.
- A listing can be unavailable, removed or redirected. Redirects are intentionally not followed.
- A 403/429 gets one direct retry after backoff, then at most one Apify datacenter proxy attempt if available. Never residential.
- Requests have hard deadlines. An internal loss guard limits unproductive requests; large lists can stop with free_work_limit.
- Public coordinates may be approximate. The actor does not infer a street address or host contact information.

### Pair it with Search

1. Run [Airbnb Search Scraper](https://apify.com/sumitr_mardy/airbnb-search-scraper) for a city, dates and currency.
2. Keep the successful rows and collect their listingId strings.
3. Send those ids here; join both datasets by listingId to combine search prices with amenities, host fields and category ratings.

Search prices and room details are collected at different times and may change. For recurring work, configure your own Apify tasks/schedule.

### API examples

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/sumitr_mardy~airbnb-listing-details/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"listings":["27349246","7743405"],"language":"en"}'
```

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("sumitr_mardy/airbnb-listing-details").call(
    run_input={"listings": ["27349246", "7743405"]}
)
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(listing["name"], listing["ratingCleanliness"], listing["amenities"])
```

### Use it from AI agents (MCP)

Hosted OAuth clients can connect to [Apify MCP](https://mcp.apify.com/?tools=sumitr_mardy/airbnb-listing-details):

```json
{"mcpServers":{"airbnb-details":{"url":"https://mcp.apify.com/?tools=sumitr_mardy/airbnb-listing-details"}}}
```

Bearer clients can supply their own token through local secret configuration:

```json
{"mcpServers":{"airbnb-details":{"url":"https://mcp.apify.com/?tools=sumitr_mardy/airbnb-listing-details","headers":{"Authorization":"Bearer <YOUR_APIFY_TOKEN>"}}}}
```

For stdio clients with Node.js:

```json
{"mcpServers":{"airbnb-details":{"command":"npx","args":["-y","@apify/actors-mcp-server","--actors","sumitr_mardy/airbnb-listing-details"],"env":{"APIFY_TOKEN":"<YOUR_APIFY_TOKEN>"}}}}
```

Agent tips: start with two ids, inspect status before analysis, distinguish listing and host rating counts, treat distribution as fractions, and use the Search actor for prices.

Support: [Actor issues](https://apify.com/sumitr_mardy/airbnb-listing-details/issues).

# Actor input Schema

## `listings` (type: `array`):

Numeric listing ids or public Airbnb room URLs. Country domains/subdomains accepted; URL query ignored. Max5000, deduplicated by id.

## `currency` (type: `string`):

Passed through. Does not add prices; use Airbnb Search Scraper for prices.

## `language` (type: `string`):

Sent as accept-language. English recommended for guest/bed/bath count labels.

## `checkIn` (type: `string`):

Optional YYYY-MM-DD; provide checkOut too. Does not add prices.

## `checkOut` (type: `string`):

Optional date after checkIn. Does not add prices.

## `adults` (type: `integer`):

Optional adult count passed through. Does not add prices.

## Actor input object example

```json
{
  "listings": [
    "27349246",
    "7743405"
  ],
  "currency": "USD",
  "language": "en"
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "listings": [
        "27349246",
        "7743405"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sumitr_mardy/airbnb-listing-details").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "listings": [
        "27349246",
        "7743405",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("sumitr_mardy/airbnb-listing-details").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "listings": [
    "27349246",
    "7743405"
  ]
}' |
apify call sumitr_mardy/airbnb-listing-details --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sumitr_mardy/airbnb-listing-details"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/NjDFALq9HMsno4cFT/builds/dydKX3ARXbhNE4s4h/openapi.json
