# Short-Term Rental Revenue Analyzer — AirDNA Alternative (`khadinakbar/airdna-alternative`) Actor

Analyze supplied short-term rental observations for occupancy, ADR, RevPAR, revenue, and comparable ranges. Add a property scenario to estimate income, expenses, cap rate, and break-even occupancy from your assumptions.

- **URL**: https://apify.com/khadinakbar/airdna-alternative.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Real estate, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $500.00 / 1,000 str market report generateds

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

## Short-Term Rental Revenue Analyzer — AirDNA Alternative

Analyze supplied short-term rental observations for occupancy, ADR, RevPAR, revenue, and comparable ranges. Add a property scenario to estimate income, expenses, cap rate, and break-even occupancy from your assumptions. For rental analysts, the dataset returns one market calculation record with an optional property-scenario projection.

### Workflow: put the results to work

Provide authorized monthly observations and the market context you want to analyze. Check occupancy and rate distributions before adding a property scenario, then test the income and expense assumptions together. The Actor calculates from supplied data; it does not provide an address-based market database.

### Best fit

Use it when a host, property manager, analyst, developer, or real-estate investor has legitimate listing-month data from a PMS, channel manager, owner portfolio, licensed data provider, or authorized export and needs reproducible Airbnb/VRBO market analysis without a monthly analytics subscription.

### When not to use

Choose a licensed market-data product when your starting point is only a public availability calendar, one current listing-price scrape, or an address that still needs historical discovery. Use independent validation for every underwriting decision.

### Supported STR workflows

- **Market performance:** weighted occupancy, ADR, RevPAR, gross revenue, available nights, and booked nights.
- **Comp-set analysis:** ADR quartiles, median listing occupancy, monthly trends, distinct supply, and low-coverage flags.
- **Rental revenue calculator:** project annual booked nights, stays, nightly revenue, cleaning-fee revenue, gross revenue, expenses, and net operating income.
- **Investment scenario:** calculate cap rate and break-even occupancy when purchase price and operating costs are supplied.
- **Automation and export:** consume the report from an Apify dataset, API, webhook, schedule, Make, Zapier, Google Sheets, or an agent workflow.

The market report and property projection share an auditable calculation chain. Every source label, formula, assumption, and data boundary is returned with the result.

#### Workflow: from PMS export to an investment scenario

A property manager starts with actual listing-month data exported from a PMS. They remove guest information, map nights and revenue into `monthlyObservations`, and run the Actor. The resulting market report first shows whether the selected comp set has enough coverage; next, the optional property scenario turns the observed occupancy and ADR into annual revenue and NOI. The manager can then compare assumptions, export the dataset to a spreadsheet, or schedule the same saved input after each authorized monthly export.

### What the Actor calculates

For each supplied listing-month observation, provide:

- `month` in `YYYY-MM`
- `listingId` — an internal or source ID; it need not be an Airbnb ID
- `availableNights` — nights available for sale, excluding booked nights
- `bookedNights` — actual booked nights from an authorized record
- `grossRevenue` — actual gross revenue for those booked nights
- `currency` — one currency for the report

The Actor aggregates them with transparent formulas:

```text
occupancyRate   = bookedNights / (bookedNights + availableNights)
averageDailyRate = grossRevenue / bookedNights
revPar          = grossRevenue / (bookedNights + availableNights)
```

`monthlyMetrics` also includes comp-set ADR percentiles and a coverage label. A coverage label only measures the number of distinct listings supplied; it is not a forecast accuracy or market-representativeness score.

Add `propertyScenario` to run a target-property scenario. Unless you supply `occupancyRate` or `nightlyRate`, the projection uses the comp set's weighted occupancy and ADR. The scenario then applies annual availability, average stay, cleaning fees, variable expenses, fixed costs, and purchase price. It is transparent underwriting math—not a promise that a property will achieve those results.

### Example input

