# Crexi Scraper & API: Commercial Real Estate Listings (`muhammadafzal/crexi-commercial-real-estate-scraper`) Actor

Use this Crexi scraper to export commercial real estate listings for sale or lease with prices, cap rates, lease rates, and brokers for CRE investors.

- **URL**: https://apify.com/muhammadafzal/crexi-commercial-real-estate-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Real estate, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 crexi property 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 & API: Commercial Real Estate Listings

This Crexi scraper exports public commercial real estate listings for sale or for lease from Crexi.com into clean, structured data: asking prices and lease rates, addresses with coordinates, property types, square footage, lot size, cap rate where shown, available lease spaces, listing brokers, images, and the listing URL. Search by city, state, property type, and keyword, or paste Crexi search and listing URLs. It is built for CRE investors sourcing deals, brokers watching their market, and analysts who need Crexi listings in a spreadsheet, database, or AI agent.

> **Price:** $2.00 per 1,000 listings on the FREE tier ($1.60 on GOLD and above), plus a $0.005 start fee per run. Up to 500 listings per run on every Apify plan.

### What data does this Crexi scraper extract?

One dataset record per unique listing, with these fields:

| Field | What you get |
|---|---|
| `listingId`, `listingUrl`, `transactionType` | Crexi listing ID, public listing page, and `sale` or `lease` |
| `title`, `status` | Listing name and Crexi status (for example Active, On-Market, Auction, Under Contract) |
| `address`, `city`, `state`, `postalCode`, `county`, `fullAddress`, `latitude`, `longitude` | Property location and map coordinates |
| `propertyTypes` | Retail, Office, Industrial, Multifamily, Land, Self Storage, and the other Crexi types |
| `price`, `priceText`, `pricePerSquareFoot` | Asking price or starting bid for sale listings |
| `leaseRateText`, `leaseRateMinPerSfYear`, `leaseRateMaxPerSfYear` | Lease rate range in USD per square foot per year |
| `rentableSqftMin`, `rentableSqftMax`, `numberOfSpaces`, `spaces` | Available lease spaces with size, rate, and space type |
| `squareFeet`, `lotSize`, `capRate`, `yearBuilt` | Building size, lot size, cap rate, and year built when Crexi shows them publicly |
| `description`, `investmentHighlights`, `propertyDetails` | Marketing description, highlights, and the public property fact table |
| `brokerName`, `brokerCompany`, `brokerPhone`, `brokers` | Listing brokers and brokerage (phone only when shown publicly) |
| `imageUrls` | Up to 20 public listing photos |
| `activatedOn`, `updatedOn`, `offersDueOn`, `isInOpportunityZone` | Date listed, last update, offer or auction deadline, Opportunity Zone flag |
| `sourceSearchUrl`, `detailEnriched`, `scrapedAt`, `warnings` | Where the record came from and notes about it |

Crexi hides some property facts (for example year built or APN on certain listings) from visitors who are not signed in. The Actor leaves those out instead of guessing and notes how many were hidden in the record's `warnings`.

### Use cases for Crexi listings data

- **Deal sourcing:** pull every retail, industrial, or multifamily property for sale in a city or state and screen it by price, size, and cap rate.
- **Lease market research:** collect commercial real estate for lease with rate ranges and available space sizes to compare asking rents.
- **Monitoring:** schedule a daily run to catch new Crexi listings, updated listings, and auction or offer deadlines.
- **Broker and brokerage lists:** see which brokers and firms list which property types in a market.
- **Analytics and AI:** feed commercial real estate data into a BI dashboard, CRM, or AI agent through the API.

**When not to use it:** it does not return closed sales comps, ownership or tax records, tenant data, offering memorandums, rent rolls, or anything Crexi shows only to signed-in or paying users.

### How to scrape Crexi listings

1. Choose **For sale** or **For lease**.
2. Add cities (`"Austin, TX"`), states (`"TX"`), property types, and an optional keyword, or paste Crexi URLs.
3. Set **Maximum listings** and run. Download the results as JSON, CSV, Excel, or HTML, or read them through the API.

| Field | Type | Default | Notes |
|---|---|---|---|
| `mode` | `sale` or `lease` | `sale` | Listing type for the filter fields below |
| `cities` | list of strings | – | US cities written as `"City, ST"`, for example `"Austin, TX"` |
| `states` | list of strings | – | Two-letter state codes, for example `"TX"` |
| `propertyTypes` | list | – | For sale: Retail, Office, Industrial, Multifamily, Land, Hospitality, Mixed Use, Special Purpose, Self Storage, Business for Sale, Senior Living, Note/Loan, Mobile Home Park. For lease: Retail, Office, Industrial, Land, Special Purpose, Restaurant |
| `searchTerm` | string | – | Keyword such as `"car wash"` or `"medical office"` |
| `startUrls` | list of URLs | – | Crexi search URLs (`/properties?...`, `/lease/properties?...`) keep their filters; listing URLs (`/properties/<id>/<slug>`, `/lease/properties/<id>/<slug>`) return that listing |
| `maxResults` | integer 1–500 | 20 | Listings delivered and charged |
| `maxPages` | integer 1–50 | 10 | Search pages (up to 100 listings each) per search |
| `enrichDetails` | boolean | `true` | Adds description, highlights, property facts, lease spaces, brokers, and photos |
| `maxDetailPages` | integer 0–500 | 500 | Cap on listings that get detail data |

