# Crexi.com - US Commercial Real Estate Listings (`swerve/crexi-scraper`) Actor

Scrape US commercial real estate for sale on Crexi: asking price, $/sq ft, size, type, tenants, address + lat/lng, opportunity zone, auction status, photos, broker contacts. Filter by state, city, zip, type, price, cap rate, size, lease type, tenant.

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

## Pricing

from $5.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Crexi Scraper - US Commercial Real Estate Listings

Extract every commercial property for sale on [Crexi](https://www.crexi.com), the second-largest US commercial real estate marketplace (~245,000 active listings). One run returns asking price, size, price per sq ft, property type, tenants, exact address with coordinates, opportunity-zone flag, auction status, photos, and the listing brokers with phone and license - as JSON, CSV, Excel, or through the API.

No Crexi login is needed. Leave every filter empty to sweep the whole US market; the actor shards large searches automatically so nothing is skipped.

### What you get

| Field | Example |
|---|---|
| `name`, `headline` | "Iroquois Manor Shopping Center", "Grocery Store Anchored" |
| `propertyTypes`, `subtypes` | \["Retail"], \["Strip Center"] |
| `askingPrice`, `pricePerSqft`, `squareFootage`, `lotSizeAcres` | 2000000, 14.85, 134699, 12.4 |
| `status`, `isAuction`, `offersDueOn` | "Auction", true, "2026-09-30T16:00:00Z" |
| `address`, `city`, `county`, `state`, `zip`, `latitude`, `longitude` | "5300 S 3rd St", "Louisville", "Jefferson County", "KY", "40214", 38.171, -85.768 |
| `tenants`, `investmentType`, `leaseType`, `tenancy` | \["Kroger"], "Net Lease", "NNN", "Multi" |
| `brokerageName`, `brokers[]` | "Mid-America Real Estate", \[{ name, title, brokerage, phone, licenseNumber, licenseState, profileUrl }] |
| `description`, `investmentHighlights[]`, `images[]` | full text, bullets, full-size photo URLs |
| `isInOpportunityZone`, `hasOfferingMemorandum`, `hasVideo` | true / false |
| `activatedOn`, `updatedOn` | ISO timestamps |

See the **Output** tab for the complete field list with descriptions.

### Input

| Field | What it does |
|---|---|
| `states`, `cities`, `zips`, `counties` | Geography. Combine freely, e.g. `states: ["TX"], cities: ["Austin"]`. |
| `propertyTypes` | Retail, Office, Industrial, Multifamily, Land, Hospitality, Mixed Use, Self Storage, Mobile Home Park, Senior Living, Special Purpose, Business for Sale, Note/Loan. |
| `minPrice` / `maxPrice`, `includeUnpriced` | Asking-price band. About 13% of listings have no published price. |
| `minCapRate` / `maxCapRate`, `minOccupancy` | Financial filters (applied by Crexi even though the values themselves are hidden from anonymous visitors - see below). |
| `minSqft` / `maxSqft`, `minPricePerSqft` / `maxPricePerSqft` | Size and unit-price bands. |
| `tenants`, `tenancy`, `leaseTypes`, `opportunityZoneOnly` | Investment filters, e.g. `tenants: ["Dollar General"]`, `leaseTypes: ["NNN"]`. |
| `listingStatus` | `active` (on-market + auctions) or `underContract`. |
| `updatedSince` | e.g. `2026-09-01` - only listings the broker touched since then. Ideal for daily delta runs. |
| `sortBy`, `sortDescending` | Crexi relevance, recently updated, recently listed, price, cap rate. |
| `maxItems` | Optional cost cap. Blank = everything that matches. |
| `enrichDetails` | Default on. Fetches the detail page, photo gallery and broker roster for every listing (3 extra requests each). Turn off for a fast price/location sweep. |
| `proxyConfig` | Apify datacenter proxy by default - Crexi's API accepts it, so runs are cheap. |

#### Example: every NNN retail deal in Texas over $1M

```json
{
  "states": ["TX"],
  "propertyTypes": ["Retail"],
  "leaseTypes": ["NNN"],
  "minPrice": 1000000
}
```

#### Example: daily feed of new listings nationwide (no enrichment, fast)

```json
{
  "updatedSince": "2026-09-01",
  "sortBy": "activatedOn",
  "enrichDetails": false
}
```

### How it works

The actor talks to Crexi's own listing search API, the same one the website uses, and pages through results 60 at a time. Crexi caps any single search at 1,500 results, so when a query is larger the actor splits it by state, then property type, then asking-price band (with a separate pass for unpriced listings), then building size, and merges the shards with de-duplication by listing id. Results are pushed to the dataset as they arrive, so a stopped run still keeps everything collected so far.

With `enrichDetails` on, each listing gets three more calls: the detail record (description, highlights, subtypes, tenants, lot size, year built, sale condition, broker of record), the photo gallery, and the broker roster with license data and brokerage phone. Failed detail fetches are retried on a fresh proxy session; if a detail still fails, the row ships with the search-card fields and `enriched: false` rather than being dropped.

### Limits and honest notes

- **Financials are hidden for anonymous visitors.** Crexi shows cap rate, NOI, occupancy, year built, lease term and similar numbers only to logged-in users. The filters still work server-side (you can ask for cap rate 6-8%), but the values come back `null` with `financialsMasked: true`. Everything else - price, size, location, tenants, brokers, photos, text - is public and fully extracted.
- **For-sale only.** Crexi's for-lease marketplace is rendered server-side without a public API; it is not covered by this actor.
- **Portfolios** list several addresses. `address`/`city`/... describe the first one; `locationCount` tells you how many there are.
- Listings that Crexi hides from anonymous traffic (private / vault-only) are not returned by the search API and therefore not by this actor.

### Use cases

- **Deal sourcing**: pull every NNN, multifamily or industrial listing in your target states daily; diff against yesterday to catch new inventory and price changes.
- **Broker prospecting**: brokers, brokerages, license numbers and phone numbers for every active listing in a market.
- **Market research and comps**: asking-price and $/sq ft distributions by county, type and size band.
- **Feeding your CRM, spreadsheet or model**: export CSV/Excel or read the dataset via the Apify API.

### Export formats

JSON, CSV, Excel (XLSX), XML, HTML table, or RSS - from the Console or via the Apify API (`/v2/datasets/{datasetId}/items?format=csv`). Schedule the actor and connect a webhook or Zapier/Make integration to push new listings anywhere.

### Frequently asked questions

**Does this scrape LoopNet too?** No, Crexi only. LoopNet and Crexi have largely separate inventories, so many teams run both.

**How many listings are there?** Around 245,000 for sale across the US at any time; Texas alone is ~33,000, Land ~120,000.

**Is it legal?** The actor reads publicly available listing data with no login, at a polite request rate. You are responsible for how you use the output; check Crexi's terms for your use case.

**Can I get cap rates?** Only if Crexi publishes them to the public - currently they are shown to logged-in users only. Contact us if you need an authenticated mode.

# Actor input Schema

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

Two-letter US state codes, e.g. \["TX", "FL"]. Leave empty for all 50 states + DC.

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

City names, e.g. \["Austin", "Dallas"]. Combine with States to avoid same-name cities in other states.

## `zips` (type: `array`):

ZIP codes, e.g. \["78701", "78702"].

## `counties` (type: `array`):

County names as Crexi spells them, e.g. \["Travis County", "Harris County"].

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

Leave empty for all types.

## `maxItems` (type: `integer`):

Optional cap on results. Leave blank to scrape ALL matching listings (recommended); set a number only to limit cost.

## `minPrice` (type: `integer`):

e.g. 1000000 for $1M+. Unpriced listings are excluded when a price filter is set.

## `maxPrice` (type: `integer`):

e.g. 5000000 for up to $5M.

## `includeUnpriced` (type: `boolean`):

Crexi lets brokers list without an asking price (~13% of listings). Uncheck to skip them. Ignored (treated as false) when Min/Max price is set.

## `minCapRate` (type: `number`):

e.g. 6 for 6%+. Only listings that publish a cap rate match.

## `maxCapRate` (type: `number`):

e.g. 8.

## `minSqft` (type: `integer`):

e.g. 10000.

## `maxSqft` (type: `integer`):

e.g. 50000.

## `minPricePerSqft` (type: `number`):

e.g. 100.

## `maxPricePerSqft` (type: `number`):

e.g. 300.

## `minOccupancy` (type: `number`):

e.g. 90 for 90%+ occupied. Only listings that publish occupancy match.

## `tenants` (type: `array`):

Match listings with these tenants, e.g. \["Starbucks", "Dollar General", "Walgreens"].

## `tenancy` (type: `string`):

Single-tenant or multi-tenant properties only.

## `leaseTypes` (type: `array`):

Investment lease structure of the property's tenants (for-sale listings only; Crexi does not expose its for-lease marketplace publicly).

## `opportunityZoneOnly` (type: `boolean`):

Only properties inside a federal Opportunity Zone.

## `listingStatus` (type: `string`):

Active = on-market + live auctions (Crexi's default view). Under contract = deals pending close.

## `updatedSince` (type: `string`):

Only listings updated on/after this date, e.g. 2026-09-01. Handy for daily delta runs.

## `sortBy` (type: `string`):

Order in which Crexi returns listings. Matters mainly when you set Max listings.

## `sortDescending` (type: `boolean`):

Checked = newest / highest first.

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

Adds 3 extra requests per listing: description, investment highlights, subtypes, tenants, lot size, year built, sale condition, all photos, and every broker with phone + license. Slower (roughly 1 second per listing at our concurrency) and adds proxy traffic; uncheck for a fast price/location-only sweep. Note: Crexi hides cap rate, NOI, occupancy and similar financials from anonymous visitors; those come back null with financialsMasked=true.

## `proxyConfig` (type: `object`):

Crexi's API accepts Apify datacenter proxies, so the default is cheap. Switch to residential only if you see blocks.

## Actor input object example

```json
{
  "states": [
    "TX"
  ],
  "cities": [
    "Austin"
  ],
  "includeUnpriced": true,
  "tenancy": "any",
  "opportunityZoneOnly": false,
  "listingStatus": "active",
  "sortBy": "rank",
  "sortDescending": true,
  "enrichDetails": true,
  "proxyConfig": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped listings (JSON). Append ?format=csv for CSV.

# 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 = {
    "states": [
        "TX"
    ],
    "cities": [
        "Austin"
    ],
    "proxyConfig": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("swerve/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 = {
    "states": ["TX"],
    "cities": ["Austin"],
    "proxyConfig": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("swerve/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 '{
  "states": [
    "TX"
  ],
  "cities": [
    "Austin"
  ],
  "proxyConfig": {
    "useApifyProxy": true
  }
}' |
apify call swerve/crexi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,swerve/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/A7qPorGPWXishNMGK/builds/ERPlS5rt3mFFRu8jx/openapi.json
