# Crexi Scraper 🏢 Cap Rate, NOI, OM Status & Broker Emails (`dz_omar/crexi-scraper`) Actor

Scrape Crexi commercial real estate listings from any search link, city or listing link. Get price, type, size, address and brokers, plus optional details: real cap rate, NOI, year built, tenancy, offering-memorandum status, broker of record, phones and brokerage emails.

- **URL**: https://apify.com/dz_omar/crexi-scraper.md
- **Developed by:** [FlowExtract API](https://apify.com/dz_omar) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**[Crexi Scraper](https://apify.com/dz_omar/crexi-scraper?fpr=smcx63)** collects **Crexi commercial real estate listings** from any search link or listing link you copy from the website. Add the optional details and each listing also comes back with its **real cap rate, NOI, year built and tenancy** (the Crexi listing page shows these as \*\*\*\*\*), its **offering-memorandum status**, the **broker of record**, **brokerage phones and social profiles** and **brokerage emails**.

Built for **commercial real estate investors and analysts**, **brokers and lead-generation teams**, **proptech and data teams** and **researchers** who need current Crexi stock in a spreadsheet or an API without copying listings by hand.

### What does Crexi Scraper do?

- **Any Crexi search link** — set your filters on the website (property type, price, cap rate, occupancy, place, for sale or for lease) and paste the address. Every filter in the link is applied, and so is its map area when the link has one and no place (the area the website shows in a typical window). A link carrying a filter the scraper cannot apply is refused with a message instead of silently widened, so you never pay for unrelated listings.
- **Single listings** — paste a listing link in the same box.
- **Many links at once** — a listing found by more than one link is delivered once.
- **Only Crexi links** — the form rejects a link from any other website before the run starts.
- **Large searches** — one Crexi search shows at most 100,000 listings; bigger searches are split up automatically so you can collect more.
- **A limit per link** — set how many listings to take from each link, or 0 for every listing the link matches.
- **Optional listing details** (a checkbox) — Crexi's full listing record, brokers and every photo, plus a summary with the numbers investors look for, filled in where the listing page shows \*\*\*\*\*.
- **Optional brokerage emails** (a checkbox) — business emails read from each brokerage's own public website, limited to the listing's brokers and the firm's general address.
- **Runs that finish cleanly** — a listing that is inactive or needs a Crexi login is still delivered, marked, and the run ends successfully with a plain summary of what was delivered, what was left out and what was charged.

#### What data can you extract from Crexi?

Every record starts with Crexi's own listing data, exactly as Crexi returns it: id, name, address and map position, price, price per sq ft, property type and sub-type, building and lot size, status and dates, brokers and brokerages, auction fields, photo counts and links. The scraper adds one `_meta` block (source, listing link, a few table-friendly copies of key values).

With **details** switched on, each listing also carries:

| Part | What it holds |
|---|---|
| `detail` | Crexi's full listing record as returned: facts table, investment highlights and marketing text, sale condition, location details, flags |
| `brokerDetails` | Crexi's broker records as returned: name, brokerage, brokerage website and address, licences, licence phone |
| `media` | Every photo as Crexi returns it, in several sizes, with video entries where present |
| `_enrichment` | What the scraper adds: cap rate, NOI, price per sq ft, year built, investment type, tenancy and tenant credit as real numbers; which fields stay hidden and why; offering-memorandum status and any OM link the seller posted; broker of record; phones, brokerage socials and emails; plain-text description; a per-listing status |

#### Why use Crexi Scraper on Apify?

Running it on Apify gives you **API access**, **scheduling**, **monitoring**, **integrations** (Make, Zapier, n8n, Google Sheets, webhooks) and **proxy rotation** without managing any infrastructure. Export results as JSON, CSV or Excel.

### How to scrape Crexi listings

1. Open [Crexi Scraper](https://apify.com/dz_omar/crexi-scraper?fpr=smcx63) in Apify Console.
2. On crexi.com, run your search with the filters you want and copy the page address. Paste it into **Crexi search links**. A single listing's address works too, and you can paste several links.
3. Set **Maximum listings per link** (start small, for example `50`).
4. Switch on **Add full listing details** to get the cap rate, offering-memorandum status and contacts, and **Find brokerage emails** if you want emails.
5. Click **Start**, then download the results as JSON, CSV or Excel, or fetch them over the API.

### How much does it cost to scrape Crexi?

Pay only for what you get. Prices per event:

| Event | Price | When |
|---|---|---|
| Run start | $0.002 | once per run |
| Listing | $0.0005 | each listing delivered |
| Listing details | $0.0004 | add-on for each listing whose details were read |
| Brokerage email | $0.01 | add-on for each distinct email address found in the run |

- **1,000 listings** cost about **$0.50** plus the run start.
- **1,000 listings with details** cost about **$0.90** plus the run start.
- An email address is **charged once per run**, even when it appears on many of that brokerage's listings; it is shown on every listing that carries it. Example: 26 listings from one brokerage, details and emails on, cost about **$0.035** in total.
- Details are never charged for a listing that is inactive, needs a Crexi login or could not be read.
- Each link has its own maximum; set a **maximum cost per run** in Apify Console to bound the whole run, and the scraper stops at that limit.

### Input and output examples

#### Input

```json
{
  "startUrls": [
    { "url": "https://www.crexi.com/search?searchType=Sales&propertyAttributes.type_tree_Land=Hunting%252FRecreational&mapZoom=4&mapCenter=62.96,-152.48&address_value=Alaska%252C%2520USA" }
  ],
  "maxItemsPerLink": 50,
  "includeDetails": true,
  "findBrokerageEmails": true
}
```

Add as many links as you like. A single listing works the same way: `{ "url": "https://www.crexi.com/properties/2644096/…" }`.

#### Output (an investment listing, trimmed)

```json
{
  "id": "sales-2644096",
  "documentType": "Sales",
  "propertyPrice": { "total": 4870369, "perSqft": 549 },
  "propertyAttributes": { "type": "Office, Retail", "buildingSqft": 9215 },
  "_enrichment": {
    "status": "ok",
    "cap_rate_percent": 6.5,
    "noi": 316574,
    "price_per_sqft": 549,
    "year_built": 2024,
    "investment_type": "Net Lease",
    "tenancy_type": "Single",
    "tenant_credit_profile": "Credit Rated",
    "has_om": true,
    "om_access": "AuthRequired",
    "masked_fields": ["Occupancy", "Lease Term", "Remaining Term"],
    "resolved_from_search": ["Cap Rate", "NOI", "Year Built", "Price per SqFt", "Tenancy"],
    "brokerage_name": "Matthews",
    "brokerage_website": "https://www.matthews.com"
  }
}
```

`masked_fields` lists what Crexi still hides from visitors who are not logged in; `resolved_from_search` lists what the scraper filled in for you.

### Actor recommendations

More real estate scrapers from FlowExtract API are in the [Apify Store](https://apify.com/dz_omar?fpr=smcx63).

### FAQ

#### Do I need a Crexi account, cookies or an API key?

No. Public listings need only the links above.

#### Do I get direct phone numbers for each broker?

You get the phone numbers Crexi lists publicly: the broker of record's office number when shown and the brokerage's licence phone. Direct numbers of individual brokers, offering-memorandum and flyer files, tax history, property records and demographics are shown by Crexi only to logged-in users and are not included. Offering-memorandum **status** and any link the seller posted in the listing text are included.

#### Why does a listing come back without details?

Three expected reasons, all marked in `_enrichment.status` and `_enrichment.reason`, none of them an error of the run: the listing is inactive on Crexi, it is shown only to logged-in users, or Crexi no longer has it. You are not charged the details event for it.

#### Why are some values still hidden?

Crexi hides occupancy, lease terms, rent steps, APN and net rentable area from visitors who are not logged in. They are listed in `masked_fields`.

#### How many listings can I collect?

Up to the per-link limit you set, or every listing a link matches with 0. One Crexi search shows at most 100,000 listings; larger searches are split up automatically.

#### Are the emails verified?

No. They are business addresses published on the brokerage's own website, read on a best-effort basis; many sites publish none.

#### Can I use it for sale and lease listings?

Yes. The link carries its own type: a for-sale search gives sale listings, a for-lease search gives lease listings.

#### Is it legal to scrape Crexi?

The scraper processes publicly available data. You are responsible for using it in line with Crexi's terms, applicable data-protection law and your own obligations.

#### Where can I get support?

See below, or open an issue on the Actor's Issues tab.

### Support

- 🌐 **Website:** [flowextractapi.com](https://flowextractapi.com)
- 📧 **Email:** <flowextractapi@outlook.com>
- 💬 **GitHub:** [FlowExtractAPI](https://github.com/FlowExtractAPI)
- 💼 **LinkedIn:** [flowextract-api](https://www.linkedin.com/in/flowextract-api/)
- 🐦 **X (Twitter):** [@FlowExtractAPI](https://x.com/FlowExtractAPI)
- 📱 **Facebook:** [flowextractapi](https://www.facebook.com/flowextractapi)
- 🎵 **TikTok:** [@flowextractapi](https://www.tiktok.com/@flowextractapi)

### Legal & compliance

- **Public data only** — processes publicly available data.
- **Rate limiting** — respects source-service limits and terms of use.
- **Data protection** — no storage of personal information or unauthorized data collection.
- **Commercial use** — suitable for business intelligence and research.
- No affiliation with or endorsement by Crexi is implied.

# Actor input Schema

## `startUrls` (type: `array`):

Paste links from <b>crexi.com</b>, one per line. Links from any other website are rejected. <ul><li><b>Search results</b> — set your filters on the website and copy the address, e.g. <code>https://www.crexi.com/search?searchType=Sales\&propertyAttributes.type_tree_Retail=\&address_value=Texas</code> or <code>https://www.crexi.com/properties?types%5B%5D=Retail\&states%5B%5D=TX</code>. Works for sale and lease searches. Every filter in the link is applied, including the map area the link carries when it has no place in it (as the website shows it in a typical window). A link with a filter the scraper can't apply is refused instead of widened, so you never pay for unrelated listings.</li><li><b>One listing</b> — e.g. <code>https://www.crexi.com/properties/2644096/sienna-plantation-animal-hospital</code>.</li></ul>You can add as many links as you like; a listing found by several links is delivered once.

## `maxItemsPerLink` (type: `integer`):

Stops collecting from each link after this many listings. <b>0</b> collects every listing the link matches (Crexi shows at most 100,000 for one search; larger ones are split up automatically). The whole run is also capped by the <i>maximum cost per run</i> you set in Apify Console. Not used for single listing links.

## `includeDetails` (type: `boolean`):

Adds Crexi's full listing record, brokers, all photos and a summary: cap rate, NOI, price per sq ft, year built and tenancy as real numbers (the listing page shows these as \*\*\*\*\*), offering-memorandum status and any OM link the seller posted, broker of record, brokerage phones and websites. Not included, because Crexi shows them only to logged-in users: direct broker phone numbers, OM and flyer files, tax history, property records and demographics.

## `findBrokerageEmails` (type: `boolean`):

Reads each brokerage's own public website (home page and up to two contact or about pages, honouring robots.txt) for business emails and lists the ones that belong to the listing's brokers or are the firm's general address. Best effort: many sites show none, and addresses are not verified. Turns on the listing details above. Charged once for each distinct email address found in the run: a brokerage's address that appears on many of its listings is delivered on every one of them and charged once.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.crexi.com/search?searchType=Sales&propertyAttributes.type_tree_Land=Hunting%252FRecreational&mapZoom=4&mapCenter=62.96,-152.48&address_value=Alaska%252C%2520USA"
    }
  ],
  "maxItemsPerLink": 100,
  "includeDetails": false,
  "findBrokerageEmails": false
}
```

# Actor output Schema

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

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://www.crexi.com/search?searchType=Sales&propertyAttributes.type_tree_Land=Hunting%252FRecreational&mapZoom=4&mapCenter=62.96,-152.48&address_value=Alaska%252C%2520USA"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dz_omar/crexi-scraper").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 = { "startUrls": [{ "url": "https://www.crexi.com/search?searchType=Sales&propertyAttributes.type_tree_Land=Hunting%252FRecreational&mapZoom=4&mapCenter=62.96,-152.48&address_value=Alaska%252C%2520USA" }] }

# Run the Actor and wait for it to finish
run = client.actor("dz_omar/crexi-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.crexi.com/search?searchType=Sales&propertyAttributes.type_tree_Land=Hunting%252FRecreational&mapZoom=4&mapCenter=62.96,-152.48&address_value=Alaska%252C%2520USA"
    }
  ]
}' |
apify call dz_omar/crexi-scraper --silent --output-dataset

```

## MCP server setup

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

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/e9l1EXoJbcco7ychX/builds/H9kdKLiUL0g6MClER/openapi.json
