# CRE Market Data API - Cap Rates, NAV, Forecasts (`nabeelbaghoor/cre-market-data-api`) Actor

Commercial real estate research across 90 datasets: market cap rates, quality grades and rent growth, REIT net asset values and fundamentals, forecast scenarios by release, CMBS and CRE CLO deals and tranches, property sale comps, retail centre and tenant analytics, executive pay and total returns.

- **URL**: https://apify.com/nabeelbaghoor/cre-market-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Real estate, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 reference row returneds

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

## CRE Market Data API - Cap Rates, NAV, Forecasts

Read commercial real estate research data straight into a dataset: market cap rates and quality grades, REIT net asset values and fundamentals, forecast scenarios with the release they were published in, securitised debt deals and tranches, property sale comps, retail centre and tenant analytics, executive pay and total return track records, across the United States, Europe, Canada and Asia Pacific.

### What this actor does

- **Ninety datasets, one query language.** Companies, sectors, markets, forecasts, macro series, CMBS and CRE CLO and ABS deals, high yield funds, sale comps, retail analytics, executive compensation, model portfolios and total returns. Pick one per run.
- **Filters checked before the request, not after it.** Each endpoint accepts its own subset of filters. A filter that does not apply to your dataset is dropped and named in the log rather than sent, because a silently ignored filter returns a result set that looks filtered and is not.
- **The region trap, handled.** The provider uses two region vocabularies across its own API: most endpoints take `usa`, `eur`, `can`, `apac` or `other`, a handful take `na` and `eu`. Pick either spelling; this actor translates it into the one your dataset accepts, and stops the run with the accepted list when no translation exists.
- **Reference datasets built in.** Company, market, sector, scenario, grade, weight, attribute, property and debt entity IDs, plus the provider's own data dictionary. Every filter on every other dataset takes IDs, and these are where you get them.
- **A free preview dataset.** The examples dataset is published without authentication. Run it first to confirm the network path works before spending a credential on it.
- **Paging done for you.** Skip and limit paging runs until a short page arrives, so a full dataset is one run rather than one run per thousand rows. A run never asks for more rows than it is allowed to keep.
- **The long tail reachable.** Several hundred filters exist across these endpoints. The ones worth a form field have one; everything else goes in as `name=value` lines, checked against the same catalogue.
- **Pay per result.** You are charged for rows carrying a real record. Filter combinations that return nothing are free.

### Bring your own key

This actor calls the provider with **your own client ID and client secret**, taken from the client credentials page of your account. They are exchanged once for an access token, which is cached for its full lifetime exactly as the provider asks rather than re-fetched per request, and refreshed a minute early so a long run never lands on the far side of an expiry. You can also paste an access token you already hold.

Paste the secret into the input or set it as the `DATA_API_KEY` secret. Nothing runs on anyone else's credentials, and a run without them ends cleanly with an explanation rather than failing.

### The User-Agent header nobody mentions until it bites

The provider requires a `User-Agent` header on **both** the token request and every data request, and refuses requests that arrive without one as access denied. Node's own fetch sends no User-Agent by default, which is exactly why this shows up in the provider's troubleshooting notes.

That matters here because a missing User-Agent and a wrong client secret produce the **same** `access_denied` answer. This actor always sends one, so if you see that error the cause is the credential rather than the header.

### Two region vocabularies, one API

`/companies/summaries` takes `usa`, `eur`, `can`, `apac` or `other`. `/companies/nav_operating_breakouts` takes `na` and `eu`. They sit next to each other in the same API and the parameter has the same name in both.

Sending `usa` to the second one does not return North American data. It returns a validation error about `region`, which is a parameter you set correctly, in a spelling that endpoint does not use. There is nothing in the message to tell you that. This actor carries the accepted list for every dataset, translates between the two spellings where they mean the same thing, refuses a Canadian request to an `na`/`eu` endpoint rather than quietly widening it to North America, and says in the log when it translated something.

### Column names are the provider's, on purpose

There are several thousand data series across these endpoints, and the provider publishes a data dictionary describing them, which is one of the datasets in this actor. Renaming columns here would break every join anyone writes against that documentation, so rows come through under the provider's own names. This actor adds four columns of its own, written last: `recordType`, `dataset`, `datasetGroup` and `requestedRegion`.

### Example output

```json
{
  "date": "2026-09-01",
  "comp_id": 10,
  "sector_id": 9,
  "symbol": "BXP",
  "sector": "Office",
  "currency_symbol": "USD",
  "price": 67.06,
  "recordType": "record",
  "dataset": "examples",
  "datasetGroup": "Preview",
  "requestedRegion": "na"
}
```

### FAQ

#### What commercial real estate data does this actor return?

