# Crexi \[$1.9💰] Scraper: Properties, Brokers & Instant Database (`memo23/crexi-ppe`) Actor

\[Only $1.9💰] Crexi scraper for commercial real estate — sale & lease listings, property records with tax/ownership history, demographics and agent profiles nationwide. Plus an instant database of 214,000+ US brokers with brokerage, license & deal stats — phone on request. Pure API-first. JSON/CSV.

- **URL**: https://apify.com/memo23/crexi-ppe.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Real estate, AI, Agents
- **Stats:** 3 total users, 2 monthly users, 16.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.90 / 1,000 records

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 — Properties + Instant Broker Database

### How It Works

<p align="center"><img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-crexi-ppe.png" alt="How the Crexi Scraper works" width="800" /></p>

Scrape Crexi commercial real estate the way you need it: sale & lease listings, property records with tax/ownership history, demographics and agent profiles nationwide — or skip scraping entirely with an instant database of **214,000+ US brokers** (brokerage, license, deal stats, and phone on request).

> Nobody else on Apify sells Crexi broker contacts — every other Crexi scraper on the Store returns properties only. This one gives you the people behind the listings, plus the full property side too.

### Why Use This Scraper?

- ✅ **214,000+ commercial real estate brokers**, instant delivery — filter by State, City, or Brokerage, no scraping needed
- ✅ **Full property scraping too** — sale & lease listings, property records, tax/ownership history, demographics, agent profiles
- ✅ **Phone numbers on request** — a logged-in broker lookup is wired in (no cookies required); opt in and only pay for the numbers you actually get
- ✅ **Rich per-broker data** — brokerage name, license number & state, active/closed deal counts, profile URL
- ✅ **DB-first live scraping** — a find-a-broker URL is served instantly if we already have that state; otherwise it scrapes live and caches for next time
- ✅ **Pure API-first** — no browser for the vast majority of requests, Camoufox fallback only when needed

### Overview

This actor serves two audiences: **CRE lead-gen teams, recruiters, and market researchers** who want broker contacts without scraping, and **investors, analysts, and proptech teams** who want Crexi property data.

Instant Database mode returns a flat broker row per broker, straight from the store — no requests to Crexi at all. Live-scrape mode (property / broker / agent-profile / find-a-broker URLs) returns property listings, broker contact blocks, and agent profile data, reading Crexi's own APIs directly.

**On contacts, honestly:** every broker record has brokerage, license, and deal-count data. **Phone** numbers are present for a growing subset — currently in the tens of thousands and climbing as more properties get scraped (each scraped listing unlocks the phone for its broker via an authenticated lookup). Phone is a metered field: set `dbIncludePhone` (Instant Database) or `includePhoneNumbers` (live-scrape) to receive real numbers — off by default, so you're never billed for a field you didn't ask for, and only billed for records that actually have one. **Email** stays masked (`user@crexi.com`) for essentially all records — Crexi only reveals real email addresses to *paid* Crexi accounts, which is a separate, bigger lift than the phone unlock.

### Supported Inputs

#### Instant Database filters (no URL needed)

| Field | Example | Notes |
|---|---|---|
| `dbState` | `TX` | 2-letter state code |
| `dbCity` | `Austin` | optional, narrows within the state |
| `dbBrokerage` | `CBRE` | brokerage name contains, optional |
| `dbHasPhone` / `dbHasEmail` | `true` | filter to records that already have that field |
| `dbIncludePhone` | `true` | **opt in to receive real phone numbers** — additional charge per record with a phone, off by default |
| `instantDatabase` | `true` | force database mode (auto-on if any filter above is set) |

#### Live-scrape URL types

| URL type | Example |
|---|---|
| Sale/lease search | `https://www.crexi.com/properties?placeIds%5B%5D=...&types%5B%5D=Land` |
| Single property | `https://www.crexi.com/properties/{id}/{slug}` |
| Group / group property | `https://www.crexi.com/groups/{groupId}[/properties/{id}]` |
| Broker directory | `https://www.crexi.com/resources/find-a-broker/{State}` |
| Agent profile | `https://www.crexi.com/profile/{slug}` |
| Property records (parcel, tax/sale/ownership history) | `https://www.crexi.com/property-records/{parcelKey}/{40-hex-recordId}` |

