# Airbnb Competitor Watch (`titan_coder/airbnb-competitor-watch`) Actor

Daily digest: which of your competitors changed price or availability for the same stays, and where your listings stand. Pay only for delivered checks (price or confirmed unavailability); errors are free; no run fee.

- **URL**: https://apify.com/titan\_coder/airbnb-competitor-watch.md
- **Developed by:** [Radu Furtuna](https://apify.com/titan_coder) (community)
- **Categories:** Travel
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Competitor Watch 🔍

**Know the moment a competitor drops their price — before your guests do.**

Every morning, get a one-glance answer to the three questions every Airbnb host asks themselves: *Am I priced right? Who just got cheaper than me? Who went unavailable?* No spreadsheets, no manually opening 20 tabs — just a clean digest and a dataset you can plug anywhere.

### Why hosts use this

- **See price moves the day they happen.** Every competitor listing is checked against your exact dates. A price drop, a price hike, a listing going unavailable — you see it the next morning, not weeks later when your bookings quietly slow down.
- **Know your rank, not just a number.** For every stay, you get your position among comparable listings and how far you sit from the median — so "am I overpriced?" has an actual answer.
- **Pay only for real answers.** One event, `check-delivered`, billed only when a check comes back with a price or a confirmed unavailability/minimum-stay result. Errors, retries, and blocked attempts cost nothing. No run fee, no hidden per-diff charge.
- **Set it and forget it.** Attach an Apify Schedule once; get a digest every day with what changed, plus an optional webhook for Slack/Telegram/your own dashboard.

### How it works

1. Give it your listings and up to 30 competitors (or let it default to the next 8 weekends automatically).
2. It checks price and availability for each listing × stay combination, the same way a browser would.
3. It compares today's result to yesterday's, ranks your listing among comparable competitors, and writes one row per delivered check to a dataset.
4. You get a short digest (and an optional webhook) summarizing what changed.

### What you pay for

**One event only — `check-delivered`.** A check = listing × stay (check-in/check-out) × guests × currency that returned **either a price or a confirmed unavailability / minimum-stay restriction**. Errors, blocks, retries, and unchecked pairs are **free**. No run fee, no extra charge for the diff, digest, or webhook. Each saved row is charged exactly once — idempotent per monitor and observation — so re-running never double-bills you.

### What it does NOT promise

Occupancy or bookings ("unavailable" ≠ booked), the full breakdown of fees/taxes beyond what Airbnb itself shows, search-ranking position, automated price changes, or coverage of Booking.com/Vrbo. If Airbnb changes its page structure, we aim to fix it fast — but we don't guarantee a repair time.

### Input

| Field | What it does |
|---|---|
| `myListings` (1–5) | Your own listings — URL or ID |
| `competitorListings` (1–30) | Who you're watching |
| `stays` | Up to 30 check-in/check-out pairs; leave empty for the next 8 weekends automatically |
| `guests`, `currency` | 1–16 guests; 12 currencies supported |
| `historyMode` | `daily` remembers yesterday and reports changes; `none` for a one-off snapshot + ranking |
| `monitorId` | Names this monitor's own history (needed for `daily`) |
| `changeFilter`, `notifyOn` | Trim the digest to price-only or availability-only; control when the webhook fires |
| `webhookUrl` | HTTPS only; delivers the daily digest as JSON — pair it with Make/Zapier/n8n for Slack or Telegram |

### Output

- **Dataset** — one row per delivered check: status (`priced` / `unavailable_for_requested_stay` / `minimum_stay_restriction`), total price for the stay, change vs. yesterday (`changeType`, `deltaPct`), and your rank among comparable listings (`rankAmongPriced`, `medianPriced`, `deltaVsMedianPct`).
- **Key-value store** — `digest` (a short human-readable summary, ≤3,500 characters) and `coverage` (how many checks were answered, with reasons for anything skipped). With `historyMode=daily`, also a full run archive and baseline for tomorrow's comparison.
- **Run status** — a clear FAILED reason on bad input, a busy/locked monitor, or answered-coverage below 50% (rows already saved stay saved and billed — you never lose data you paid for).

### Scheduling

Save it as a Task and attach an Apify Schedule (daily works well). The Actor itself doesn't self-schedule.

### Limits

Up to 35 listings × 30 stays (≤1,050 checks per run); one retry per check on transient errors; an early stop after 20 consecutive failures so a bad run doesn't burn your budget; a light request pace designed to be a good citizen.

### A note on the source

Data comes from Airbnb's public listing pages, fetched the same way a browser does. Airbnb's Terms of Service restrict automated access — use this at your own discretion and within the limits that make sense for your account.

# Actor input Schema

## `monitorId` (type: `string`):

Name of this monitoring set (a-z, 0-9, dash; up to 40 chars). Keeps its own history. Required when historyMode=daily.

## `historyMode` (type: `string`):

daily — remembers yesterday's prices and reports what changed (needs a stable monitorId across runs); none — one-off snapshot and ranking only, no comparison to previous runs.

## `myListings` (type: `array`):

1–5 Airbnb listing URLs or IDs (https://www.airbnb.com/rooms/12345678). Only the numeric ID is used.

## `competitorListings` (type: `array`):

1–30 Airbnb listing URLs or IDs of competitors. Duplicates and overlaps with your listings are rejected.

## `stays` (type: `array`):

Up to 30 pairs {"checkIn":"YYYY-MM-DD","checkOut":"YYYY-MM-DD"}. Leave empty for the next 8 weekends (Fri→Sun, 2 nights). checkIn must be strictly after today in your timezone.

## `timezone` (type: `string`):

Used to build default weekends and the 'today' cut-off, e.g. Europe/Lisbon. Default UTC (a warning is logged).

## `guests` (type: `integer`):

Number of guests used for every check, same for your listings and competitors.

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

Currency requested from Airbnb for every check. A different currency returned by Airbnb marks that check unknown\_error rather than mixing currencies in the digest.

## `changeFilter` (type: `string`):

Filters only the digest/webhook. The dataset always contains every delivered check.

## `notifyOn` (type: `string`):

changes — post the webhook only when something changed since yesterday; always — post it every run; never — do not call webhookUrl at all.

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

Optional. Receives the daily digest as JSON (POST). HTTPS only; private/loopback addresses are rejected; redirects are not followed. Slack/Telegram need an adapter (Make, Zapier, n8n).

## Actor input object example

```json
{
  "monitorId": "my-hotel-vs-neighbours",
  "historyMode": "daily",
  "stays": [],
  "timezone": "UTC",
  "guests": 2,
  "currency": "EUR",
  "changeFilter": "all",
  "notifyOn": "changes"
}
```

# Actor output Schema

# 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 = {
    "monitorId": "my-hotel-vs-neighbours",
    "stays": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("titan_coder/airbnb-competitor-watch").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 = {
    "monitorId": "my-hotel-vs-neighbours",
    "stays": [],
}

# Run the Actor and wait for it to finish
run = client.actor("titan_coder/airbnb-competitor-watch").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 '{
  "monitorId": "my-hotel-vs-neighbours",
  "stays": []
}' |
apify call titan_coder/airbnb-competitor-watch --silent --output-dataset

```

## MCP server setup

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

```

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/t7X92AkV0eWavyl1u/builds/3gbtbQm3z5uYPtFZJ/openapi.json
