Crexi Real Estate Scraper
Pricing
Pay per usage
Crexi Real Estate Scraper
Scrapes commercial real estate listings from Crexi.com including property details, pricing, location, images, and investment metrics.
Pricing
Pay per usage
Rating
5.0
(25)
Developer
Crawler Bros
Actor stats
24
Bookmarked
78
Total users
13
Monthly active users
5 days ago
Last modified
Categories
Share
Extract commercial real estate listings from Crexi.com — the largest US marketplace for commercial property. Get property names, addresses, prices, square footage, property types, listing URLs, and high-resolution images, ready for analysis, lead generation, market research, or CRM imports.
The scraper covers all 51 US states (50 + DC) and every commercial asset class — Office, Retail, Industrial, Multifamily, Land, Hotel, Hospitality, Mixed Use, Special Purpose, Healthcare, Self Storage, Mobile Home Park, Senior Housing, Student Housing.
What you get
For each property listing:
| Field | Description |
|---|---|
property_id | Unique Crexi asset identifier |
name | Listing title (e.g., "Multi-Tenant Office Building") |
property_type | Asset class (e.g., Office, Retail, Multifamily) |
address | Full street address |
city | City name |
state | Two-letter state code |
zip_code | Postal code |
price | Asking / sale price (formatted with $ and commas) |
square_footage | Building or unit size |
cap_rate | Capitalization rate when published by the listing agent |
image_url | Primary listing photo |
images | Array of all listing photos |
property_url | Direct link to the Crexi detail page |
description | Listing description (when available) |
listing_date | Date the property was listed |
source | Origin (api for primary path, crexi.com for detail enrichment) |
scraped_at | UTC timestamp of extraction |
When scrapeDetails=true is enabled, additional fields appear:
| Field | Description |
|---|---|
agent_info.name | Listing agent |
agent_info.company | Brokerage |
agent_info.phone | Agent phone (when published) |
agent_info.email | Agent email (when published) |
highlights | Array of property highlights |
features | Array of features |
amenities | Array of amenities |
specifications.year_built | Year of construction |
specifications.units | Unit count (Multifamily) |
specifications.parking | Parking summary |
specifications.building_class | Building class (A / B / C) |
specifications.zoning | Zoning code |
documents | Brochures and offering memoranda |
Empty fields are omitted from each record so the dataset stays clean.
Input
| Parameter | Type | Default | Description |
|---|---|---|---|
maxProperties | Integer | 1000 | Maximum properties to return across all locations / filters. |
scrapeDetails | Boolean | true | When true, also opens each detail page to enrich agent_info, highlights, features, amenities, etc. Slower but more complete. |
propertyTypes | Array | [] | Pick one or more from the 14 asset classes. Empty = all types. |
locations | Array | [] | Pick one or more US state codes (e.g., CA) or names (e.g., California). Empty = nationwide. |
minPrice | Integer | — | Minimum asking price in USD. |
maxPrice | Integer | — | Maximum asking price in USD. |
runTimeoutSecs | Integer | 1800 | Wall-clock cap on the run. Default 30 min suits most production scrapes. Lower it (e.g., 240 s) for quick smoke tests. |
proxy | Object | required | Apify Residential Proxy. Datacenter IPs are reliably blocked by Crexi's anti-bot. |
Example input — start small
{"maxProperties": 5,"scrapeDetails": false,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }}
Example input — Multifamily, $500K-$5M, full details
{"maxProperties": 50,"scrapeDetails": true,"propertyTypes": ["Multifamily"],"minPrice": 500000,"maxPrice": 5000000,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }}
Example input — Office + Retail in TX and CA
{"maxProperties": 200,"propertyTypes": ["Office", "Retail"],"locations": ["TX", "CA"],"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }}
Example output
{"property_id": "1747973","name": "Multi-Tenant Office Building","property_type": "Office","address": "123 Commerce Way, Plano, TX 75024","city": "Plano","state": "TX","zip_code": "75024","price": "$3,725,000","square_footage": "12,400 SF","image_url": "https://images.crexi.com/assets/.../716x444.jpg","images": ["https://images.crexi.com/assets/.../716x444.jpg"],"property_url": "https://www.crexi.com/properties/1747973/texas-multi-tenant-office-building","source": "api","scraped_at": "2026-05-05T07:11:14Z"}
Use cases
- Lead generation — Build prospect lists of for-sale CRE inventory by city, state, asset class, or price band.
- Market research — Track inventory volume, price ranges, and asset-class mix across markets.
- Investment analysis — Pull cap-rate-published listings for underwriting comparisons.
- CRM enrichment — Augment broker / owner records with currently listed properties.
- Geographic targeting — Run state-level pulls (e.g., FL, TX, CA) to feed regional dashboards.
- Price-range monitoring — Set
minPrice/maxPriceto capture only assets inside your buy box.
FAQ
Do I need a proxy?
Yes. Crexi is fronted by Cloudflare and reliably blocks datacenter IPs. Apify Residential Proxy with country=US is the supported configuration and is set as the input default.
Can I filter by city?
Filtering is at the state level (locations: ["FL"]). To narrow by city, run a state-level scrape and post-filter on the city field — Crexi's listing API does not expose city filters as a path-based URL.
Why does propertyTypes sometimes return mixed types?
Crexi tags many listings with multiple asset classes — for example, a building can be both Office and Mixed Use. The scraper returns properties that include the requested type in their tag list. Filter the dataset on property_type afterward if you need a single-class view.
What does scrapeDetails cost in time?
Each detail-page fetch adds ~5-10 s. For a 100-property run, expect scrapeDetails=true to take ~10 min vs ~1-2 min without it. Use scrapeDetails=false for fast list pulls and re-run with directUrls-style enrichment later if needed.
What happens if my run hits the timeout?
The actor stops launching new fetches at the runTimeoutSecs mark, pushes everything it has collected so far, and exits cleanly. No partial-data loss.
What if Crexi blocks every IP in a run?
The actor rotates up to three residential sessions per run. If all three are silently challenged by Cloudflare it exits successfully and writes a single record { "type": "crexi_blocked", "reason": "...", "scrapedAt": "..." } so downstream pipelines can detect the block and re-run for fresh IPs.
How current is the data? Live — every run hits Crexi at request time. Schedule the actor on the Apify platform for daily / hourly refreshes.
Can I scrape closed / sold / off-market properties? The actor returns currently active for-sale listings on Crexi. Sold or off-market properties are not exposed publicly.
Why are some listings priced "Negotiable" or missing a number?
Crexi lets sellers hide the asking price. Records without a numeric price are still emitted, with the price field omitted, when no price filter is set. If minPrice or maxPrice is provided, listings without a numeric price are excluded so the price filter remains accurate.
Limitations
- Only publicly listed properties are scraped — no auth-gated or off-market data.
- Crexi can change its API or page structure; if a particular field disappears the actor will continue but may emit fewer columns.
- City-level URL filtering is not supported (state level is). Filter on
cityafter the fact. - Sold / closed listing history is not in scope.