Airbnb Host Portfolio & Operator Mapper
Pricing
from $0.80 / 1,000 row saveds
Airbnb Host Portfolio & Operator Mapper
Turn Airbnb listings into host entities. One row per operator: every listing found in the areas you scan, whole-property share, years hosting, registration numbers and an auditable 0-100 operator score. Filter to multi-property hosts, scan a city as a grid, get a coverage report. No account needed.
Pricing
from $0.80 / 1,000 row saveds
Rating
0.0
(0)
Developer
Hamza
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
17 days ago
Last modified
Categories
Share
Airbnb shows you listings. This actor shows you the people and companies behind them. Point it at a city or a map rectangle and it comes back with one row per host: every listing of theirs it found, how many are whole properties, how long they have been hosting, their own rating, the registration or licence number on each listing and where that number was published, the geographic centre and spread of their portfolio, and a published 0–100 commercial-operator score. It is built for regulators, housing researchers, hotel and short-let analysts, and anyone who needs to separate the neighbour renting a spare room from an operator running forty flats. No Airbnb account, no login, nothing to connect.
What you can do with it
- Find the commercial operators in a market. Set a minimum portfolio size of two or more and the dataset becomes a list of multi-property hosts, ranked by size and by operator score.
- Support a short-let compliance review. Every listing reports its registration or licence number and which of the places Airbnb publishes it the number came from, plus an optional check against the format your city uses.
- Measure real market concentration. Whole-property share, portfolio size distribution and median nightly rate per host tell you how much of a neighbourhood's supply sits with a handful of operators.
- Build a property-management prospect list. Hosts with several whole properties, a real tenure and no superhost badge are exactly the audience for management, cleaning, insurance and pricing tools.
- Map a competitor's footprint. The portfolio centroid, spread in kilometres and neighbourhood list show where an operator actually concentrates.
- Track a market over time. Run it on a schedule and compare host rows between runs to see who is growing, who has left and who has newly appeared.
What you get
One row per host. Abridged example:
{"recordType": "host","hostUserId": "10214195","hostName": "Pierre","hostProfileUrl": "https://www.airbnb.com/users/profile/1462834525352805037","hostContextualUserId": "1462834525352805037","isSuperhost": false,"isVerified": true,"hostTitleText": "Host","yearsHosting": 11,"monthsHosting": 133,"hostRatingAverage": 4.68,"hostRatingCount": 79,"listingCount": 2,"listingCountIsComplete": false,"listingCountScope": "Minimum — listings found in the areas scanned (Paris, France); the host may hold more","listingCountStatement": "2 listings found for this host in the areas this run scanned (Paris, France). That is a minimum, not a total: the scan stopped at the listing limit set for the run, so this host may hold more listings in the same areas. Listings this host holds outside the areas scanned are not counted, and Airbnb does not publish a host's total listing count anywhere on a listing page, so no tool can report one. Scan a wider area or raise the listing limit to raise this floor.","placesSeenIn": ["Paris, France"],"coverageConfidence": "partial","scanStoppedAtListingLimit": true,"scanStoppedAtRunLimit": false,"areasLeftCrowded": 0,"portfolioMetricsArePartial": true,"listingIds": ["1737062443587734735", "1716681499327714304"],"entireHomeCount": 2,"entireHomeSharePct": 100,"privateRoomCount": 0,"medianNightlyRate": 217.2,"currency": "USD","totalPersonCapacity": 8,"medianBedrooms": 1,"listingsWithRegistration": 2,"listingsWithoutRegistration": 0,"registrationNumbers": ["7510203094826"],"licenceSources": ["descriptionModal"],"registrationFormatValidCount": 1,"centroidLatitude": 48.87051,"centroidLongitude": 2.34879,"coordinateSpreadKm": 4.311,"neighbourhoods": ["Paris, Île-de-France, France"],"commercialOperatorScore": 47,"commercialOperatorScoreIsProvisional": true,"commercialOperatorVerdict": null,"commercialOperatorVerdictBasis": "No verdict: the scan covered part of the area, so a larger portfolio cannot be ruled out and calling this host small would be a guess. The score of 47 out of 100 describes only the listings found here.","commercialOperatorScoreInputs": {"listingCount": 2,"entireHomeCount": 2,"entireHomeSharePct": 100,"yearsHosting": 11,"portfolioSizePoints": 6.67,"entireHomePoints": 25,"tenurePoints": 15},"placesScanned": ["Paris, France"],"scrapedAt": "2026-07-29T10:00:00.000Z"}
Alongside the host rows you also get, unless you switch them off, one
recordType: "listing" row per property — with its own registrationNumber,
licenceSource, propertyType, bedrooms, beds, bathrooms,
personCapacity, ratingValue, reviewCount, coordinates and the host it
belongs to — and one recordType: "coverageReport" row per area scanned, which
states in plain English how much of that area was actually covered.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
places | list of strings | ["Paris, France"] | Cities or areas to scan, written the way you would type them into Airbnb's own search box. Up to 10. |
bboxes | list of objects | [] | Optional exact rectangles, each {neLat, neLng, swLat, swLng} with an optional query naming the neighbourhood. Up to 20. |
tileSaturationThreshold | integer | 240 | When one map area reaches this many listings it is divided into four smaller areas and each is scanned again. Lower is more thorough and slower. Max 320. |
maxQuadtreeDepth | integer | 3 | How many times a crowded area may be divided. Max 6. |
roomTypes | multi-select | [] | Restrict to Entire home/apt, Private room, Shared room or Hotel room. Whole properties are what short-let rules usually target. |
priceBands | list of objects | [] | Optional {min, max} slices, used only when an area is still crowded after being divided as far as allowed. Up to 8. |
minPortfolioSize | integer | 1 | Only save hosts with at least this many listings in the area scanned. Set 2+ for multi-property operators only. Max 50. |
unregisteredOnly | boolean | false | Save only hosts with at least one listing whose registration number is not visible. |
registrationFormat | string | empty | Optional pattern each number is checked against, e.g. ^\d{13}$. Each record then reports whether it matched. |
includeLicence | boolean | true | Collect registration and licence numbers. |
emitListingRows | boolean | true | Also save one row per listing behind each portfolio. Turning it off lowers both the row count and the cost. |
maxListings | integer | 500 | The main size and cost control: how many listings get looked up individually to find their host. It also decides how much of an area you see — see the note below. Max 5,000. |
maxRequests | integer | 800 | A hard ceiling on total work per run. The run stops cleanly when it is reached and the coverage report says so. Max 8,000. |
| Parallel workers | integer | 4 | How many listings are worked through at the same time. Higher finishes sooner; 4 is a good balance. Max 8. |
currency | string | USD | Currency for the nightly rates in the output. |
locale | string | en | Language for names, property types and neighbourhood labels. |
proxyCountry | string | empty | Country to appear to browse from, as a two-letter code. Leave empty unless a market looks different from different countries. |
What the default 500 buys, and when to change it. 500 is a cheap first look — enough to scan a single district until it stops producing new listings. A whole city is a different job: Paris alone carries tens of thousands of listings, so a 500-listing run over it is a thin slice, and in a thin slice almost every host looks like a one-property host — a real operator with thirty flats across the city only shows the handful that happened to fall inside the slice. That is a fact about how much was scanned, not about the market, and the run says so in the log, in the coverage report and on every host row.
The default is deliberately left small, because it is also what you are billed for and raising it does not on its own make a city complete: even the 5,000 maximum is a fraction of Paris. If you want portfolios rather than a sample, scan an area small enough to finish — one or two map rectangles over the districts you care about — and the run can then tell you a host is small, instead of withholding the verdict. If you want a broad market sweep, raise
maxListingsand read every count as the floor it is labelled as.
Output fields
Host rows (recordType: "host")
| Field | Type | Description |
|---|---|---|
hostUserId | string | Airbnb's own identifier for the host. Stable between runs, so it is the key to join on. |
hostName / hostTitleText | string | Display name, and the label Airbnb shows under it (Host, Superhost). |
hostProfileUrl / hostContextualUserId | string | Link to the public profile, and the separate identifier that link is built from. |
isSuperhost / isVerified | boolean | Badge and identity-verification status. |
yearsHosting / monthsHosting | number | Tenure, in whole years and in total months. |
hostRatingAverage / hostRatingCount | number | The host's own rating and review total across all their listings. |
listingCount / listingIds | number / array | How many of this host's listings the run found in the areas it scanned, and their identifiers. It is a floor, not a verified total — see the note under this table. |
listingCountIsComplete | boolean | true only when every area this host appeared in was scanned until it stopped producing new listings. false means the count is a minimum. |
listingCountScope | string | One line naming exactly what the count covers, so a column of numbers is never read on its own. |
listingCountStatement | string | The same thing in full sentences: what was counted, why it may be short, and how to raise it. |
placesSeenIn / coverageConfidence | array / string | Which of the areas you asked for this host turned up in, and how well those areas were covered (high, partial, low, unknown). |
scanStoppedAtListingLimit / scanStoppedAtRunLimit / areasLeftCrowded | boolean / boolean / number | Whether your listing limit or the run's own size limit ended the scan early, and how many areas were still producing new listings when it stopped. Any of these means the count is short. |
portfolioMetricsArePartial / metricsAffectedByScanScope | boolean / array | Whether the portfolio numbers on this row are bounded by the scan, and the exact list of columns that are. |
entireHomeCount / entireHomeSharePct / privateRoomCount | number | How much of the portfolio found in the areas scanned is a whole property versus a room. |
medianNightlyRate / currency | number / string | Median nightly rate observed across the portfolio, in your chosen currency. |
totalPersonCapacity / medianBedrooms | number | Combined guest capacity and typical property size, across the listings found. |
listingsWithRegistration / listingsWithoutRegistration | number | How many of the listings found publish a registration number. Both are counts of what was found, so both move if a wider area is scanned. |
registrationNumbers / licenceSources | array | The distinct numbers found, and where each was published. |
registrationFormatValidCount | number | How many matched your expected format. Null when no format was given. |
centroidLatitude / centroidLongitude / coordinateSpreadKm | number | Geographic centre of the portfolio and the distance between its two furthest listings. |
neighbourhoods | array | Neighbourhood labels the portfolio spans. |
commercialOperatorScore | number | 0–100 composite, see below. Built from the listings found, so it moves as the scan widens. |
commercialOperatorScoreIsProvisional | boolean | true when the score was computed from a portfolio that was only partly found. |
commercialOperatorVerdict | string | likely commercial operator, small or individual host, or blank. It is left blank rather than guessed whenever the areas were not scanned in full and the listings found are too few to be sure — calling a large operator a small host is the one mistake this dataset refuses to make. |
commercialOperatorVerdictBasis | string | Why the verdict says what it says, in one sentence. |
commercialOperatorScoreInputs | object | Every number that produced the score, so it can be recomputed by hand. |
placesScanned | array | Which of your inputs this run covered. |
scrapedAt / actorRunId | string | When the row was produced, and by which run. |
About
listingCount. It counts the host's listings that this run found in the areas it scanned. It is a floor, not a verified total: the same host may hold more listings in the same city that the run did not reach, and more again in cities it never looked at. Airbnb does not publish a host's total listing count anywhere on a listing page — a listing page carries the host's rating, review count and how long they have been hosting, and nothing about how many properties they hold — so no tool can report a verified total, and any that claims to is counting what it happened to find. To raise the floor, scan a wider area (more cities, or map rectangles covering the neighbourhoods you care about) and raisemaxListingsso the sweep is not cut short. Sort bylistingCountto rank operators, but readlistingCountIsCompleteandlistingCountScopebefore quoting any single number.
Listing rows (recordType: "listing")
listingId, listingUrl, listingName, listingTitle, latitude,
longitude, propertyType, roomTypeText, personCapacity, bedrooms,
beds, bathrooms, ratingValue, reviewCount, isGuestFavorite,
nightlyRate, currency, neighbourhood, registrationNumber,
hasRegistration, licenceSource, registrationFormatValid, hostUserId,
hostName, isSuperhost, tileId, tileDepth, place, scrapedAt.
Coverage rows (recordType: "coverageReport")
place, rootBbox, tilesVisited, tilesSplit, tilesStillSaturated,
uniqueListings, requestsUsed, budgetExhausted, listingCeilingReached,
maxDepthReached, mapAreasUnread, mapAreasPartlyRead, coverageConfidence
(high / partial / low), completenessStatement, listingsEnumerated,
listingsResolved, listingsAttributed, listingsWithoutHostCard,
listingsWithoutPdp, hostsFound, hostsBelowMinPortfolio, scrapedAt.
listingsResolved counts the listings whose details were read;
listingsAttributed counts the ones that actually named a host, and
listingsWithoutHostCard counts the difference — listings that published no host
at all. Only the attributed ones can appear in a portfolio, so those three
numbers, plus listingsWithoutPdp, add up to listingsEnumerated.
listingCeilingReached is true when the scan stopped because it had collected
as many listings as you allowed, rather than because the areas ran out. When that
happens the confidence is never high and the plain-English statement says so —
a run that stops at your own limit has seen a slice of the market, not all of it.
How the operator score is calculated
The score is a published formula, not a black box, and every input to it is in the row so you can check the arithmetic:
| Component | Weight | How it is awarded |
|---|---|---|
| Portfolio size | 60 points | 1 listing scores 0; 10 or more scores the full 60; linear in between. |
| Whole-property share | 25 points | 25 × the share of the portfolio that is a whole property rather than a room. |
| Tenure | 15 points | 15 × (years hosting ÷ 5), capped at 5 years. |
So a host with ten whole properties and five years of hosting scores 100, while a long-standing host with a single whole flat scores 40 — the size of the portfolio is deliberately the dominant term. It is a comparison aid, not an official designation of any kind.
Because portfolio size dominates, the score moves with how much ground the run
covered. That is why each row carries commercialOperatorScoreIsProvisional and
why commercialOperatorVerdict is asymmetric: likely commercial operator is
given whenever the listings already found earn 50 points or more, since finding
more of a host's listings cannot make them smaller — but
small or individual hostcommercialOperatorVerdictBasis. A blank verdict means "not
established", never "small".
Pricing
This actor is pay per event and there are two charges:
- Row saved — $0.0008 for every row written, which is $0.80 per 1,000 rows. It covers host rows, listing rows and coverage rows alike.
- Listing host resolved — $0.008 each time one listing is opened
individually to read who hosts it and whether a registration number is
published. This is the real work behind the dataset: it happens once per
listing, and it is the reason
maxListingsis the setting that controls your bill.
A typical first pass — 500 listings resolved into roughly 300 host rows — costs about $4.24, or about $4.64 with the per-listing rows kept as well. Filtering by minimum portfolio size or by missing registration reduces the rows you keep but not the resolution charge, because a host can only be filtered once their listings have been attributed to them. Areas that turn out to be empty cost nothing, and if you set a maximum cost for a run the actor stops cleanly as soon as that budget is spent rather than overshooting it.
Limits and what this actor cannot do
Every one of these is real, and most of them are Airbnb's own ceilings rather than this actor's:
listingCountis a floor, never a verified total. It counts the host's listings this run found inside the areas it scanned. Airbnb does not publish a host's total listing count anywhere on a listing page — the page carries their rating, review count and how long they have been hosting, and nothing about how many properties they hold — so no tool can report a verified total, and one that claims to is reporting what it happened to find. Every host row therefore carrieslistingCountIsComplete,listingCountScopeand the coverage grade for the areas that host was seen in, so the qualifier travels with the number even when you sort, filter or export. To raise the floor: scan a wider area (add cities, or map rectangles over the neighbourhoods you care about) and raisemaxListingsso the sweep is not cut short. A run of 500 listings over a city with tens of thousands will show most operators as one- or two-property hosts, because that is all it looked at.- Everything counted out of the portfolio inherits that floor —
whole-property share, guest capacity, how many listings lack a registration
number, and the operator score itself. Each host row names those columns in
metricsAffectedByScanScopeand flags them withportfolioMetricsArePartial. Where the areas were not scanned in full, the row gives a score but withholds the one-word verdict rather than label a large operator a small host. - Airbnb publishes no index of a host's listings. A portfolio can only be assembled by scanning an area and grouping what is found, so a host with properties outside the area you scanned is under-counted. This is the single most important limitation of this dataset, and it is why every run ships a coverage report.
- Airbnb shows only a few hundred listings for any single search and starts
repeating itself past that point. A market is therefore covered by splitting it
into map areas and merging the results, and coverage cannot be proven
complete — the coverage report names the areas that were still crowded when
scanning stopped and gives a confidence level of
high,partialorlow. Evenhighmeans "thorough for the area scanned", never "complete". - Registration and licence numbers are published inconsistently by market.
Each record reports where its number was found, and a blank means "not
published anywhere we can see it" — not that a listing is unlicensed or
that a host is breaking any rule. Treat the
unregisteredOnlyfilter as a starting point for a review, never as a finding. - The host's own rating count is host-level. It covers all of their listings and legitimately differs from any single listing's review count — 79 against 78 on a real host we checked. Both numbers are in the output; do not compare them as if they measured the same thing.
- Bedroom, bed and bathroom counts come from the listing's own summary line, which is the only place Airbnb publishes them. A listing described only as a studio has no bedroom count, and that is reported as blank rather than guessed.
- Nightly rates are what Airbnb was showing at the time of the run, for its own default stay window and without any dates of yours. They are useful for comparing hosts within one run, not as a booked-revenue figure, and cleaning and service fees are not itemised separately.
- The operator score is a composite with published weights, not an official classification, a legal determination or a measure of anything Airbnb itself publishes. Because it is built from the listings found, it moves as the scan widens, and a low score on a partly scanned area means "not shown to be large here", never "small".
- A host with no published host card cannot be attributed. Those listings are counted separately in the run log and in each coverage row, and left out of the portfolios rather than assigned to a placeholder — which is why the listings looked up and the listings attributed to a host are two different numbers.
- Only English has been verified. Other languages will change how property types, neighbourhood labels and summary lines read, and the size parsing has not been checked against them.
- Speed depends on the size of the job and on how quickly Airbnb answers. No fixed run time is promised.
- Airbnb's terms prohibit automated access. You are responsible for using this data lawfully and in line with the source site's terms, and for whatever conclusions you draw from it.
FAQ
Do I need an Airbnb account? No. No Airbnb account, no login, no personal details — enter a city and run it.
Is the data complete?
No, and no tool can make it so. Airbnb never publishes a list of a host's
properties nor a count of them, and it stops showing new listings for any one
search after a few hundred. This actor gets past the second problem by scanning a
market as a grid of smaller areas, but the honest answer travels on every row:
listingCount is what was found in the areas scanned, listingCountIsComplete
says whether those areas were finished, and the coverage report grades each area
high, partial or low. Read those before quoting a number.
Does a blank registration number mean the listing is illegal? No, and please do not report it that way. It means no number was published anywhere visible for that listing. Some markets do not require one, some hosts put it somewhere the public page does not show, and some listings are exempt. Every record that does carry a number also says where it was found, which is what makes the positives auditable.
Can I run it on a schedule?
Yes. Host rows are keyed on hostUserId, which is stable between runs, so
comparing two runs of the same area shows you which operators grew, shrank,
appeared or disappeared. Keep the place list and the size settings identical
between runs or the comparison will reflect your settings rather than the market.
How do I get only the big operators?
Set minPortfolioSize to 2 or more. Bear in mind that portfolio size is measured
inside the area you scanned, so widening the area usually raises it — a host with
three flats across a city looks like a one-listing host if you only scan one
district.
Why do some hosts have fewer listings than I expected?
Because the number is a floor. Either their remaining listings sit outside the
area scanned, or the run hit its maxListings ceiling before reaching them — the
row itself says which, in listingCountScope, scanStoppedAtListingLimit and
areasLeftCrowded. Airbnb publishes no total to compare against, so widening the
area and raising maxListings is the only way to raise the floor. The coverage
report's listingsWithoutPdp figure tells you how many listings were found but
never looked up, and listingsWithoutHostCard how many were looked up but
published no host at all.
Can I get a full year of prices or availability per listing? Not from this actor — it is built around host identity. Use the companion occupancy and price-tracking actors for that.
