# Airbnb Listing Monitor - Ratings & Public Profile Changes (`maydit/airbnb-listing-reputation-monitor`) Actor

Track public Airbnb listing titles, descriptions, photos, capacity and review totals. Monitor known rooms or a bounded curated city page with saved changes, source links and clear coverage.

- **URL**: https://apify.com/maydit/airbnb-listing-reputation-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Categories:** Travel
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 saved observations

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 Monitor

**See when a rental's public profile or review totals change.** Paste Airbnb room URLs and receive structured listing observations with source links, timestamps and optional saved comparisons. A curated city directory can supply a small discovery set when you do not yet have a watchlist.

Built for rental managers, hosts and travel research teams following known comparable properties. The output keeps listing identity and source facts together, so your spreadsheet or AI workflow can explain what changed and where it was observed.

### Start with one room

```json
{"roomUrls":["https://www.airbnb.com/rooms/905399"],"maxResults":1}
```

Click **Start**, then open the **Dataset** for the listing row. **Coverage and diagnostics** explains what was reached. **Readable run report** gives a compact result and any incomplete-source details. No Airbnb account, API key or proxy is needed. Empty input uses this independently operated public example; it can change over time.

### What you receive

| Question | Source-backed fields |
| --- | --- |
| Has the listing's positioning changed? | `title`, plain-text `description`, `photoUrls`, `photoCount` |
| Has public feedback increased? | `ratingAverage`, `ratingCount`, literal count and average deltas |
| What place does the page describe? | `locality`, optional region/country, public approximate coordinates and structured-data `occupancy` |
| What changed since our last complete observation? | `comparisonStatus`, `changedFields`, `previous`, `previousObservedAt` |
| Can we trace the result? | Stable `listingId`/`recordId`, canonical `sourceUrl`, `observedAt` and `coverage` |

Each row represents one room page. Missing source fields remain `null`. `amenities` is returned only if the room's structured data actually supplies it. A city card's amenity summary is not substituted for missing detail-page data.

### Three ready-to-run recipes

#### 1. A room's public reputation snapshot

```json
{"roomUrls":["https://www.airbnb.com/rooms/905399"],"maxResults":1}
```

#### 2. Two comparable public listings

```json
{
  "roomUrls": [
    "https://www.airbnb.com/rooms/50271268",
    "https://www.airbnb.com/rooms/16779078"
  ],
  "maxResults": 2
}
```

#### 3. A curated city discovery set

```json
{
  "roomUrls": [],
  "cityUrls": ["https://www.airbnb.com/san-francisco-ca/stays"],
  "maxDiscoveredListings": 20,
  "maxResults": 20
}
```

The city recipe reads the public structured directory and then each selected room page. Twelve curated rentals were present when tested. This is **not** every listing in the city, arbitrary search pagination or a measure of market inventory. The source can change its curated selection. The report records how many listings the directory supplied and how many were selected.

### Turn snapshots into a watchlist

```json
{
  "roomUrls": [
    "https://www.airbnb.com/rooms/905399",
    "https://www.airbnb.com/rooms/50271268"
  ],
  "maxResults": 5,
  "comparePrevious": true,
  "onlyChanges": true,
  "snapshotName": "rental-comparables"
}
```

The first complete run emits `new` observations and establishes history. Later runs emit changed listings; an unchanged run can correctly save zero rows. Changes-only mode incurs no result event for skipped unchanged listings. Prefer a fixed room watchlist for a stable comparison group.

History belongs to the normalized room and city selections, discovery cap and snapshot name. Changing that selection creates a separate scope. Use one active writer for each scope. A city directory can introduce new rooms; a room disappearing from its curated list does not establish that the room was delisted or booked.

If a source fails, selected rooms remain unread, discovery is truncated, time expires or the spending limit is reached, the run does **not** advance its comparison history. Useful rows may still be returned with a partial report. Read `SUMMARY.status` and `SUMMARY.incomplete` before treating a run as a complete check.

### Input reference

| Field | Default | Purpose |
| --- | --- | --- |
| `roomUrls` | Sample room when both URL lists are empty | Up to 20 explicit public `/rooms/ID` URLs |
| `cityUrls` | Empty | Up to 2 exact public `/city-name/stays` directories |
| `maxDiscoveredListings` | 20 | Total unique discovered rooms, 1–40; truncated selection is partial |
| `maxResults` | 20 | Maximum saved listing rows, 1–60 |
| `comparePrevious` | false | Compare against the last complete saved observations |
| `onlyChanges` | false | Enable comparison and skip unchanged rows |
| `snapshotName` |`default` | 1–80 letters, numbers, underscores or hyphens |
| `maxRunSeconds` | 90 | Shared collection budget, 30–120 seconds |