With no filters and no URLs, the Actor searches all Crexi listings of the selected type. Filters and URLs can be combined, and a listing found by two searches is delivered once.

Retail properties for sale in Austin:

```json
{ "mode": "sale", "cities": ["Austin, TX"], "propertyTypes": ["Retail"], "maxResults": 25 }
```

Office space for lease in Texas:

```json
{ "mode": "lease", "states": ["TX"], "propertyTypes": ["Office"], "maxResults": 50 }
```

Crexi URLs (a filtered search and a single lease listing):

```json
{
  "startUrls": [
    { "url": "https://www.crexi.com/properties?types%5B%5D=Self%20Storage&states%5B%5D=FL" },
    { "url": "https://www.crexi.com/lease/properties/38040/wisconsin-brookfield-lakes-corporate-center-iii" }
  ],
  "maxResults": 10
}
```

### Crexi API access from your code

This Actor is not an official Crexi API, but it gives you API access to public Crexi listings through the Apify API. Run it and get the listings back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/muhammadafzal~crexi-commercial-real-estate-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"sale","cities":["Phoenix, AZ"],"propertyTypes":["Multifamily"],"maxResults":10}'
```

The same input works with the Apify JavaScript and Python clients, schedules, webhooks, and the Apify MCP server, so an AI agent can ask for "5 industrial properties for lease in Dallas, TX" and know the cost in advance.

### Output example

A lease listing with details loaded (description shortened):

```json
{
  "listingId": "1286432",
  "listingUrl": "https://www.crexi.com/lease/properties/1286432/illinois-2472-w-foster-avenue-103",
  "sourceSearchUrl": "https://www.crexi.com/lease/properties?cities%5B%5D=Chicago%2C+IL&types%5B%5D=Retail",
  "transactionType": "lease",
  "title": "2472 W FOSTER Avenue 103",
  "status": "Active",
  "city": "Chicago",
  "state": "IL",
  "postalCode": "60625",
  "fullAddress": "2472 W FOSTER Avenue 103, Chicago, IL 60625",
  "latitude": 41.9761625,
  "longitude": -87.6918912,
  "propertyTypes": ["Retail"],
  "price": null,
  "priceText": "$19.05/SF/YR",
  "leaseRateText": "$19.05/SF/YR",
  "leaseRateMinPerSfYear": 19.05,
  "leaseRateMaxPerSfYear": 19.05,
  "rentableSqftMin": 1260,
  "rentableSqftMax": 1260,
  "numberOfSpaces": 1,
  "spaces": [{ "name": "103", "rentableSqFt": 1260, "rate": "$19.05/SF/YR", "rateType": "Per Year", "listingType": "Direct", "subtypes": [] }],
  "description": "Position your business for success in this spacious, light-filled retail or office suite...",
  "propertyDetails": { "Property Type": "Retail", "Stories": "4" },
  "brokerName": "Kieran Conlon",
  "brokerCompany": "Compass",
  "brokerPhone": null,
  "imageUrls": ["https://crexi.com/images/format=auto,width=3000,height=2000/lease-assets/1286432/c8bfba2d90944697b648f7eabfda0f20.JPG"],
  "activatedOn": "2026-10-23T09:41:00.308Z",
  "detailEnriched": true,
  "warnings": ["6 property detail field(s) are hidden by Crexi for anonymous visitors and were omitted."]
}
```

Sale listings fill `price`, `squareFeet`, `lotSize`, `capRate` (when shown), and `offersDueOn` instead of the lease fields. Each run also writes an `OUTPUT` record with the outcome (`DATA`, `EMPTY`, `BLOCKED`, `REJECTED`, or `FAILED`), delivered and charged counts, the stop reason, per-search totals, duplicates skipped, and warnings.

### Pricing

Pay per event. Platform usage is included in the event prices; you pay only for the events below.

| Event | FREE | BRONZE | SILVER | GOLD and above | When it is charged |
|---|---:|---:|---:|---:|---|
| Crexi Property Listing (`result-item`, primary) | $0.002 | $0.00195 | $0.0019 | $0.0016 | Once per listing delivered to the dataset |
| Actor Start (`apify-actor-start`) | $0.005 | $0.005 | $0.005 | $0.005 | Once per run per started GB of allocated memory (one event at the default 256 MB and at the 512 MB maximum) |

Listing discounts: BRONZE 2.5%, SILVER 5%, GOLD and above 20%.

Worked examples at default memory:

| Listings | FREE | GOLD |
|---:|---:|---:|
| 3 | $0.011 | $0.0098 |
| 20 | $0.045 | $0.037 |
| 100 | $0.205 | $0.165 |
| 500 | $1.005 | $0.805 |

Duplicates, rejected input, blocked runs, and empty searches are never charged as listings. You can set a maximum cost per run; the Actor stops cleanly when it is reached.

### Reliability, limits, and failure modes

- The Actor reads the same public listing data that the Crexi website loads in a browser, without signing in, and handles access automatically with bounded retries. No browser is launched, so runs are fast: in cloud tests, 3 listings with details took about 3–5 seconds and 120 listings about 20 seconds.
- Invalid input (an unknown property type for the selected mode, a malformed city, a non-Crexi URL) is rejected before any request, with a clear message and no listing charges.
- Runs that cannot reach Crexi end with a `BLOCKED` outcome and no listing charges. A valid search with no matches ends as `EMPTY`. Nothing is fabricated.
- Lease searches use a stable newest-first order so results do not reshuffle between pages, and every run deduplicates listings by listing ID.
- Limits per run: 500 listings, 50 search pages per search, 100 listings per page. Runs also stop at `maxResults`, your maximum cost, or the timeout, keeping the listings already delivered.
- Fields Crexi hides from anonymous visitors are omitted, so some records have fewer facts than the signed-in Crexi page.

### Legal and personal data

The Actor collects only public listing information that Crexi shows to anonymous visitors. It is not affiliated with or endorsed by Crexi. Broker names, brokerages, and phone numbers are business contact details published on listings; use them in line with applicable privacy, anti-spam, and telemarketing laws and with Crexi's terms. Do not use the data to republish listings wholesale.

### FAQ

**How can I scrape real estate data from Crexi?**
Enter a city, state, property type, or keyword (or paste a Crexi search URL), choose sale or lease, and run the Actor. It returns one structured record per listing that you can export to CSV, Excel, or JSON.

**Is there a Crexi API for listings?**
This Actor works as an unofficial Crexi API: you call it through the Apify API (example above) and get listings as JSON. It is not a Crexi product, and it covers public listing data only.

**Do I need a Crexi account?**
No. The Actor never signs in and returns only what Crexi shows to visitors who are not signed in.

**Does it include Crexi auction listings?**
Yes. Auction listings come through with status `Auction`, the starting bid in `price`/`priceText`, and the deadline in `offersDueOn` when Crexi lists one.

**Can it scrape commercial real estate for lease?**
Yes. Choose **For lease** (or paste a `/lease/properties` URL) to get commercial properties for lease with lease rate ranges, available spaces, and their sizes.

### Support

Open an issue on the Actor page with the run ID and input if a listing field looks wrong or a run fails.

Last verified: 2026-11-04

# Actor input Schema

## `mode` (type: `string`):

Search properties for sale or for lease. Applies to the filter fields below; Crexi URLs keep their own type.

## `cities` (type: `array`):

One or more US cities written as "City, ST", for example "Austin, TX".

## `states` (type: `array`):

Two-letter US state codes, for example "TX" or "FL".

## `propertyTypes` (type: `array`):

Crexi property types. For sale: Retail, Office, Industrial, Multifamily, Land, Hospitality, Mixed Use, Special Purpose, Self Storage, Business for Sale, Senior Living, Note/Loan, Mobile Home Park. For lease: Retail, Office, Industrial, Land, Special Purpose, Restaurant.

## `searchTerm` (type: `string`):

Optional keyword matched against listing names, descriptions, and addresses, for example "car wash" or "medical office".

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

Optional public Crexi search URLs (https://www.crexi.com/properties?... or https://www.crexi.com/lease/properties?...) with their filters, or listing URLs (https://www.crexi.com/properties/<id>/<slug>). When only URLs are given, the filter fields above are not used.

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

Maximum number of listings to deliver (and charge) in this run.

## `maxPages` (type: `integer`):

Maximum Crexi search result pages (up to 100 listings each) read per search.

## `enrichDetails` (type: `boolean`):

Load each listing's public detail data: full description, investment highlights, property facts (year built, lot size, cap rate where shown), lease spaces, brokers, and gallery images.

## `maxDetailPages` (type: `integer`):

Cap on listings that receive detail data when details are on; listings beyond the cap keep search-card fields only. The default covers every delivered listing.

## Actor input object example

```json
{
  "mode": "sale",
  "cities": [
    "Austin, TX"
  ],
  "maxResults": 3,
  "maxPages": 10,
  "enrichDetails": true,
  "maxDetailPages": 500
}
```

# Actor output Schema

## `listings` (type: `string`):

Delivered Crexi listings in the default dataset.

## `summary` (type: `string`):

OUTPUT record with status, counts, access route, and 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 = {
    "cities": [
        "Austin, TX"
    ],
    "maxResults": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/crexi-commercial-real-estate-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 = {
    "cities": ["Austin, TX"],
    "maxResults": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/crexi-commercial-real-estate-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 '{
  "cities": [
    "Austin, TX"
  ],
  "maxResults": 3
}' |
apify call muhammadafzal/crexi-commercial-real-estate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/crexi-commercial-real-estate-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/1lD7VYGRwIA9zfYB3/builds/zVXXnfRjHft9hzzIB/openapi.json