```json
{
    "marketName": "Austin, TX — 2-bedroom entire homes",
    "currency": "USD",
    "minimumListingsPerMonth": 5,
    "propertyScenario": {
        "name": "South Congress candidate",
        "availableNightsPerYear": 300,
        "averageStayNights": 3,
        "cleaningFeePerStay": 90,
        "variableExpenseRate": 0.2,
        "annualFixedCosts": 12000,
        "purchasePrice": 500000
    },
    "monthlyObservations": [
        {
            "month": "2026-06",
            "listingId": "portfolio-142",
            "availableNights": 9,
            "bookedNights": 21,
            "grossRevenue": 4410,
            "currency": "USD",
            "bedrooms": 2,
            "source": "pms_export"
        },
        {
            "month": "2026-06",
            "listingId": "portfolio-211",
            "availableNights": 12,
            "bookedNights": 18,
            "grossRevenue": 3600,
            "currency": "USD",
            "bedrooms": 2,
            "source": "owner_authorized_comp_set"
        }
    ]
}
```

### Output

One validated `marketReport` dataset item is written per successful run.

| Field                                         | Meaning                                                                                                   |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `occupancyRate`, `averageDailyRate`, `revPar` | Weighted metrics calculated only from supplied actual observations                                        |
| `monthlyMetrics`                              | Metrics, ADR percentiles, and coverage by month                                                           |
| `provenance`                                  | Source labels, formulas, and the explicit data boundary                                                   |
| `confidence`                                  | Months that fall below your minimum-listing threshold                                                     |
| `propertyProjection`                          | Annual booked nights, stays, revenue, expenses, NOI, cap rate, break-even occupancy, and assumption basis |
| `generatedAt`                                 | ISO timestamp when the report was calculated                                                              |

Example persisted dataset item (values are illustrative):

```json
{
    "marketName": "Austin, TX — 2-bedroom entire homes",
    "currency": "USD",
    "periodStart": "2026-06",
    "periodEnd": "2026-06",
    "distinctListings": 2,
    "observationCount": 2,
    "bookedNights": 39,
    "availableNights": 21,
    "grossRevenue": 8010,
    "occupancyRate": 0.65,
    "averageDailyRate": 205.38,
    "revPar": 133.5,
    "monthlyMetrics": [{ "month": "2026-06", "coverage": "low_coverage" }],
    "propertyProjection": {
        "name": "South Congress candidate",
        "projectedGrossRevenue": 45840.65,
        "projectedNetOperatingIncome": 24672.52,
        "projectedCapRate": 0.0493,
        "basis": {
            "occupancyRate": "market_observation_weighted",
            "nightlyRate": "market_observation_weighted_adr"
        }
    },
    "provenance": { "method": "authorized_observation_aggregation" },
    "confidence": { "overall": "mixed_coverage", "monthsBelowThreshold": ["2026-06"] },
    "generatedAt": "ISO timestamp"
}
```

When input needs correction, inspect the `OUTPUT` and `RUN_SUMMARY` key-value records. The Actor uses `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED`, and `CONFIG_ERROR` outcome semantics; this workflow normally returns `COMPLETE` or an actionable `INVALID_INPUT`.

### API example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/airdna-alternative').call({
    marketName: 'Austin, TX — 2-bedroom entire homes',
    currency: 'USD',
    monthlyObservations: [
        {
            month: '2026-06',
            listingId: 'portfolio-142',
            availableNights: 9,
            bookedNights: 21,
            grossRevenue: 4410,
            currency: 'USD',
            bedrooms: 2,
            source: 'pms_export',
        },
    ],
    propertyScenario: {
        name: 'South Congress candidate',
        availableNightsPerYear: 300,
        averageStayNights: 3,
        cleaningFeePerStay: 90,
        variableExpenseRate: 0.2,
        annualFixedCosts: 12000,
        purchasePrice: 500000,
    },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

### Agent prompt card

An AI agent can use the following prompt, then branch on `OUTPUT.outcome`: stop and correct the input on `INVALID_INPUT`, and read the single dataset item on `COMPLETE`.

> Analyze these authorized short-term-rental monthly observations for a named comp set. Keep source labels, calculate occupancy, ADR, RevPAR, revenue, and coverage, then project annual revenue and NOI for my target property. Flag low-coverage months and never infer bookings from calendar blocks.

### Where the observation data can come from

No third-party API is required to use this release. Suitable inputs include owner/PMS exports, channel-manager reports, authorized client portfolios, and licensed datasets that already distinguish actual booked nights from available nights.

For automatic address lookup, market discovery, historical Airbnb estimates, or provider-selected comparables, a licensed STR data API is required. That optional integration is not enabled in this release because it would require the caller's provider key, separate provider charges, schema verification, and provider-specific acceptance testing. Keeping it outside the critical path makes the base Actor deterministic and removes an upstream outage from ordinary runs.