Use `https://www.airbnb.com` URLs. Bare `airbnb.com` and trailing slashes are normalized. Supported tracking parameters are removed. Booking dates, guest counts, fragments and other functional parameters are rejected so the observation always represents the public listing profile.

Unknown input fields fail before any source request, so a misspelled URL field never silently starts the sample. If Airbnb returns HTTP 401, 403 or 429, the Actor stops further source requests for that run and reports the unread targets; it does not retry the denial or switch access methods.

### Interpreting the data

`ratingCount` and its delta are platform-reported aggregate counts, not bookings. The Actor does not collect individual guest reviews, guest names or contact details. A negative count delta can reflect source corrections; it is preserved rather than hidden.

`occupancy` comes from the page's structured accommodation data. It may differ from a number written in a marketing title and is not a booking guarantee. Public coordinates are approximate and are not represented as an exact address. The photo list is the source's structured selection, which may be smaller than its interactive gallery.

No date-specific nightly price, booking availability, occupancy rate, revenue estimate or profitability score is produced. Such fields require different source evidence. This Actor does not infer them from review growth or missing listings.

### Exports and automation

Download JSON or CSV from the Dataset. JSON preserves nested photos, amenities and previous observations. The free `SUMMARY` record reports source coverage, rows saved, limits, failures and history updates. `RUN_REPORT` is an HTML view of the same evidence. Neither creates a listing result charge.

Save your input as an Apify task to use your own schedule or integration. Send changed rows to a spreadsheet, database or property research workflow. An AI agent can use the same input through the [Apify API](https://docs.apify.com/api/v2) or [Apify MCP server](https://docs.apify.com/platform/integrations/mcp). Include the source URL and observation time in any generated report.

Pricing is **$0.00005 per Actor start plus $0.003 per saved listing observation ($3 per 1,000)**. The live Pricing tab is authoritative. Skipped unchanged rows create no result event; platform usage may still apply under your plan. Set a maximum charge in Run options to bound a run.

### Source coverage and support

The Actor reads public page structured data, respects robots directives and uses bounded requests. It does not sign in, bypass challenges, access reservation records or retrieve private host/guest information. Unsupported source shapes and unavailable pages are reported rather than converted into invented observations. Public source behavior can change, so successful retained runs are dated evidence, not a guarantee of future availability.

If a page changes, open an Actor issue with the public URL, run ID and expected field. Do not include account credentials. Find related [event monitoring](https://apify.com/maydit/meetup-group-event-monitor), [product price monitoring](https://apify.com/maydit/gumroad-product-price-monitor) and more workflow ideas at [Mayd It Data Tools](https://mayd-it.com/data-tools/).

# Actor input Schema

## `roomUrls` (type: `array`):

Up to 20 exact https://www.airbnb.com/rooms/ID URLs. Tracking parameters are removed; booking date, guest-count and price queries are not supported. Empty room and city lists use the sample room.

## `cityUrls` (type: `array`):

Up to 2 exact https://www.airbnb.com/city-name/stays URLs. Discover the public structured list (12 listings observed), then read each room. This is not full search or all local inventory.

## `maxDiscoveredListings` (type: `integer`):

Total unique rooms selected from city pages. Lower than the visible directory count yields partial coverage and prevents history advancement.

## `maxResults` (type: `integer`):

Maximum charged rows saved. When requested rooms remain, SUMMARY reports partial coverage and comparison history stays unchanged.

## `comparePrevious` (type: `boolean`):

Compare with the last complete successful observation under the same input selection and snapshot name. First comparison establishes a baseline.

## `onlyChanges` (type: `boolean`):

Enables comparison. Unchanged observations are skipped and incur no result event; an unchanged run may correctly produce zero rows.

## `snapshotName` (type: `string`):

Use 1-80 letters, numbers, underscores or hyphens. One active writer per watchlist and snapshot; new names create independent history.

## `maxRunSeconds` (type: `integer`):

Shared deadline for all source reads and output. Failed, partial or spending-limited runs do not advance comparison history.

## Actor input object example

```json
{
  "roomUrls": [
    "https://www.airbnb.com/rooms/905399"
  ],
  "cityUrls": [],
  "maxDiscoveredListings": 20,
  "maxResults": 20,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxRunSeconds": 90
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

## `report` (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 = {
    "roomUrls": [
        "https://www.airbnb.com/rooms/905399"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/airbnb-listing-reputation-monitor").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 = { "roomUrls": ["https://www.airbnb.com/rooms/905399"] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/airbnb-listing-reputation-monitor").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 '{
  "roomUrls": [
    "https://www.airbnb.com/rooms/905399"
  ]
}' |
apify call maydit/airbnb-listing-reputation-monitor --silent --output-dataset

```

## MCP server setup

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

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/rLYHbML05MOgCSaaU/builds/5OLTZ92aoo26lOFPh/openapi.json