#### Copy-pasteable startUrls

```json
{
  "startUrls": [
    "https://www.crexi.com/properties",
    "https://www.crexi.com/resources/find-a-broker/TX"
  ],
  "includeBrokerDetails": true,
  "includePhoneNumbers": true
}
````

#### Unsupported inputs

- ❌ Content behind a Crexi login (beyond the actor's own broker-phone unlock, which uses our own account, not yours)
- ❌ Non-crexi.com domains
- ❌ Real email addresses — Crexi requires a paid account for that; this actor's account is not paid

### Use Cases

| Audience | Use case |
|---|---|
| **CRE lead-gen teams** | Pull thousands of broker contacts instantly by state, city, or brokerage |
| **Recruiters** | Build brokerage rosters filtered by state, city, or firm |
| **Investors / analysts** | Track sale & lease listings, pricing, and property records nationwide |
| **Proptech / CRM** | Enrich a pipeline with verified broker + brokerage + license data |
| **Market researchers** | Bulk-export Crexi property and broker data for analysis |

1. **Choose a mode** — Instant Database (State/City/Brokerage filters) for broker contacts, or live scrape (property / broker / find-a-broker URL) for listings and fresh broker data
2. **Instant Database path** — the actor queries our pre-collected store and returns matching brokers in seconds
3. **DB-first on find-a-broker URLs** — if we already have that state, it's served instantly; otherwise the actor scrapes live and caches the result for next time
4. **Live-scrape path** — the actor calls Crexi's own APIs directly (search, property detail, broker lookup); a logged-in account is used automatically so broker phone numbers unlock without you supplying cookies
5. **Output** — one row per broker (database) or per property / broker / agent profile (live scrape), JSON or CSV

### Input Configuration

#### Input fields

| Field | Type | Required | Notes |
|---|---|---|---|
| `dbState` / `dbCity` / `dbBrokerage` | `string` | no | Instant Database filters |
| `dbHasPhone` / `dbHasEmail` | `boolean` | no | Filter to records that already have that field, default `false` |
| `dbIncludePhone` | `boolean` | no | Opt in to real phone numbers in Instant Database mode — additional charge per record with a phone, default `false` |
| `instantDatabase` | `boolean` | no | Force DB mode, default `false` |
| `maxItems` | `integer` | no | Cap on Instant Database rows, default `200` |
| `forceFresh` | `boolean` | no | Skip DB-first, always live-scrape find-a-broker URLs, default `false` |
| `startUrls` | `array<string>` | no (or DB filters) | Crexi URLs to scrape |
| `moreResults` | `boolean` | no | Fan out by price range to exhaust >1,500-result searches, default `false` |
| `includeListingDetails` | `boolean` | no | Fetch full detail per search result, default `false` |
| `includeBrokerDetails` | `boolean` | no | Fetch broker contact block per result, default `false` |
| `includePhoneNumbers` | `boolean` | no | Opt in to real phone numbers on live-scraped brokers (requires `includeBrokerDetails`) — additional charge per record with a phone, default `false` |
| `includePropertyRecord` | `boolean` | no | Fetch parcel/property-record data, default `false` |
| `includePropertyHistory` | `boolean` | no | Fetch property update history, default `false` |
| `includeTaxHistory` | `boolean` | no | Fetch tax history, default `false` |
| `includeDemographics` | `boolean` | no | Fetch population/income/household data, default `false` |
| `includeMoreMedia` | `boolean` | no | Fetch additional media, default `false` |
| `maxConcurrency` / `minConcurrency` | `integer` | no | Default `50` / `1` |
| `maxRequestRetries` | `integer` | no | Default `50` |
| `cookies` | `array` | no | Your own Crexi login cookies (EditThisCookie export) — optional, the actor logs in with its own account by default |
| `proxy` | `object` | no | Apify Residential recommended |

#### Common scenarios

**1. Instant Database — every Texas broker with a real phone number**

```json
{
  "dbState": "TX",
  "dbHasPhone": true,
  "dbIncludePhone": true,
  "maxItems": 500
}
```

**2. Instant Database — brokers at a specific brokerage in Austin, no phone (cheaper)**

```json
{
  "dbState": "TX",
  "dbCity": "Austin",
  "dbBrokerage": "CBRE",
  "maxItems": 100
}
```

**3. Live scrape — sale listings with broker phone unlocks**

```json
{
  "startUrls": ["https://www.crexi.com/properties"],
  "includeListingDetails": true,
  "includeBrokerDetails": true,
  "includePhoneNumbers": true
}
```

### Output Overview

- **Database broker** (Instant Database mode) — a flat broker row served from our store: name, contact (phone/email), brokerage, license, deal stats, profile URL.
- **Live-scraped property / broker / agent profile** — full Crexi detail from the site's own API response.

### Output Samples

**Instant Database broker — default (no `dbIncludePhone`, phone masked):**

```jsonc
{
  "id": "2536950",
  "first_name": "Jesse",
  "last_name": "Molinar",
  "slug": "jessemoli",
  "phone": "🔒 Set includePhoneNumbers to true to unlock phone (additional charge per record with a phone)",
  "email": "user@crexi.com",
  "number_of_assets": 16,
  "brokerage_name": "D.E. The Home Boss Group LLC",
  "license_number": "0832459",
  "license_state": "TX",
  "profile_url": "https://www.crexi.com/profile/jessemoli"
}
```

**Instant Database broker — with `dbIncludePhone: true` (phone unlocked, additional charge):**

```jsonc
{
  "id": "2536950",
  "first_name": "Jesse",
  "last_name": "Molinar",
  "slug": "jessemoli",
  "phone": "432.349.6024",
  "email": "user@crexi.com",
  "number_of_assets": 16,
  "brokerage_name": "D.E. The Home Boss Group LLC",
  "license_number": "0832459",
  "license_state": "TX",
  "profile_url": "https://www.crexi.com/profile/jessemoli"
}
```

### Key Output Fields

| Group | Fields |
|---|---|
| **Identity & contact** | id, first\_name, last\_name, slug, phone, email, photo\_url, profile\_url |
| **Performance** | number\_of\_assets |
| **Brokerage** | brokerage\_name, brokerage\_website, brokerage\_city, brokerage\_state |
| **License** | license\_number, license\_state, broker\_title |
| **Metadata** | source\_location, last\_scraped\_at |

### FAQ

#### What's the difference between Instant Database mode and live scraping?

Instant Database mode (`dbState` + optional filters) serves brokers straight from our pre-collected store — no requests to Crexi, results in seconds. Live scraping (`startUrls`) hits Crexi directly for current listings, broker contacts, or profiles.

#### Do all brokers have a phone number?

Not yet — phone coverage is a growing subset of the 214,000+ database, populated by an authenticated per-property lookup. Set `dbHasPhone: true` to only receive records that already have one, or run a live scrape with `includeBrokerDetails: true` to unlock phone on fresh properties as you scrape them. Either way, you also need to opt in (see below) to actually receive the number.

#### Why don't I see real phone numbers by default?

Phone is a metered field, billed separately from the base record — set `dbIncludePhone: true` (Instant Database) or `includePhoneNumbers: true` (live-scrape, alongside `includeBrokerDetails`) to receive real numbers. It's off by default so nobody's billed for a field they didn't ask for, and you're only ever charged for records that actually have a phone to unlock — never for a miss.

#### Can I get real broker email addresses?

Not currently. Crexi only reveals a broker's real email to Crexi accounts on a paid plan; without one, Crexi itself returns a placeholder (`user@crexi.com`). This actor doesn't have a paid Crexi account today.

#### Do I need my own Crexi cookies?

No. The actor logs in with its own Crexi account automatically to unlock broker phone numbers on live scrapes. You can still supply your own `cookies` if you want requests made under your own account instead.

#### Do I need a URL for Instant Database mode?

No — just set `dbState` (and optionally city/brokerage) and leave `startUrls` empty.

#### What happens if I request a find-a-broker URL for a state we already have?

It's served instantly from the database instead of hitting Crexi — set `forceFresh: true` to always scrape live instead.

#### Can it scrape properties too, not just brokers?

Yes. Live-scrape mode handles sale/lease search results, property detail pages, property records (parcel/tax/ownership history), and agent profiles.

#### Can I scrape content behind a login?

No. The actor only accesses publicly available Crexi pages, plus the broker-contact unlock available to its own logged-in account — never paid features or content behind a customer's own login.

#### JSON or CSV?

Both — export from your Apify dataset in whichever format you need.

### Support

Found a bug or want a field added? Open an issue on the actor's **Issues** tab and we'll take a look.

### Additional Services

Need a custom CRE data feed (bulk state exports, scheduled monitoring, a webhook/Sheets/DB push, or a tailored schema)? Reach out — custom scraping and data-pipeline work is available.

### Explore More Scrapers

- [Crexi Scraper (flat monthly rate)](https://apify.com/memo23/apify-crexi) — same property/broker scraping, no Instant Database, billed as a flat monthly rental instead of pay-per-event
- [Redfin Scraper — Listings + Agent Database](https://apify.com/memo23/apify-redfin-cheerio-ppe) — US residential agents, email + phone
- [Realtor.com Scraper — 200K+ Agent Database](https://apify.com/memo23/realtor-search-cheerio)
- [Zillow Agents & Leads Scraper](https://apify.com/memo23/zillow-agents-leads-scraper-ppe)
- [PropertyFinder Scraper — Instant Broker Database](https://apify.com/memo23/apify-propertyfinder-cheerio-ppe) — UAE & Qatar

See the [full memo23 actor catalog →](https://apify.com/memo23)

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Crexi, Inc. or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available Crexi pages and broker-directory data, plus broker-contact lookups made available to a standard (non-paid) Crexi account — no paid-tier features or content behind a customer's own login wall. Users are responsible for ensuring their use complies with Crexi's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organization.

### SEO Keywords

crexi scraper, crexi.com scraper, crexi api, crexi broker scraper, crexi agent scraper, commercial real estate broker data, commercial real estate leads, cre lead generation, cre broker contacts, crexi property scraper, crexi find a broker, brokerage roster scraper, commercial real estate api, cre market research data, crexi json csv export, real estate agent emails, real estate broker phone numbers, commercial property listings scraper, cre data extraction, us commercial real estate data

# Actor input Schema

## `instantDatabase` (type: `boolean`):

Serve brokers from the database instead of live-scraping. Auto-enabled if you set State, City or Brokerage below.

## `dbState` (type: `string`):

e.g. TX, CA, FL. Filters the broker database to this state.

## `dbCity` (type: `string`):

e.g. Austin. Optional, narrows within the state.

## `dbBrokerage` (type: `string`):

e.g. CBRE, Marcus & Millichap. Optional.

## `dbHasEmail` (type: `boolean`):

Real (non-placeholder) emails require an authenticated ingestion pass and are currently a small share of the database — most brokers have phone, not email.

## `dbHasPhone` (type: `boolean`):

Phone is the more commonly available contact field in the database.

## `dbIncludePhone` (type: `boolean`):

Phone is a real, hard-won field — unlocked via an authenticated per-property lookup. Off by default so you're never billed for a field you didn't ask for; check this to receive real phone numbers, billed per record that actually has one.

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

Maximum number of database records to return.

## `forceFresh` (type: `boolean`):

When a Start URL is a find-a-broker directory page and we already have that state/city in the database, we serve it instantly from there instead of scraping. Check this to always scrape live instead.

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

URLs to start with. Supported patterns:

- Search/listing: https://www.crexi.com/properties?...
- Single property: https://www.crexi.com/properties/{id}/...
- Group overview / group property: https://www.crexi.com/groups/{groupId}\[/properties/{id}]
- Agent search: https://www.crexi.com/find-a-broker?...
- Agent profile: https://www.crexi.com/profile/...
- Property records (parcel data, tax / sale / ownership history): https://www.crexi.com/property-records/{parcelKey}/{40-hex-recordId}

## `moreResults` (type: `boolean`):

If checked, the scraper will try to exhaust all possible results that it can get. Also it will take longer to finish.

## `includeListingDetails` (type: `boolean`):

Set to true if you want to include listing details of each search result.

## `includeBrokerDetails` (type: `boolean`):

Set to true if you want to include broker/contact details of each search result.

## `includePhoneNumbers` (type: `boolean`):

Only applies when Include broker/contact details is on. Phone is a real, hard-won field — unlocked via an authenticated per-property lookup. Off by default so you're never billed for a field you didn't ask for; check this to receive real phone numbers, billed per record that actually has one.

## `includePropertyRecord` (type: `boolean`):

Set to true if you want to include property record of each search result.

## `includePropertyHistory` (type: `boolean`):

Set to true if you want to include property history (updates) of each search result. Note: This requires an additional API call per property.

## `includeTaxHistory` (type: `boolean`):

Set to true if you want to include tax history for each property. Note: This requires an additional API call per property and will increase processing time.

## `includeDemographics` (type: `boolean`):

Set to true if you want to include demographics data (population, income, households) for each property. Note: This requires 2 additional API calls per property and will increase processing time.

## `includeMoreMedia` (type: `boolean`):

Set to true if you want to include more media of each search result.

## `maxConcurrency` (type: `integer`):

Maximum number of pages that can be processed at the same time.

## `minConcurrency` (type: `integer`):

Minimum number of pages that will be processed at the same time.

## `maxRequestRetries` (type: `integer`):

Number of times the crawler will retry a failed request before giving up.

## `cookies` (type: `array`):

<p>Cookie used to authorize actor with crexi.com. Install <a rel="noopener noreferrer nofollow" target="_blank" href="https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg" previewlistener="true">EditThisCookie</a> chrome extension. Login to your crexi.com account. Click on the extension and export the crexi.com cookies. Insert the contents here</p>
## `proxy` (type: `object`):

Specifies proxy servers that will be used by the scraper in order to hide its origin.<br><br>For details, see <a href='https://apify.com/apify/web-scraper#proxy-configuration' target='_blank' rel='noopener'>Proxy configuration</a> in README.

## Actor input object example

```json
{
  "instantDatabase": false,
  "dbHasEmail": false,
  "dbHasPhone": false,
  "dbIncludePhone": false,
  "maxItems": 200,
  "forceFresh": false,
  "startUrls": [
    "https://www.crexi.com/properties?placeIds%5B%5D=ChIJG8CuwJzfAFQRNduKqSde27w&types%5B%5D=Land&mapZoom=4&mapCenter=62.96671780797615,-152.48233374774952&subtypes%5B%5D=Hunting%2FRecreational",
    "https://www.crexi.com/property-records/19-23-29-3861-01-000-ORLANDO-FL-32819/3d210c0b6ca9b74ce0cfa2dc26df25c928cc2f9d"
  ],
  "moreResults": false,
  "includeListingDetails": false,
  "includeBrokerDetails": false,
  "includePhoneNumbers": false,
  "includePropertyRecord": false,
  "includePropertyHistory": false,
  "includeTaxHistory": false,
  "includeDemographics": false,
  "includeMoreMedia": false,
  "maxConcurrency": 50,
  "minConcurrency": 1,
  "maxRequestRetries": 50,
  "cookies": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# 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": [
        "https://www.crexi.com/properties?placeIds%5B%5D=ChIJG8CuwJzfAFQRNduKqSde27w&types%5B%5D=Land&mapZoom=4&mapCenter=62.96671780797615,-152.48233374774952&subtypes%5B%5D=Hunting%2FRecreational",
        "https://www.crexi.com/property-records/19-23-29-3861-01-000-ORLANDO-FL-32819/3d210c0b6ca9b74ce0cfa2dc26df25c928cc2f9d"
    ],
    "cookies": [],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/crexi-ppe").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": [
        "https://www.crexi.com/properties?placeIds%5B%5D=ChIJG8CuwJzfAFQRNduKqSde27w&types%5B%5D=Land&mapZoom=4&mapCenter=62.96671780797615,-152.48233374774952&subtypes%5B%5D=Hunting%2FRecreational",
        "https://www.crexi.com/property-records/19-23-29-3861-01-000-ORLANDO-FL-32819/3d210c0b6ca9b74ce0cfa2dc26df25c928cc2f9d",
    ],
    "cookies": [],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/crexi-ppe").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "https://www.crexi.com/properties?placeIds%5B%5D=ChIJG8CuwJzfAFQRNduKqSde27w&types%5B%5D=Land&mapZoom=4&mapCenter=62.96671780797615,-152.48233374774952&subtypes%5B%5D=Hunting%2FRecreational",
    "https://www.crexi.com/property-records/19-23-29-3861-01-000-ORLANDO-FL-32819/3d210c0b6ca9b74ce0cfa2dc26df25c928cc2f9d"
  ],
  "cookies": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call memo23/crexi-ppe --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/crexi-ppe",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Crexi [$1.9💰] Scraper: Properties, Brokers & Instant Database",
        "description": "[Only $1.9💰] Crexi scraper for commercial real estate — sale & lease listings, property records with tax/ownership history, demographics and agent profiles nationwide. Plus an instant database of 214,000+ US brokers with brokerage, license & deal stats — phone on request. Pure API-first. JSON/CSV.",
        "version": "0.0",
        "x-build-id": "5G3KD012ExEj4WfVa"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~crexi-ppe/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-crexi-ppe",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~crexi-ppe/runs": {
            "post": {
                "operationId": "runs-sync-memo23-crexi-ppe",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~crexi-ppe/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-crexi-ppe",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "instantDatabase": {
                        "title": "Use Instant Database mode",
                        "type": "boolean",
                        "description": "Serve brokers from the database instead of live-scraping. Auto-enabled if you set State, City or Brokerage below.",
                        "default": false
                    },
                    "dbState": {
                        "title": "State (2-letter code)",
                        "type": "string",
                        "description": "e.g. TX, CA, FL. Filters the broker database to this state."
                    },
                    "dbCity": {
                        "title": "City",
                        "type": "string",
                        "description": "e.g. Austin. Optional, narrows within the state."
                    },
                    "dbBrokerage": {
                        "title": "Brokerage name contains",
                        "type": "string",
                        "description": "e.g. CBRE, Marcus & Millichap. Optional."
                    },
                    "dbHasEmail": {
                        "title": "Only brokers with an email",
                        "type": "boolean",
                        "description": "Real (non-placeholder) emails require an authenticated ingestion pass and are currently a small share of the database — most brokers have phone, not email.",
                        "default": false
                    },
                    "dbHasPhone": {
                        "title": "Only brokers with a phone",
                        "type": "boolean",
                        "description": "Phone is the more commonly available contact field in the database.",
                        "default": false
                    },
                    "dbIncludePhone": {
                        "title": "Include phone numbers (additional charge)",
                        "type": "boolean",
                        "description": "Phone is a real, hard-won field — unlocked via an authenticated per-property lookup. Off by default so you're never billed for a field you didn't ask for; check this to receive real phone numbers, billed per record that actually has one.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Max items (Instant Database mode)",
                        "type": "integer",
                        "description": "Maximum number of database records to return.",
                        "default": 200
                    },
                    "forceFresh": {
                        "title": "Force live scrape (skip DB-first)",
                        "type": "boolean",
                        "description": "When a Start URL is a find-a-broker directory page and we already have that state/city in the database, we serve it instantly from there instead of scraping. Check this to always scrape live instead.",
                        "default": false
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "URLs to start with. Supported patterns:\n- Search/listing: https://www.crexi.com/properties?...\n- Single property: https://www.crexi.com/properties/{id}/...\n- Group overview / group property: https://www.crexi.com/groups/{groupId}[/properties/{id}]\n- Agent search: https://www.crexi.com/find-a-broker?...\n- Agent profile: https://www.crexi.com/profile/...\n- Property records (parcel data, tax / sale / ownership history): https://www.crexi.com/property-records/{parcelKey}/{40-hex-recordId}",
                        "items": {
                            "type": "string"
                        }
                    },
                    "moreResults": {
                        "title": "Scrape all possible results (this process may take longer and consumes more resources)",
                        "type": "boolean",
                        "description": "If checked, the scraper will try to exhaust all possible results that it can get. Also it will take longer to finish.",
                        "default": false
                    },
                    "includeListingDetails": {
                        "title": "Include listing details",
                        "type": "boolean",
                        "description": "Set to true if you want to include listing details of each search result.",
                        "default": false
                    },
                    "includeBrokerDetails": {
                        "title": "Include broker/contact details",
                        "type": "boolean",
                        "description": "Set to true if you want to include broker/contact details of each search result.",
                        "default": false
                    },
                    "includePhoneNumbers": {
                        "title": "Include phone numbers (additional charge)",
                        "type": "boolean",
                        "description": "Only applies when Include broker/contact details is on. Phone is a real, hard-won field — unlocked via an authenticated per-property lookup. Off by default so you're never billed for a field you didn't ask for; check this to receive real phone numbers, billed per record that actually has one.",
                        "default": false
                    },
                    "includePropertyRecord": {
                        "title": "Include property record",
                        "type": "boolean",
                        "description": "Set to true if you want to include property record of each search result.",
                        "default": false
                    },
                    "includePropertyHistory": {
                        "title": "Include property history",
                        "type": "boolean",
                        "description": "Set to true if you want to include property history (updates) of each search result. Note: This requires an additional API call per property.",
                        "default": false
                    },
                    "includeTaxHistory": {
                        "title": "Include tax history",
                        "type": "boolean",
                        "description": "Set to true if you want to include tax history for each property. Note: This requires an additional API call per property and will increase processing time.",
                        "default": false
                    },
                    "includeDemographics": {
                        "title": "Include demographics data",
                        "type": "boolean",
                        "description": "Set to true if you want to include demographics data (population, income, households) for each property. Note: This requires 2 additional API calls per property and will increase processing time.",
                        "default": false
                    },
                    "includeMoreMedia": {
                        "title": "Include more media",
                        "type": "boolean",
                        "description": "Set to true if you want to include more media of each search result.",
                        "default": false
                    },
                    "maxConcurrency": {
                        "title": "Max Concurrency",
                        "type": "integer",
                        "description": "Maximum number of pages that can be processed at the same time.",
                        "default": 50
                    },
                    "minConcurrency": {
                        "title": "Min Concurrency",
                        "type": "integer",
                        "description": "Minimum number of pages that will be processed at the same time.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max Request Retries",
                        "type": "integer",
                        "description": "Number of times the crawler will retry a failed request before giving up.",
                        "default": 50
                    },
                    "cookies": {
                        "title": "Cookies",
                        "type": "array",
                        "description": "<p>Cookie used to authorize actor with crexi.com. Install <a rel=\"noopener noreferrer nofollow\" target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg\" previewlistener=\"true\">EditThisCookie</a> chrome extension. Login to your crexi.com account. Click on the extension and export the crexi.com cookies. Insert the contents here</p>"
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Specifies proxy servers that will be used by the scraper in order to hide its origin.<br><br>For details, see <a href='https://apify.com/apify/web-scraper#proxy-configuration' target='_blank' rel='noopener'>Proxy configuration</a> in README.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ],
                            "apifyProxyCountry": "US"
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