### Data use and privacy

Submit only data you are authorized to analyze and keep guest names, email addresses, booking references, iCalendar URLs, cookies, and API keys outside the input. Listing IDs can be internal IDs. The workflow runs without third-party credentials, rental-platform browsing, or booking-calendar scraping.

### Builder's note

I designed this Actor after seeing calendar-based occupancy tools combine reservations with owner blocks. My goal was to keep every consequential number traceable to actual booked nights, available nights, revenue, and explicit property assumptions. That design choice shaped the source-labelled output, formula disclosure, coverage flags, and the separation between observed market metrics and scenario overrides. Each report's `generatedAt`, period, and source labels make its input freshness visible.

### How this bounded workflow compares with AirDNA

| Decision dimension       | This Actor                                                                                          | AirDNA boundary                                                                            |
| ------------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Scope coverage           | Calculates comp performance and explicit property scenarios from supplied observations              | Adds proprietary market discovery, forecasts, dynamic pricing, and dashboard workflows     |
| Billing model            | Pay per event for each persisted report, plus platform usage                                        | Limited free access and subscription products; check the current pricing page              |
| Effective efficiency     | One tested API call produces one calculation report with formulas, assumptions, and outcome records | No authorized same-job timing and export test was performed                                |
| Input friction           | Requires actual booked nights, available nights, and revenue that you are authorized to analyze     | Can start from an address because the product supplies comparable and historical estimates |
| Output contract          | Declared JSON schema with market/month metrics, projection economics, provenance, and confidence    | Provides dashboard/report workflows; no current API response was tested here               |
| Freshness and provenance | Returns input periods, source labels, formulas, generation time, and coverage limits                | Uses its own historical and forecast modelling; per-result provenance was not tested here  |

The right choice depends on the starting point. Use this Actor after obtaining authorized observations and when transparent automation matters. Use AirDNA when the missing value is proprietary data acquisition, address-first discovery, forecasts, or its broader suite.

### Scope and AirDNA boundary

AirDNA can be the better choice when you need its proprietary data collection, wide market coverage, historical estimates, forecasts, interactive dashboard, dynamic pricing, or address-first comparable discovery. This Actor is useful when your workflow already has authorized observations and needs transparent, automatable market calculations, property scenario modelling, and a structured export.

Use the projection as a scenario rather than an appraisal, promised return, tax opinion, or legal assessment. Use only data you are authorized to access and analyze, follow applicable laws and source terms, and validate local STR rules, permit eligibility, taxes, insurance, financing, platform fees, cleaning economics, seasonality, and property-specific demand before making an investment decision.

AirDNA is a trademark of its respective owner. This Actor is independent and not affiliated with, endorsed by, or sponsored by AirDNA.

### Pricing and run costs

