# Airbnb Rank Tracker (`cirkit/airbnb-rank-tracker`) Actor

Find where an Airbnb listing ranks in search. Runs each search several times because Airbnb reshuffles results on every request, then reports median, best and worst position, appearance rate, page, and the competitors ranked above you with their price and rating.

- **URL**: https://apify.com/cirkit/airbnb-rank-tracker.md
- **Developed by:** [Crikit](https://apify.com/cirkit) (community)
- **Categories:** Travel, Real estate, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$50.00 / 1,000 ranking measureds

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/actors/running/actors-in-store.md#pay-per-event

## 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

### What is Airbnb Rank Tracker?

**Airbnb Rank Tracker** lets you find out where your Airbnb listing actually appears in search results for the destinations and dates your guests are booking, helping you prove whether an optimisation worked, catch a drop in visibility before your calendar empties, and see exactly which competitors are ranked above you.

Airbnb does not show hosts their search position, and it does not return a stable one. Reload the same search twice and the order changes. That is why this actor does not report a single number from a single fetch.

- 🎯 **Know where you really rank:** every search is run several independent times and reported as a median, best and worst position, so you get a range you can trust instead of one lucky or unlucky snapshot.
- 📉 **Catch visibility drops early:** the `appearanceRate` field shows how often your listing showed up at all. A listing that appears in only 2 of 3 identical searches is losing impressions, and no single-shot rank checker can see that.
- 🥊 **See who is beating you:** every row carries the listings ranked immediately above yours with their price, rating, review count and badges, so you can tell whether you are losing on price, on reviews, or on Guest Favourite status.
- 📅 **Rank for real booking windows:** set the check-in and check-out dates and guest count you care about. Ranking for a date range you are actually trying to fill is the only ranking that matters.
- 🏘 **Track a whole portfolio cheaply:** every listing you track is looked up inside the same market scan, so tracking 20 properties in one city costs the same page fetches as tracking one.
- 🔁 **Built to be scheduled:** point it at your listings once, run it on a schedule, and keep a dated history of your position over time.

Unlike a manual check in a browser, this does not depend on your own location, login state or cookies, and it does not quietly show you a personalised result set and call it a ranking.

### What data does Airbnb Rank Tracker extract?

- 🏷 Listing id, name and canonical URL (`listingId`, `listingName`, `listingUrl`)
- 🔎 The exact search it was ranked in, with dates and filters (`searchLabel`, `searchUrl`, `checkIn`, `checkOut`, `adults`)
- 📊 Median, best and worst position across samples (`medianRank`, `bestRank`, `worstRank`)
- 📈 How far the position moved between identical searches (`rankSpread`)
- 🧾 The raw position from every individual sample (`sampleRanks`)
- 👀 How often the listing appeared at all, 0 to 1 (`appearanceRate`, `timesFound`, `samplesRun`)
- 📄 Results page and position on that page (`page`, `positionOnPage`)
- 🚦 A banded verdict: PAGE\_1, PAGE\_2\_3, DEEP or NOT\_VISIBLE (`visibility`)
- 💲 Your listing's price, rating, review count, badges and Guest Favourite status as shown in search (`listing`)
- 🥊 Up to five competitors ranked directly above you, with their pricing and ratings (`competitorsAbove`)
- 🏆 The top three listings in the market (`marketTopThree`)
- 📐 How deep the scan went (`scanDepth`, `pagesScanned`)
- ⏱ Measurement timestamp (`scrapedAt`)

### How to use Airbnb Rank Tracker

1. Paste your Airbnb listing URLs into **Listings to track**. Bare numeric ids work too.
2. Type the destinations you want to rank for into **Destinations to rank against**, exactly as a guest would type them, for example `Asheville, North Carolina`. You can paste full Airbnb search URLs instead if you want specific filters.
3. Set **Check-in** and **Check-out** to a booking window you care about. This matters a lot, see the FAQ.
4. Leave **Samples per search** at 3 and **Pages to scan** at 5 unless you know you rank deep.
5. Run it, then read the Rankings table or export to CSV, Excel, or JSON.

### Input

```json
{
  "listingUrls": [
    "https://www.airbnb.com/rooms/2072026",
    "https://www.airbnb.com/rooms/39811858"
  ],
  "locations": ["Asheville, North Carolina"],
  "checkIn": "2026-10-15",
  "checkOut": "2026-10-18",
  "adults": 2,
  "samples": 3,
  "maxPages": 5,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyCountry": "US" }
}
```

### Output

One row per tracked listing per search. A real record, trimmed:

```json
{
  "listingId": "2072026",
  "listingName": "The Tree House Studio, Mins to Downtown",
  "searchLabel": "Asheville, North Carolina",
  "checkIn": "2026-10-15",
  "checkOut": "2026-10-18",
  "found": true,
  "appearanceRate": 1,
  "samplesRun": 3,
  "timesFound": 3,
  "medianRank": 7,
  "bestRank": 7,
  "worstRank": 7,
  "rankSpread": 0,
  "sampleRanks": [7, 7, 7],
  "page": 1,
  "positionOnPage": 7,
  "visibility": "PAGE_1",
  "scanDepth": 83,
  "listing": {
    "price": "$391", "rating": 4.94, "reviewsCount": 464, "isGuestFavorite": true
  },
  "competitorsAbove": [
    { "rank": 6, "listingId": "39811858", "price": "$577", "rating": 4.93, "reviewsCount": 366 }
  ],
  "scrapedAt": "2026-08-30T18:04:11.000Z"
}
```

The **Rankings** table view shows listing, search, visibility, median, best, worst, spread and appearance rate as clean columns, so you can read a portfolio at a glance without unpacking JSON.

### How much does it cost to track Airbnb rankings?

A flat **$0.05 per ranking**. One ranking is one tracked listing in one search, and it covers every sample and every page scanned to produce it. A deep scan costs the same as a first-page hit.

| Rankings | Cost |
|---|---|
| 20 | $1.00 |
| 100 | $5.00 |
| 1,000 | $50.00 |

Because all your tracked listings are found inside the same market scan, a portfolio is much cheaper than it looks: tracking 20 listings across 5 destinations is 100 rankings, or $5.00 per run, however deep the scan has to go.

### Measured coverage

From a QA run across three markets (Savannah, Scottsdale and Gatlinburg), tracking six known listings plus one deliberately invalid id, 21 rows total:

| Check | Result |
|---|---|
| Correct found / not-found classification | 21 / 21 |
| False positives | 0 |
| False negatives | 0 |
| Field coverage on found rows | 100% on all 12 core fields |
| Runs ending SUCCEEDED across 8 edge cases | 8 / 8 |

Why the sampling exists, from that same run: one tracked listing was returned at position **52**, then **18**, then not at all, across three identical searches seconds apart. Any single-fetch rank checker would have reported one of those three answers with full confidence. Repeated identical searches returned only about 14 of the same 18 listings on page 1, and no listing held the same position twice.

### Limits

- **Airbnb reshuffles results on every request.** This actor measures and reports that spread rather than hiding it. Treat `medianRank` as a band, not a coordinate, and read `rankSpread` alongside it.
- **Maximum scan depth is 270 listings**, about 15 pages. Airbnb stops issuing pagination cursors past that point. A listing that never appears within your scan depth is reported as NOT\_VISIBLE rather than given a number.
- **Ranking is personalised.** These results reflect a clean, logged-out, US-based guest. A specific guest with history may see something different.
- **Dateless searches are much noisier.** Airbnb randomises them heavily, so ranks without dates are far less meaningful.
- **A listing unavailable for your dates will not appear at all.** That is a real ranking outcome for those dates, not a scraping failure, and it is why `NOT_VISIBLE` rows carry an explanatory `warning`.
- Only public search data is read. No login, no cookies, no private host analytics.

### FAQ

#### Is it legal to scrape Airbnb search results?

This actor reads only public Airbnb search pages that any logged-out visitor can see. It collects no login-gated data and no personal data about guests. You are responsible for how you use the output and for your own compliance with Airbnb's terms and applicable law.

#### Why do my ranks change between runs?

Because Airbnb's ranks genuinely change between requests. That is the core problem this actor exists to handle. Look at `rankSpread` and `appearanceRate`: a spread of 2 means a stable position, a spread of 30 means Airbnb is moving you around and any single number is misleading.

#### How many samples should I use?

Three is right for most markets. Use five in large, volatile markets or when `rankSpread` comes back wide. Use one only for a rough smoke test.

#### Why is my listing NOT\_VISIBLE when I can see it in the app?

Three common causes: your listing is unavailable for those dates, your app view is personalised or location-biased, or your listing ranks deeper than your `maxPages` setting. Raise `maxPages` and confirm the dates are bookable.

#### Can I use Airbnb Rank Tracker as an API?

Yes. Every actor on Apify has a REST API for starting runs and pulling results. See the [Apify API docs](https://docs.apify.com/api/v2).

#### Can I use this in Python?

Yes, with `apify-client`:

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("cirkit/airbnb-rank-tracker").call(run_input={
    "listingUrls": ["https://www.airbnb.com/rooms/2072026"],
    "locations": ["Asheville, North Carolina"],
    "checkIn": "2026-10-15", "checkOut": "2026-10-18"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["listingName"], item["medianRank"], item["visibility"])
```

#### How do I schedule Airbnb Rank Tracker to run automatically?

Use Apify Schedules to run it daily or weekly. Each run is timestamped with `scrapedAt`, so the dataset history becomes your rank-over-time chart.

#### Can I integrate it with other apps?

Yes. Apify has native integrations for Zapier, Make, Google Sheets, Slack, Airtable and generic webhooks, so a rank drop can trigger an alert.

#### Can I track competitors instead of my own listings?

Yes. Nothing about the input assumes you own the listing. Put any listing ids in `listingUrls` to track a rival's visibility over time.

#### Why did I get fewer rows than expected?

Rows are tracked listings multiplied by searches, capped by `maxItems`. Check that `maxItems` is at least that product, and that every listing URL parsed correctly, since unparseable entries are skipped with a warning in the log.

#### Can I get a field that is not listed?

If it appears on the Airbnb search card, it can usually be added. Open an issue on the actor and ask.

### You might also like

- [Airbnb Search Scraper](https://apify.com/cirkit/airbnb-search-scraper) for the full result set behind these rankings
- [Airbnb Listing Details Scraper](https://apify.com/cirkit/airbnb-details-scraper) for everything on a single listing page
- [Airbnb Reviews Scraper](https://apify.com/cirkit/airbnb-reviews-scraper) for full review histories
- [Airbnb Host Listings Scraper](https://apify.com/cirkit/airbnb-host-scraper) for a host's whole portfolio

### Changelog

- **0.1** (2026-08-30) First release. Multi-sample ranking with median, best, worst and spread, appearance rate, competitor context and outlier-scan rejection.

# Actor input Schema

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

The Airbnb listings you want a rank for. Paste full listing URLs (https://www.airbnb.com/rooms/12345678) or bare numeric listing ids. Every listing is looked up in every search below, and tracking more listings in the same market costs no extra page fetches.

## `locations` (type: `array`):

Destinations exactly as a guest would type them into Airbnb, for example "Asheville, North Carolina". One search is run per destination. Leave empty if you are pasting full search URLs instead.

## `searchUrls` (type: `array`):

Full Airbnb search URLs copied from your browser, for example https://www.airbnb.com/s/Asheville--North-Carolina/homes?adults=2. Use these when you want the exact filters, map area or amenity set a guest would see. Any dates and guest counts you set below are applied unless the URL already carries them.

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

Check-in date as YYYY-MM-DD. Strongly recommended: without dates Airbnb heavily randomises results and ranks become much less meaningful. Dates in the past are ignored.

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

Check-out date as YYYY-MM-DD. Must be after the check-in date.

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

Number of adults in the search, matching the guest you want to rank for.

## `children` (type: `integer`):

Number of children in the search. Leave empty for none.

## `pets` (type: `integer`):

Number of pets in the search. Setting this filters out listings that do not allow pets, which changes the ranking.

## `samples` (type: `integer`):

How many independent times to run each search. Airbnb returns a different order on every request and drops listings at random, so one sample is not enough to state a rank. Three is a good balance; five gives a tighter median on volatile markets.

## `maxPages` (type: `integer`):

How deep to look, at 18 listings per page. 5 pages covers the first 90 results, which is where essentially all booking traffic goes. Scanning stops early as soon as every tracked listing has been found, so ranking well costs less.

## `priceMin` (type: `integer`):

Only rank against listings at or above this nightly price, matching Airbnb's price filter.

## `priceMax` (type: `integer`):

Only rank against listings at or below this nightly price, matching Airbnb's price filter.

## `minBedrooms` (type: `integer`):

Apply Airbnb's minimum-bedrooms filter to the search before ranking.

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

Currency for the prices shown on the result cards.

## `locale` (type: `string`):

Airbnb locale used for the request, which controls the language of titles and badges.

## `maxItems` (type: `integer`):

Hard cap on rows written, and therefore on what the run can cost. One row is produced per tracked listing per search.

## `maxConcurrency` (type: `integer`):

How many search pages to fetch at once. Lower this if you see throttling warnings in the log.

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

Proxy used for the searches. Airbnb returns a US-shaped result set only from US exits, so the country is pinned to US by default. Leave this as it is unless you are deliberately ranking a non-US storefront.

## Actor input object example

```json
{
  "listingUrls": [
    "https://www.airbnb.com/rooms/2072026"
  ],
  "locations": [
    "Asheville, North Carolina"
  ],
  "searchUrls": [
    {
      "url": "https://www.airbnb.com/s/Asheville--North-Carolina/homes"
    }
  ],
  "checkIn": "2026-10-15",
  "checkOut": "2026-10-18",
  "adults": 2,
  "samples": 3,
  "maxPages": 5,
  "currency": "USD",
  "locale": "en-US",
  "maxItems": 100,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `rankings` (type: `string`):

Every ranking measured in this run, as JSON.

## `rankingsCsv` (type: `string`):

The same rankings as a CSV download.

## `rankingsExcel` (type: `string`):

The same rankings as an Excel workbook.

# 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/2072026",
        "https://www.airbnb.com/rooms/39811858"
    ],
    "locations": [
        "Asheville, North Carolina"
    ],
    "checkIn": "2026-10-15",
    "checkOut": "2026-10-18",
    "adults": 2,
    "samples": 3,
    "maxPages": 5,
    "currency": "USD",
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("cirkit/airbnb-rank-tracker").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/2072026",
        "https://www.airbnb.com/rooms/39811858",
    ],
    "locations": ["Asheville, North Carolina"],
    "checkIn": "2026-10-15",
    "checkOut": "2026-10-18",
    "adults": 2,
    "samples": 3,
    "maxPages": 5,
    "currency": "USD",
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("cirkit/airbnb-rank-tracker").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 '{
  "listingUrls": [
    "https://www.airbnb.com/rooms/2072026",
    "https://www.airbnb.com/rooms/39811858"
  ],
  "locations": [
    "Asheville, North Carolina"
  ],
  "checkIn": "2026-10-15",
  "checkOut": "2026-10-18",
  "adults": 2,
  "samples": 3,
  "maxPages": 5,
  "currency": "USD",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}' |
apify call cirkit/airbnb-rank-tracker --silent --output-dataset

```

## MCP server setup

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

```

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/I5PDaYLiT6Is5nGlC/builds/AcASCXiKUbxOstxPu/openapi.json
