# Airbnb Multi-Listing Hosts by City (`wellbuilt_zythem/airbnb-host-portfolio`) Actor

Find the hosts running more than one Airbnb listing in a city. One row per host with portfolio size, superhost status, average rating, total reviews and median price. The listing data is public; the portfolio is not, and that is the product.

- **URL**: https://apify.com/wellbuilt\_zythem/airbnb-host-portfolio.md
- **Developed by:** [Carlos Escanez](https://apify.com/wellbuilt_zythem) (community)
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 host portfolios

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

## Airbnb Multi-Listing Hosts — who runs more than one flat in a city

**Not a list of listings. A list of the operators behind them.**

### See it run

https://youtu.be/Y84RiVi2MFQ

Airbnb shows you a listing at a time. It never shows you that seven of the flats you just scrolled past belong to the same person. This Actor works that out by comparing host ids across a whole city, and hands you one row per host:

```
7 listings | Marta | Superhost | 4.91 | 1,204 reviews | median $148 | 34 beds
5 listings | Urban Stay | Superhost | 4.78 |   612 reviews | median $210 | 22 beds
2 listings | Diego   |           | 4.96 |    29 reviews | median $119 |  8 beds
```

Sorted by portfolio size, because the operator with twenty flats is a business and the one with two is a hobby.

***

### What you get per host

Portfolio size. Superhost status and how many of their listings hold it. Average rating across the portfolio, total reviews, median, minimum and maximum price. Total guest capacity. How many listings are Guest Favourites. A sample of their listings with names, links and prices. Their public profile link.

In `listings` mode you get the raw rows instead: name, price, rating, reviews, capacity, property type, coordinates, and the host id that ties them together.

***

### Who buys this

- **Property management companies** — the whole pitch is "let us run your flats". A host with five listings is a qualified lead; a host with one is not.
- **Dynamic pricing and channel manager tools** — same reason, and portfolio size predicts willingness to pay for software.
- **Cleaning, laundry and maintenance firms** — one operator with twenty flats is worth twenty individual owners.
- **City councils and housing researchers** — concentration of short-term rentals in the hands of few operators is the exact number these studies need.
- **Investors** — where the professionals are already operating tells you the market works.

***

### Example inputs

**Professional operators only, two cities**

```json
{
  "locations": ["Lisbon, Portugal", "Porto, Portugal"],
  "minListings": 5,
  "pagesPerLocation": 10
}
```

**Everyone with a second flat, in euros**

```json
{
  "locations": ["Madrid, Spain"],
  "minListings": 2,
  "currency": "EUR"
}
```

**Raw listings for your own analysis**

```json
{
  "locations": ["Austin, TX"],
  "outputMode": "listings",
  "pagesPerLocation": 15
}
```

***

### What is deliberately not collected

**No email addresses, no phone numbers, no contact details of any kind.** Other tools in this category sell host contact data scraped from listing text. This one does not. You get the public profile link and the business facts: how many listings, what rating, what price. Reach out through Airbnb like anyone else.

Host names are the public display names Airbnb shows on the listing page. Nothing here is private data.

***

### Reliability, said plainly

Airbnb does not put listings in the page as ordinary links. It ships a preloaded JSON block that the browser uses to draw the page, and the listings live in there. Looking for `/rooms/` links finds nothing at all, which is why this looks harder than it is.

- **Measured on live pages:** 27 listings per search page in Madrid, 24 in Barcelona, and 25 of 26 listing pages returned a host id, from an ordinary datacenter address with no proxy.
- The id that works in a listing URL is not the listing's own id. Using the wrong one returns an Airbnb "not found" page **with status 200**, so a run can look successful and be empty. This Actor treats a suspiciously small 200 response as not-found rather than as data.
- Every retry leaves from a different proxy exit when proxying is on, because retrying on an address that just refused you gets refused again.
- `RUN_SUMMARY` reports pages served, pages refused, listings found, how many gave a host id, and megabytes used.

**A run finds a shared host only if it sees both listings.** One page of one city will rarely find anyone. Raise `pagesPerLocation` to give the comparison something to work with.

***

### Pricing

Pay per delivered row. Host rows and listing rows are charged separately, so `hosts` mode charges only for the rolled-up rows you asked for, not for the hundreds of listings read to build them.

***

### Data source

Public Airbnb search and listing pages. Records describe listings and their public marketing data. No guest data and no host contact details are collected.

# Actor input Schema

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

Write them as you would in the Airbnb search box: "Madrid, Spain", "Lisbon, Portugal", "Austin, TX".

## `minListings` (type: `integer`):

The filter that defines the product. 2 finds anyone with a second flat; 5 finds the professional operators worth a sales call.

## `outputMode` (type: `string`):

Hosts is one row per host, which is what most buyers want. Listings is the raw listing rows with a host id attached. Both returns hosts first, then listings.

## `pagesPerLocation` (type: `integer`):

About 27 listings per page. More pages means more listings compared against each other, which is what makes a shared host show up.

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

Prices come back in this currency. Without it Airbnb uses the currency of the server's country, which is not yours.

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

0 for no limit. Hosts arrive sorted by portfolio size, so a capped run keeps the biggest operators.

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

Airbnb serves search and listing pages without complaint from most addresses, so a proxy is optional. Turn on residential exits if a run reports listing pages giving no host id.

## Actor input object example

```json
{
  "locations": [
    "Madrid, Spain",
    "Barcelona, Spain"
  ],
  "minListings": 2,
  "outputMode": "hosts",
  "pagesPerLocation": 3,
  "currency": "USD",
  "maxResults": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per host with portfolio size, ratings and prices. In listings mode, one row per listing with its host id attached.

## `runSummary` (type: `string`):

Pages served, pages refused, listings found, how many gave a host id, and megabytes used. Read this to see what the run actually cost.

# 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 = {
    "locations": [
        "Madrid, Spain",
        "Barcelona, Spain"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wellbuilt_zythem/airbnb-host-portfolio").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 = { "locations": [
        "Madrid, Spain",
        "Barcelona, Spain",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wellbuilt_zythem/airbnb-host-portfolio").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 '{
  "locations": [
    "Madrid, Spain",
    "Barcelona, Spain"
  ]
}' |
apify call wellbuilt_zythem/airbnb-host-portfolio --silent --output-dataset

```

## MCP server setup

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

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/XqNZAQocWjQXAUEXu/builds/vcIkwSpovkMb5rdW8/openapi.json