This Actor uses **Pay per event plus Apify platform usage**. The [Pricing tab](https://apify.com/khadinakbar/airdna-alternative/pricing) lists the current event rates and billing terms.

| Event | Billing unit | When it applies |
|---|---|---|
| `apify-actor-start` | Actor Start | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `market-report-generated` | STR market report generated | One validated STR market report and optional property projection calculated from authorized observations and persisted to the dataset. |

Run cost combines the charged events and Apify platform usage. Review the run charge limit and requested result count before starting.

### Connect an AI agent

Use the [Apify MCP configurator](https://mcp.apify.com) to choose an available client connection. Inspect this Actor’s current input schema and required credentials before running it.

# Actor input Schema

## `marketName` (type: `string`):

Name the market, comp set, or portfolio being summarized, for example 'Austin, TX — 2-bedroom entire homes'. This label is returned unchanged and does not trigger a geographic search. Use a stable name when comparing repeated reports; it is not an Airbnb destination URL.

## `monthlyObservations` (type: `array`):

Monthly actual or authorized comp-set observations. Each item needs month, listingId, availableNights, bookedNights, grossRevenue, and currency; optional bedrooms and source are retained as provenance. Enter JSON with month '2026-06', listingId 'host-unit-1', availableNights 30, bookedNights 21, grossRevenue 4830, currency 'USD'. Do not use blocked calendar nights as booked nights and do not include guest names, calendar URLs, or credentials.

## `targetBedrooms` (type: `number`):

Optionally limit the comp set to one bedroom count, for example 2. The default analyzes all valid observations; rows without a bedroom count are excluded only when this filter is set. This is a comp-set filter, not a minimum-bedroom search on a booking site.

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

Three-letter currency required for every included observation, for example USD. The Actor rejects mixed currencies instead of converting them with an undisclosed exchange rate. Defaults to USD and is not a request to fetch live foreign-exchange data.

## `minimumListingsPerMonth` (type: `integer`):

Minimum distinct listings needed before a monthly market metric is labelled sufficient, for example 5. The default is 5; lower samples are still calculated but marked low\_coverage. This threshold changes report confidence only, not the input rows used in arithmetic.

## `propertyScenario` (type: `object`):

Optionally calculate a transparent Rentalizer-style annual property scenario from the supplied comp set. By default it uses the comp set's weighted occupancy and ADR. Override either value to test a conservative or aggressive case. This is deterministic scenario math, not an address lookup, appraisal, or demand forecast.

## Actor input object example

```json
{
  "marketName": "Austin, TX — 2-bedroom entire homes",
  "monthlyObservations": [
    {
      "month": "2026-06",
      "listingId": "portfolio-142",
      "availableNights": 9,
      "bookedNights": 21,
      "grossRevenue": 4410,
      "currency": "USD",
      "bedrooms": 2,
      "source": "pms_export"
    }
  ],
  "currency": "USD",
  "minimumListingsPerMonth": 5,
  "propertyScenario": {
    "name": "Target property",
    "availableNightsPerYear": 365,
    "averageStayNights": 3,
    "cleaningFeePerStay": 90,
    "variableExpenseRate": 0.2,
    "annualFixedCosts": 12000,
    "purchasePrice": 500000
  }
}
```

# Actor output Schema

## `marketReport` (type: `string`):

One source-labelled STR market report with aggregate and monthly occupancy, ADR, RevPAR, revenue, coverage, provenance, and an optional Rentalizer-style property scenario.

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

Terminal diagnostics including the named outcome, input validation state, report count, warnings, and billable event counts.

## `output` (type: `string`):

Compact terminal outcome for an agent or workflow branch, with report count and actionable warnings.

# 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 = {
    "marketName": "Austin, TX — 2-bedroom entire homes",
    "monthlyObservations": [
        {
            "month": "2026-06",
            "listingId": "portfolio-142",
            "availableNights": 9,
            "bookedNights": 21,
            "grossRevenue": 4410,
            "currency": "USD",
            "bedrooms": 2,
            "source": "pms_export"
        }
    ],
    "currency": "USD",
    "propertyScenario": {
        "name": "Target property",
        "availableNightsPerYear": 365,
        "averageStayNights": 3,
        "cleaningFeePerStay": 90,
        "variableExpenseRate": 0.2,
        "annualFixedCosts": 12000,
        "purchasePrice": 500000
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/airdna-alternative").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 = {
    "marketName": "Austin, TX — 2-bedroom entire homes",
    "monthlyObservations": [{
            "month": "2026-06",
            "listingId": "portfolio-142",
            "availableNights": 9,
            "bookedNights": 21,
            "grossRevenue": 4410,
            "currency": "USD",
            "bedrooms": 2,
            "source": "pms_export",
        }],
    "currency": "USD",
    "propertyScenario": {
        "name": "Target property",
        "availableNightsPerYear": 365,
        "averageStayNights": 3,
        "cleaningFeePerStay": 90,
        "variableExpenseRate": 0.2,
        "annualFixedCosts": 12000,
        "purchasePrice": 500000,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/airdna-alternative").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 '{
  "marketName": "Austin, TX — 2-bedroom entire homes",
  "monthlyObservations": [
    {
      "month": "2026-06",
      "listingId": "portfolio-142",
      "availableNights": 9,
      "bookedNights": 21,
      "grossRevenue": 4410,
      "currency": "USD",
      "bedrooms": 2,
      "source": "pms_export"
    }
  ],
  "currency": "USD",
  "propertyScenario": {
    "name": "Target property",
    "availableNightsPerYear": 365,
    "averageStayNights": 3,
    "cleaningFeePerStay": 90,
    "variableExpenseRate": 0.2,
    "annualFixedCosts": 12000,
    "purchasePrice": 500000
  }
}' |
apify call khadinakbar/airdna-alternative --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/airdna-alternative"
        }
    }
}

```

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/IimNQDhgbDvbpYG0U/builds/IVCURIGmBOmNq8ubM/openapi.json