Market and sector analytics including cap rates, rent and NOI growth, occupancy, quality grades and market rankings. Listed company fundamentals including net asset value, NAV breakouts by operating line, balance sheet, geography and property type, earnings, surprises, tenant exposure and transaction activity. Forecast scenarios by market, sector and release. Macroeconomic and fair value model series. Securitised debt: CMBS, CRE CLO and ABS deals, tranches and participants, issuance volumes and high yield funds. Property sale comps with prices and cap rates. Retail property, tenant and geography analytics. Executive compensation. Total returns and model portfolio weights.

#### Do I need an account?

Yes, for everything except the examples dataset, which the provider publishes without authentication. Datasets are entitled separately, so a credential that works on one family can be refused on another; the actor reports that as an entitlement answer rather than as a bad key.

#### How do I find the IDs the filters take?

Run a reference dataset first. Company IDs returns IDs, names, tickers and coverage flags. Market IDs returns markets by region, level and zoom. Sector, scenario, grade, weight and attribute IDs do the same for their own dimensions, and property IDs looks a property up by name or address. The data dictionary dataset explains what any returned column means.

#### Why did my forecast run stop before calling the API?

Because forecast datasets require a market level and a scenario, and market sector summaries require a market level and a zoom. Without them the provider returns a validation error naming a field you were never shown a form for, so this actor checks first and names the missing input instead.

#### Can I get historical cap rates by market?

Yes. Use the historical market sector summaries dataset with a market level and zoom, a date range and the market IDs you want. Each row carries the date it belongs to, so the series comes back ready to plot.

#### How do I compare a forecast against the one it replaced?

Use the historical forecast scenarios dataset and filter on release IDs. Each row carries the release it was published in, which is what makes the comparison meaningful: a projection without its vintage cannot be checked against what actually happened.

#### What if the filter I need has no input field?

Put it in extra filters as a `name=value` line. Around six hundred filters exist across these endpoints - CMBS deals alone accepts about forty - so the ones worth a form field have one and the rest go in as lines. A name your chosen dataset does not accept is reported in the log and not sent.

#### How many rows can one run collect?

As many as you set. Paging runs on skip and limit up to the provider's ceiling of 1000 records per request, and continues until a short page arrives or your row cap is reached. Set a start offset to resume a large dataset where a previous run stopped.

### Keyword map

CRE data API, commercial real estate data API, cap rate data API, REIT data API, NAV data API, net asset value REIT, CRE forecast API, rent growth forecast data, NOI forecast API, market grades commercial real estate, CMBS data API, CRE CLO data, ABS deal data API, commercial mortgage data, sales comps API, property transaction data API, retail analytics API, shopping centre data, retail vacancy data API, executive compensation data API, REIT total returns, NAREIT index data, model portfolio data, real estate research API, institutional CRE data

# Actor input Schema

## `dataset` (type: `string`):

Which of the provider's datasets to read. Ninety of them share one query language, and each accepts its own subset of the filters below; filters that do not apply to your choice are dropped before the request and named in the log. Start with the preview dataset, which needs no credential, or with a reference dataset to find the IDs the others filter on.

## `region` (type: `string`):

Which regional dataset to read. The provider uses two vocabularies across its own API: most endpoints take usa, eur, can, apac or other, a few take na and eu instead. Pick either spelling and it is translated into the one your dataset accepts; a region a dataset does not serve stops the run with the accepted list rather than failing at the provider.

## `compIds` (type: `array`):

One company ID per line. Look them up with the company IDs reference dataset, which also returns tickers and coverage flags.

## `symbols` (type: `array`):

One ticker per line, as listed on the company's local exchange. An alternative to company IDs on the endpoints that accept both.

## `sectorIds` (type: `array`):

One sector ID per line. Look them up with the sector IDs reference dataset.

## `marketIds` (type: `array`):

One market ID per line. Look them up with the market IDs reference dataset. The market commentary dataset reads the first of these from the request path rather than as a filter.

## `marketLevelId` (type: `string`):

Which geographic level the market IDs are at. Required by the market sector and forecast datasets, which will not run without it.

## `marketZoomId` (type: `string`):

Which zoom level the market summaries are aggregated to. Required by the current and historical market sector summaries.

## `scenarioIds` (type: `array`):

One forecast scenario ID per line. Required by the forecast datasets. Look them up with the scenario IDs reference dataset.

## `releaseIds` (type: `array`):

One forecast release ID per line, to pin a historical forecast run to the vintage it was published in.

## `dealIds` (type: `array`):

One securitisation deal ID per line, for the CMBS, CRE CLO and ABS datasets.

## `entityIds` (type: `array`):

