# Airbnb Reviews Scraper — Most Comprehensive (`scrapersdelight/airbnb-reviews-scraper`) Actor

From $0.30 per 1,000 reviews — 16x cheaper than the $5/1k incumbent. Star rating, full text, translations, host responses, dates, review tags. Keyword + date filters with early stop, GDPR-safe PII strip, and a new-review monitor with Slack/email/webhook alerts. No login or API key.

- **URL**: https://apify.com/scrapersdelight/airbnb-reviews-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** AI, E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## 🏠 Airbnb Reviews Scraper — Most Comprehensive (+ New-Review Monitor)

**Scrape every review from any Airbnb listing — per-review star rating, full text, automatic translations, host responses, dates, reviewer context, photos, and the listing's review tags — for $0.30 per 1,000 reviews. Then schedule it as a monitor that pings Slack, email, or a webhook the moment a new review lands.**

### Why this one? (honest comparison)

| | **This actor** | Leading Airbnb reviews scraper | Budget clone |
|---|---|---|---|
| **Price per 1,000 reviews** | **$0.30** | $5.00 | low-cost, but see below |
| Per-review star rating | ✅ | ✅ | ✅ |
| Host responses (+ responded date) | ✅ | ✅ | — not documented |
| Translated text (Airbnb's own translation) | ✅ | ✅ | — not documented |
| Review tags ("Hot tub", "Cleanliness" + counts) | ✅ | — | — |
| Keyword filter | ✅ | — | — |
| Date-range filter with **early stop** (don't pay for pages you skip) | ✅ | — | — |
| Min/max rating filter (complaints mining) | ✅ | — | — |
| New-review **monitor mode** + Slack/email/webhook alerts | ✅ | — | — |
| GDPR `stripPersonalData` toggle (default ON) | ✅ | — | — |
| Raw API object passthrough (`includeRaw`) | ✅ | — | — |
| Failure handling | per-page retries with fresh proxy sessions; one dead listing never kills the run | n/a | n/a |

*Competitor columns are based on their public store pages as of June 2026 — check them yourself. A cheap clone already exists and sits at single-digit monthly users: price alone doesn't win this niche. Features are what keep a reviews pipeline alive — filters, translations, host responses, monitoring, and not crashing on a dead listing. That's the gap this actor fills, at 1/16th of the leader's price.*

---

### What does Airbnb Reviews Scraper do?

Give it one or more **Airbnb listing URLs** (any country domain) or bare listing IDs and it returns **one clean row per review**, exportable to **JSON, CSV, Excel, or your app via API**. No login, no Airbnb API key, no browser automation — it reads the same public reviews endpoint the Airbnb page itself uses, so it's fast (~50 reviews per request) and cheap.

- ⭐ **Per-review star rating** (1–5) — not just the listing average.
- 📝 **Full review text** — plain text *and* original HTML, plus **Airbnb's own translation** when the review isn't in English (`text_translated`, `needs_translation`, disclaimer).
- 💬 **Host responses** — full text + the responded date, plain and HTML.
- 📅 **Exact ISO timestamps** (`created_at`) plus Airbnb's humanized date.
- 🧳 **Stay & reviewer context** — reviewer location / tenure on Airbnb, stay context, superhost flags.
- 🏷️ **Listing review tags** — Airbnb's aggregated themes ("Hot tub" ×157, "Cleanliness" ×62…) with counts, on every row.
- 📸 **Review photos** where guests attached them.
- 🔎 **Filters that save you money** — keyword, min/max rating, and a date-range filter that **stops paginating early** (reviews come newest-first, so `dateFrom` means fewer requests, not just fewer rows).
- 🔔 **Monitor mode** — schedule it and get **Slack / email / webhook alerts** for every new review on the listings you manage or compete with.
- 🛡️ **GDPR-safe by default** — `stripPersonalData` (ON) removes reviewer name, ID, profile URL, and avatar while keeping all the review substance.

---

### Who is it for?

- 🏘️ **Property managers & hosts** watching their own (and competitors') listings for new reviews and complaints.
- 📊 **Market researchers / data teams** mining guest sentiment at scale (the per-review rating + ISO dates make time-series trivial).
- 🤖 **AI builders** feeding review corpora into LLM sentiment, summarization, or RAG pipelines (`includeRaw` future-proofs your schema).
- 💼 **Revenue managers & investors** doing due diligence on a listing or a whole micro-market before buying/pricing.
- 🛎️ **Reputation tools** that need host-response coverage rates and response-time stats.

---

### How to use it

1. Click **Try for free**.
2. Paste one or more **listing URLs** (e.g. `https://www.airbnb.com/rooms/20669368`) — any country domain works, or just the numeric ID.
3. (Optional) set filters: `dateFrom`, `keyword`, `minRating`/`maxRating`, `maxReviews`.
4. Click **Start**, open the **Dataset** tab, export.
5. (Optional) turn on **monitorMode**, attach an Apify **Schedule**, add a Slack/webhook/email channel — and get pinged on every new review.

#### Quick start

```json
{ "listingUrls": ["https://www.airbnb.com/rooms/20669368"], "maxReviews": 50 }
````

#### Complaints mining (what goes wrong at this property?)

```json
{
  "listingUrls": ["https://www.airbnb.com/rooms/20669368"],
  "maxRating": 3,
  "maxReviews": 0
}
```

#### New-review monitor (the recurring play)

```json
{
  "listingUrls": ["https://www.airbnb.com/rooms/20669368", "https://www.airbnb.com/rooms/1206441548197247311"],
  "monitorMode": true,
  "alertOnNewReview": true,
  "slackWebhookUrl": "https://hooks.slack.com/services/…"
}
```

#### Only reviews since January (early-stop = fewer requests)

```json
{
  "listingUrls": ["https://www.airbnb.com/rooms/20669368"],
  "dateFrom": "2026-01-01",
  "maxReviews": 0
}
```

***

### Input

| Field | What it does |
|-------|--------------|
| `listingUrls` | Airbnb listing URLs (any country domain) or numeric IDs — one row per review |
| `maxReviews` | cap per listing (default 50; `0` = every review) |
| `sortBy` | `newest` · `oldest` · `rating-high` · `rating-low` (output order) |
| `dateFrom` | only reviews on/after this date — **stops paginating early** |
| `dateTo` | only reviews on/before this date |
| `keyword` | only reviews mentioning this word/phrase (text, translation, or host response) |
| `minRating` / `maxRating` | per-review star-rating band (e.g. `maxRating: 3` = complaints) |
| `stripPersonalData` | **ON by default** — removes reviewer name/ID/profile/avatar |
| `includeRaw` | attach the original API object as `raw` on every row |
| `monitorMode`, `alertOnNewReview` | recurring watcher: output/alert only reviews new since last run |
| `webhookUrl`, `slackWebhookUrl`, `emailRecipients` | alert channels |
| `proxyConfiguration`, `requestConcurrency` | proxy + parallel listings |

***

### Output

One dataset record per review. Example (truncated):

```json
{
  "listing_id": "20669368",
  "listing_url": "https://www.airbnb.com/rooms/20669368",
  "listing_title": "Luxury cabin + hot tub, Stratford-upon-Avon",
  "listing_reviews_count": 307,
  "listing_review_tags": [{ "tag": "HOT_TUB", "label": "Hot tub", "count": 157 }],
  "review_id": "1701461540622642748",
  "rating": 5,
  "text": "Our stay here was Superb.\nThe Cabin was Lovely, very clean and stylish…",
  "language": "en",
  "needs_translation": false,
  "text_translated": null,
  "created_at": "2026-06-05T13:40:21Z",
  "localized_date": "1 week ago",
  "reviewer_location": "2 months on Airbnb",
  "reviewer_is_superhost": false,
  "host_name": "Tanya",
  "host_response": null,
  "host_responded_date": null,
  "review_photos": [],
  "scraped_at": "2026-06-12T18:00:00.000Z"
}
```

Plus on every row: `rating_label`, `text_html`, `text_translated_html`, `translation_disclaimer`, `stay_context`, `host_response`/`_html`/`_translated`, `host_responder_name`, `host_is_superhost`, `highlighted_sentences`, `is_host_highlighted`, `collection_tag`, `channel`, `room_type_listing_id`/`_title`, `is_new` (monitor mode), and optionally `raw`.

***

### How much does it cost?

Pay-per-event — you pay for what you pull, no subscription:

| Event | What it covers | Price |
|-------|----------------|-------|
| `lot-scraped` | each review returned | **$0.0003 / review** |
| `monitor-run-completed` | each scheduled watch run | $0.02 / run |
| `new-lot-detected` | each newly posted review found | $0.005 / review |
| `alert-delivered` | each Slack/email/webhook push | $0.005 / alert |

That's **$0.30 per 1,000 reviews** — the leading Airbnb reviews actor charges **$5.00 per 1,000** for the scrape alone. A daily monitor on 10 listings costs well under a dollar a month plus the new reviews it actually finds.

***

### Is it legal to scrape Airbnb reviews? (read this)

Airbnb reviews are **publicly visible without a login**, and this actor only reads what any visitor's browser loads. That said:

- **Airbnb's Terms of Service prohibit automated access** — scraping public pages is generally lawful in many jurisdictions (e.g. the *hiQ v. LinkedIn* line of cases in the US), but it sits in a ToS-gray zone. You are responsible for your own legal review before commercial use.
- **Reviews contain personal data** (names, avatars, locations). `stripPersonalData` is **ON by default** and removes reviewer name, user ID, profile URL, and avatar so your dataset holds review substance, not identities. If you switch it off, **you** become responsible for a lawful basis under **GDPR/CCPA** (consent, legitimate interest assessment, deletion handling).
- Use the data for analysis/monitoring; don't republish reviewer identities.

***

### FAQ

**Do I need an Airbnb account, login, or API key?**
No. The actor reads the public reviews endpoint that the listing page itself uses — no account, cookies, or official API access.

**Which listing URLs work?**
Any country domain (`airbnb.com`, `.ca`, `.co.uk`, `.fr`, …), `/rooms/{id}`, `/rooms/plus/{id}`, `/luxury/listing/{id}`, or just the numeric ID.

**Does it get ALL reviews, not just the first page?**
Yes — it paginates 50 at a time until it has every review (or hits your `maxReviews` / `dateFrom` limit). Verified against listings with 300+ reviews.

**Do I get the star rating of each individual review?**
Yes — `rating` (1–5) per review, not just the listing average.

**Are non-English reviews translated?**
When Airbnb itself serves a translation, you get it in `text_translated` (with the original in `text` and `language`). The actor doesn't run its own MT.

**Do I get host replies?**
Yes — `host_response` (plain + HTML + translated when present) and `host_responded_date`.

**Can I get only negative reviews?**
Yes — `maxRating: 3` returns only 1–3-star reviews. Combine with `keyword` (e.g. "dirty", "wifi") for complaint mining.

**How does the monitor know what's new?**
It keeps a per-listing seen-set in a named key-value store that persists across runs. Each scheduled run outputs and alerts only reviews it hasn't seen before.

**What happens if a listing is deleted or a page fails?**
The actor detects dead listings and skips them with a warning; every request retries with fresh proxy sessions. One bad listing never crashes the run — you keep everything else.

**What does it cost to scrape 10,000 reviews?**
$3.00 (10,000 × $0.0003), plus Apify platform usage. The $5/1k incumbent would charge $50 for the same pull.

**Is the reviewer's name included?**
Only if you turn `stripPersonalData` OFF — by default reviewer name, ID, profile URL, and avatar are removed (GDPR-friendly).

**Airbnb changed something and it broke?**
The actor self-heals the most common breakage (Airbnb rotating its internal query hash) by re-extracting it from Airbnb's own JS bundle at runtime. If something else changes, open an issue — fast fixes.

**How fast is it?**
\~50 reviews per request, sub-second responses: 1,000 reviews in well under a minute.

**Can I pipe results to Make / Zapier / n8n / my backend?**
Yes — webhook alerts for new reviews, or pull the dataset via the Apify API.

***

### You might also like

- 🏨 Booking.com / TripAdvisor reviews scrapers
- 🏠 Airbnb listing & pricing scrapers
- 🔔 Review monitors for other marketplaces

***

### Feedback

Found a missing field or want a new filter? Open an issue on the actor — fast fixes and feature requests welcome.

# Actor input Schema

## `listingUrls` (type: `array`):

Airbnb listing page URLs (any country domain, e.g. https://www.airbnb.com/rooms/20669368) or bare numeric listing IDs. One dataset row per review, for every listing.

## `maxReviews` (type: `integer`):

Hard cap on reviews scraped per listing (cost/safety guard). Defaults to 50 for a fast first run — set to 0 to pull EVERY review the listing has.

## `sortBy` (type: `string`):

Order of the output dataset. Reviews are always fetched newest-first from Airbnb (which is what makes the 'Reviews from date' early-stop possible); this re-orders the final dataset.

## `dateFrom` (type: `string`):

Only reviews written on/after this date, format YYYY-MM-DD. Because Airbnb serves reviews newest-first, the scraper STOPS paginating the moment it hits an older review — you don't pay for pages you don't need.

## `dateTo` (type: `string`):

Only reviews written on/before this date, format YYYY-MM-DD (client-side filter).

## `keyword` (type: `string`):

Only output reviews whose text, translation, or host response contains this word/phrase (case-insensitive). E.g. 'wifi', 'dirty', 'check-in'.

## `minRating` (type: `integer`):

Only reviews with this per-review star rating or higher (1–5). 0 = no floor.

## `maxRating` (type: `integer`):

Only reviews with this per-review star rating or lower (1–5) — e.g. 3 to study complaints. 0 = no cap.

## `stripPersonalData` (type: `boolean`):

ON (default): reviewer name, user id, profile URL, and avatar are removed from the output — you keep the full review text, rating, dates, and host response. Turn OFF only if you have a lawful basis to process the reviewer's personal data (GDPR/CCPA — your responsibility).

## `includeRaw` (type: `boolean`):

Attach the original Airbnb API review object (minus UI noise) as a `raw` sub-object on every record — future-proofs you against any field we didn't flatten.

## `monitorMode` (type: `boolean`):

Recurring watcher: diff against the prior run's seen reviews (per listing) and output/alert ONLY reviews posted since the last run. Pair with an Apify Schedule.

## `alertOnNewReview` (type: `boolean`):

In monitor mode, deliver an alert for each new review via the channels below.

## `webhookUrl` (type: `string`):

POST endpoint for new-review alert payloads (Make / Zapier / n8n / custom). One JSON body per alert.

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL for formatted new-review cards (stars + excerpt + listing link).

## `emailRecipients` (type: `array`):

Email addresses for the new-review digest (sent via apify/send-mail).

## `proxyConfiguration` (type: `object`):

Proxy settings. Datacenter rotation worked in testing; switch to residential if you scrape thousands of listings per day.

## `requestConcurrency` (type: `integer`):

How many listings to scrape in parallel. Keep modest (4–8) to stay polite.

## `diagnose` (type: `boolean`):

Dev only. Dumps the raw reviews API JSON to the key-value store (DEBUG\_REVIEWS\_JSON) and logs the parsed first record, then exits. Leave off for normal runs.

## Actor input object example

```json
{
  "listingUrls": [
    "https://www.airbnb.com/rooms/20669368",
    "https://www.airbnb.com/rooms/1206441548197247311"
  ],
  "maxReviews": 50,
  "sortBy": "newest",
  "minRating": 0,
  "maxRating": 0,
  "stripPersonalData": true,
  "includeRaw": false,
  "monitorMode": false,
  "alertOnNewReview": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "requestConcurrency": 4,
  "diagnose": false
}
```

# Actor output Schema

## `items` (type: `string`):

The dataset of scraped Airbnb reviews (one review per row).

# 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 = {
    "listingUrls": [
        "https://www.airbnb.com/rooms/20669368",
        "https://www.airbnb.com/rooms/1206441548197247311"
    ],
    "maxReviews": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/airbnb-reviews-scraper").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 = {
    "listingUrls": [
        "https://www.airbnb.com/rooms/20669368",
        "https://www.airbnb.com/rooms/1206441548197247311",
    ],
    "maxReviews": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/airbnb-reviews-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "listingUrls": [
    "https://www.airbnb.com/rooms/20669368",
    "https://www.airbnb.com/rooms/1206441548197247311"
  ],
  "maxReviews": 50
}' |
apify call scrapersdelight/airbnb-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scrapersdelight/airbnb-reviews-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Airbnb Reviews Scraper — Most Comprehensive",
        "description": "From $0.30 per 1,000 reviews — 16x cheaper than the $5/1k incumbent. Star rating, full text, translations, host responses, dates, review tags. Keyword + date filters with early stop, GDPR-safe PII strip, and a new-review monitor with Slack/email/webhook alerts. No login or API key.",
        "version": "0.1",
        "x-build-id": "LTyvUxJsA4rNMWHK2"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/scrapersdelight~airbnb-reviews-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-scrapersdelight-airbnb-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/scrapersdelight~airbnb-reviews-scraper/runs": {
            "post": {
                "operationId": "runs-sync-scrapersdelight-airbnb-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/scrapersdelight~airbnb-reviews-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-scrapersdelight-airbnb-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "listingUrls"
                ],
                "properties": {
                    "listingUrls": {
                        "title": "Listing URLs or IDs",
                        "type": "array",
                        "description": "Airbnb listing page URLs (any country domain, e.g. https://www.airbnb.com/rooms/20669368) or bare numeric listing IDs. One dataset row per review, for every listing.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxReviews": {
                        "title": "Max reviews per listing",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Hard cap on reviews scraped per listing (cost/safety guard). Defaults to 50 for a fast first run — set to 0 to pull EVERY review the listing has.",
                        "default": 50
                    },
                    "sortBy": {
                        "title": "Sort results by",
                        "enum": [
                            "newest",
                            "oldest",
                            "rating-high",
                            "rating-low"
                        ],
                        "type": "string",
                        "description": "Order of the output dataset. Reviews are always fetched newest-first from Airbnb (which is what makes the 'Reviews from date' early-stop possible); this re-orders the final dataset.",
                        "default": "newest"
                    },
                    "dateFrom": {
                        "title": "Reviews from date (early stop)",
                        "type": "string",
                        "description": "Only reviews written on/after this date, format YYYY-MM-DD. Because Airbnb serves reviews newest-first, the scraper STOPS paginating the moment it hits an older review — you don't pay for pages you don't need."
                    },
                    "dateTo": {
                        "title": "Reviews up to date",
                        "type": "string",
                        "description": "Only reviews written on/before this date, format YYYY-MM-DD (client-side filter)."
                    },
                    "keyword": {
                        "title": "Keyword filter",
                        "type": "string",
                        "description": "Only output reviews whose text, translation, or host response contains this word/phrase (case-insensitive). E.g. 'wifi', 'dirty', 'check-in'."
                    },
                    "minRating": {
                        "title": "Min star rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Only reviews with this per-review star rating or higher (1–5). 0 = no floor.",
                        "default": 0
                    },
                    "maxRating": {
                        "title": "Max star rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Only reviews with this per-review star rating or lower (1–5) — e.g. 3 to study complaints. 0 = no cap.",
                        "default": 0
                    },
                    "stripPersonalData": {
                        "title": "Strip personal data (GDPR-safe)",
                        "type": "boolean",
                        "description": "ON (default): reviewer name, user id, profile URL, and avatar are removed from the output — you keep the full review text, rating, dates, and host response. Turn OFF only if you have a lawful basis to process the reviewer's personal data (GDPR/CCPA — your responsibility).",
                        "default": true
                    },
                    "includeRaw": {
                        "title": "Include raw API object",
                        "type": "boolean",
                        "description": "Attach the original Airbnb API review object (minus UI noise) as a `raw` sub-object on every record — future-proofs you against any field we didn't flatten.",
                        "default": false
                    },
                    "monitorMode": {
                        "title": "Monitor mode (new-review watcher)",
                        "type": "boolean",
                        "description": "Recurring watcher: diff against the prior run's seen reviews (per listing) and output/alert ONLY reviews posted since the last run. Pair with an Apify Schedule.",
                        "default": false
                    },
                    "alertOnNewReview": {
                        "title": "Alert on new reviews",
                        "type": "boolean",
                        "description": "In monitor mode, deliver an alert for each new review via the channels below.",
                        "default": true
                    },
                    "webhookUrl": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "POST endpoint for new-review alert payloads (Make / Zapier / n8n / custom). One JSON body per alert."
                    },
                    "slackWebhookUrl": {
                        "title": "Slack webhook URL",
                        "type": "string",
                        "description": "Slack incoming-webhook URL for formatted new-review cards (stars + excerpt + listing link)."
                    },
                    "emailRecipients": {
                        "title": "Email recipients",
                        "type": "array",
                        "description": "Email addresses for the new-review digest (sent via apify/send-mail).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "proxyConfiguration": {
                        "title": "Proxy",
                        "type": "object",
                        "description": "Proxy settings. Datacenter rotation worked in testing; switch to residential if you scrape thousands of listings per day.",
                        "default": {
                            "useApifyProxy": true
                        }
                    },
                    "requestConcurrency": {
                        "title": "Listing concurrency",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "How many listings to scrape in parallel. Keep modest (4–8) to stay polite.",
                        "default": 4
                    },
                    "diagnose": {
                        "title": "Diagnostic mode (dev)",
                        "type": "boolean",
                        "description": "Dev only. Dumps the raw reviews API JSON to the key-value store (DEBUG_REVIEWS_JSON) and logs the parsed first record, then exits. Leave off for normal runs.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