One debt entity ID per line: servicers, trustees, underwriters and sellers. Look them up with the debt entity IDs reference dataset.

## `propertyIds` (type: `array`):

One property ID per line, for the sales comps and retail property datasets. Look them up with the property IDs reference dataset by name or address.

## `tenantIds` (type: `array`):

One retail tenant ID per line.

## `ownerIds` (type: `array`):

One retail property owner ID per line.

## `geographyIds` (type: `array`):

One retail geography ID per line.

## `gradeIds` (type: `array`):

One market grade ID per line, for the retail cap rate datasets. Look them up with the grade IDs reference dataset.

## `columns` (type: `array`):

One column name per line to return instead of the full record. Leave empty for everything the dataset publishes. The data dictionary dataset lists what each column means.

## `orderBy` (type: `array`):

One column name per line to sort on, on the datasets that accept sorting.

## `sortOrder` (type: `string`):

Ascending or descending, applied to the order by columns.

## `dateStart` (type: `string`):

Earliest date to return, as YYYY-MM-DD, on the historical datasets.

## `dateEnd` (type: `string`):

Latest date to return, as YYYY-MM-DD, on the historical datasets.

## `yearStart` (type: `string`):

Earliest year to return on the periodical datasets, which report by year rather than by date.

## `yearEnd` (type: `string`):

Latest year to return on the periodical datasets.

## `years` (type: `array`):

One year per line, for the datasets that filter on a list of years rather than a range.

## `quarter` (type: `string`):

Which quarter to return: 1 to 4, or 5 for the full year summary. Quarterly data is not published for every European dataset.

## `period` (type: `string`):

The reporting frequency a historical dataset is read at, in the provider's own spelling, for example annual or quarterly.

## `level` (type: `string`):

The aggregation level required by the older market summary datasets.

## `module` (type: `string`):

Which retail module a request is about: properties, tenants or geographies. Required by several retail datasets.

## `moduleId` (type: `string`):

The ID of the property, tenant or geography the retail module request is about.

## `eventType` (type: `string`):

Whether to return openings or closings, on the retail openings and closings datasets.

## `sectorRetail` (type: `string`):

Which retail sector the retail property datasets are read for. Required by those datasets.

## `classificationType` (type: `string`):

Which classification the retail concentration dataset groups by.

## `product` (type: `string`):

Which retail analytics product the request reads from, where the dataset serves more than one.

## `keyword` (type: `string`):

Free text search, on the debt datasets that accept one.

## `extraFilters` (type: `array`):

One name=value line per extra filter, for the several hundred filters this API publishes that have no form field here. Repeat a name to send it more than once. A name the chosen dataset does not accept is reported in the log and not sent, rather than silently ignored by the provider.

## `version` (type: `string`):

Overrides the endpoint version. Leave empty: each dataset already points at its own version and the ceiling differs per endpoint, so a number above it is rejected.

## `pageSize` (type: `integer`):

How many records to ask for per request, up to the provider's ceiling of 1000. A run never asks for more rows than it is allowed to keep.

## `startAt` (type: `integer`):

Skip this many records before collecting. Use it to resume a large dataset where a previous run stopped.

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

Stop after this many rows.

## `requestsPerMinute` (type: `integer`):

How fast to call the provider. Lower this if your plan's rate limit is being hit.

## `clientId` (type: `string`):

Your own client ID, from the client credentials page of your account. Stored encrypted and never written into the dataset.

## `clientSecret` (type: `string`):

Your own client secret. Exchanged once for an access token, which is then cached for its full lifetime as the provider asks. Can also be supplied as the DATA\_API\_KEY environment secret.

## `accessToken` (type: `string`):

An access token you already hold, used instead of exchanging a client ID and secret. Useful when your own systems already mint one. It cannot be refreshed, so a run longer than its lifetime needs the client credentials instead.

## `baseUrl` (type: `string`):

Overrides the host the API is called on. Leave empty unless the provider has given you a different one.

## `tokenUrl` (type: `string`):

Overrides the login host the client ID and secret are exchanged at. Leave empty unless the provider has given you a different one.

## Actor input object example

```json
{
  "dataset": "market-sector-summaries",
  "region": "",
  "sortOrder": "",
  "pageSize": 500,
  "startAt": 0,
  "maxResults": 100,
  "requestsPerMinute": 120
}
```

# Actor output Schema

## `records` (type: `string`):

One row per record, alongside the dataset that produced it.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/cre-market-data-api").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/cre-market-data-api").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 '{}' |
apify call nabeelbaghoor/cre-market-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/cre-market-data-api"
        }
    }
}
```

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/THld2bdA2PiPL9hIh/builds/sIP0Yef1k4BfXGwdm/openapi.json
