Crexi Commercial Real Estate Listings & Broker Scraper
Pricing
$0.003 / listing
Crexi Commercial Real Estate Listings & Broker Scraper
Commercial property listings from Crexi with address, county, asking price, coordinates and the listing broker — and paywall placeholders dropped instead of passed through.
Pricing
$0.003 / listing
Rating
0.0
(0)
Developer
ScrapeBench
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 hours ago
Last modified
Categories
Share
Pain points
- Crexi writes paywalled values as runs of asterisks rather than leaving them empty. Over 12 retail listings checked on 2026-09-07, 'Year Built' came back as '****' on 9 of the 9 that had the field, 'APN' on 6 of 6, and Cap Rate, Parking, Tenancy, Units and Price per SqFt on every occurrence. Copied straight through, those land in your spreadsheet as text that passes an is-not-null filter.
- The API refuses to page past 1,499 results. The catalogue held 242,488 listings on 2026-09-07 and a single city can exceed the window on its own — Austin alone matched 2,367 — so a sweep that looks complete is often the first 1,499 of many, with nothing saying so.
- Two filters look supported and are not. Sending isLease, or an askingPriceFrom/askingPriceTo band, returns exactly the same 242,488 matches as sending neither.
- A commercial-listing scraper that quietly returns nothing still finishes as a SUCCEEDED run, so the Store's failure rate cannot show it. 'The site changed and we now get zero rows' and 'there is nothing here' are written identically in a dataset.
- Broker email addresses and phone numbers are not published on Crexi's API at any tier, which is worth knowing before you buy a scraper on the promise of them.
What we solve
- Paywalled placeholders are dropped, so a field is either a real published value or absent — never '****'.
- When a search matches more than Crexi will page through, the run returns a free row stating how many it matched against how many it could reach.
- Price filtering is done here, on the values actually returned, because Crexi's own price parameters do nothing.
- An outage or a changed response shape returns a free, unbilled marker row saying which — never zero rows on a successful-looking run.
- A property type Crexi does not recognise returns a free row naming the eleven it does, instead of failing the run.
- Many locations in one run, with the result cap applied per location.
Summary
Searches Crexi by city, county, state or free text and returns one row per commercial listing: name, full address with county, city, state, ZIP, Crexi's own latitude and longitude, asking price, square footage, derived price per square foot, property types, status, opportunity-zone flag, whether an offering memorandum is attached, image count, listed and updated dates, and a link to the listing page. Turn on detail enrichment for the broker's full write-up and Crexi's detail table, and broker enrichment for the listing broker's name, brokerage, public profile and how many listings they currently hold. Submit many locations in one run; the result cap applies per location, so one busy city cannot crowd out the rest.
Who it's for
- Commercial brokers and investors building deal pipelines by market
- Lenders and appraisers pulling comparable listings by county and type
- Proptech and CRE data teams ingesting listing inventory on a schedule
- Market researchers measuring inventory, pricing and days-on-market by metro
How to use
Set the input, run the actor, and collect results from the run's dataset (export to JSON/CSV/Excel, or pull via the Apify API). Example input:
{"queries": ["austin texas","san antonio texas"],"types": ["Retail","Office"],"maxResults": 200,"includeBrokers": true}
See Inputs below for every available field.
What you get
One row per record:
| Field | Description |
|---|---|
listing_id | Crexi's own asset id — stable, so it de-duplicates across runs |
name / description | The listing title and the short marketing headline |
property_types | Crexi's types for the listing; a property can carry several |
status | On-Market, Under Contract, and so on |
asking_price | USD. Null where the listing is marketed without a published price |
square_footage | Building size, where published |
price_per_sqft | Derived from asking price and square footage, only when both are real numbers |
address / full_address | Street address, and Crexi's formatted street, city, county, state and ZIP |
city / county / state / state_name / zip | Parsed location components |
latitude / longitude | Crexi's own per-listing coordinate — not a geocode we derived |
brokerage_name | The firm marketing the listing, on every row without enrichment |
broker_name / broker_profile_url / broker_listing_count | The listing broker, their public Crexi profile and how many listings they hold. Only with broker enrichment on |
in_opportunity_zone / has_offering_memorandum / has_flyer | Listing flags Crexi publishes |
image_count / thumbnail_url | How many photos the listing has, and Crexi's hosted thumbnail |
activated_on / updated_on | When the listing went live and when it last changed — this is what makes a new-listings run possible |
marketing_description | The broker's full write-up. Only with detail enrichment on |
details | Crexi's own detail table — zoning, lot size, year built, cap rate, APN — carrying only the entries it actually publishes |
market_url | The listing page on crexi.com |
source_url | The Crexi endpoint this row came from |
Sample:
{"source_url": "https://api.crexi.com/assets/2661656","listing_id": "2661656","name": "6229 Old Lockhart Road","description": null,"property_types": ["Retail","Industrial","Land"],"status": "On-Market","asking_price": 650000.0,"square_footage": null,"price_per_sqft": null,"address": "6229 Old Lockhart Road","full_address": "6229 Old Lockhart Road, Buda, Travis County, TX 78610","city": "Buda","county": "Travis County","state": "TX","state_name": "Texas","zip": "78610","latitude": 30.0733165,"longitude": -97.7213696,"brokerage_name": "John B. Sanford Real Estate","broker_name": "J.D. Sanford","broker_profile_url": "https://www.crexi.com/brokers/jdsanf","broker_listing_count": 21,"in_opportunity_zone": false,"has_offering_memorandum": false,"has_flyer": true,"image_count": 4,"activated_on": "2026-08-13T18:35:24.429Z","updated_on": "2026-08-19T14:40:14.293Z","details": {"Asking Price": "$650,000","Property Type": "Retail, Industrial, Land","Zoning": "Residential","Lot Size (acres)": "8.32","Ground Lease": "No"},"market_url": "https://www.crexi.com/properties/2661656/texas-6229-old-lockhart-road"}
Inputs
| Field | Required | Type | Default | Description |
|---|---|---|---|---|
query | no | string | "austin texas" | Where to search — a city, county, state or free-text phrase: 'austin texas', 'harris county', 'miami'. Leave blank to sweep the whole catalogue (242,488 listings on 2026-09-07), though Crexi will only page 1,499 deep into any one search, so a location is usually what you want. Kept forever alongside 'Locations' — saved tasks and API callers send it. |
queries | no | array | ["austin texas", "san antonio texas"] | Search many locations in ONE run instead of starting a run per city. Takes the same values as 'Location or keyword'. Combined with it if you fill both, and duplicates are removed. The result cap below applies PER location, so one city cannot eat the whole run and leave the others looking empty. |
types | no | array | ["Retail", "Office"] | Crexi's own property types, exactly as it spells them: Land, Retail, Office, Industrial, Multifamily, MixedUse, SpecialPurpose, Hospitality, SelfStorage, MobileHomePark, SeniorLiving. Anything else is rejected by Crexi, so an unrecognised value returns a free row naming the valid ones rather than failing the run. Leave empty for all types. |
minPrice | no | integer | — | Applied after fetching, because Crexi accepts askingPriceFrom and then ignores it — the total comes back unchanged either way. Setting any band drops listings with no published price ('Call for offers'), since a band is a statement about price that an unpriced listing cannot satisfy. |
maxPrice | no | integer | — | See 'Minimum asking price'. Leave both empty to keep unpriced listings. |
includeDetails | no | boolean | false | Adds the marketing description and Crexi's detail table (zoning, lot size, year built, cap rate, APN and so on) with one extra request per listing. Only the entries Crexi actually publishes come through: it writes paywalled values as runs of asterisks ('Year Built': '****'), and those are dropped rather than handed to you as text that survives an is-not-null filter. |
includeBrokers | no | boolean | false | Adds the listing broker's name, brokerage, public profile link and how many listings they hold, with one extra request per listing. Crexi publishes no broker email or phone number on this API at any tier, so those are not returned and are not implied. |
maxResults | no | integer | 200 | Cap on listings returned PER location, not per run — so a batch cannot silently return only the first rows overall and read as 'these cities have nothing'. Crexi refuses to page beyond 1,499 into any single search, so that is the hard ceiling per location whatever you set; when a search matches more, the run says how many it matched. |
proxyConfiguration | no | object | {"useApifyProxy": false} | Optional and off by default. Crexi's search API answered a plain client in about 0.24s from an ordinary connection, so a proxy is not needed and only adds latency (#145: never reach for one before the plain path is proven to fail). |
Pricing (Pay Per Event)
You pay per result (listing) — no charge for empty runs. Example: 1000 listings at $0.003/result ≈ $3.00.
The default input — Retail and Office across Austin and San Antonio, capped at 200 per city — returns 400 listings, so a default run costs $1.20 and takes under two seconds. You are charged per listing returned, not per location submitted: 1,000 listings cost the same from one city or from ten. Detail and broker enrichment add requests, not charges. Apify platform usage (compute) is billed separately per your plan.
Use cases
- Market inventory — sweep every retail and office listing in a metro with asking price, square footage and coordinates, ready to map.
- New-listing alerts — run on a schedule and filter on the listed date to see what came to market since the last run.
- Broker mapping — turn on broker enrichment to see who is marketing inventory in a county and how many listings each of them holds.
- Price-band screening — pull only listings inside a budget, with unpriced 'call for offers' listings excluded automatically.
Why this actor
- Crexi's paywall placeholders are stripped to empty rather than delivered as '****' — measured masked on every occurrence of Year Built, APN, Cap Rate, Tenancy, Parking, Units and Price per SqFt in a 12-listing sample on 2026-09-07.
- The 1,499-result paging ceiling is reported against Crexi's own match count, so a partial sweep can never read as a complete one.
- County, latitude and longitude come from Crexi's own listing record on every row, with no geocoding step and no derived approximation.
- Every failure mode returns a free, unbilled marker row explaining itself, so a zero-row run always says why.
- Batch many locations per run, with the cap applied per location rather than per run.
- $3 per 1,000 listings, against $0.99 to $30 across this category on the Store (2026-09-07).
Limitations & updates
Covers listings published on Crexi's public search API. The hard ceiling is Crexi's: no single search can page beyond 1,499 results, out of a catalogue of 242,488 on 2026-09-07, so wide sweeps must be split by location, property type or price band — the run says when it hit the ceiling. No broker email or phone number is available from this API at any tier. Lease-versus-sale filtering is not offered because Crexi's own parameter for it has no effect. Attributes Crexi puts behind its paywall (frequently Year Built, APN, Cap Rate, Parking, Tenancy, Units, Price per SqFt) are returned empty rather than as its asterisk placeholders — they are not available to any unauthenticated reader. Detail and broker enrichment each cost one extra request per listing, so a large run with both on takes noticeably longer. Data is whatever Crexi shows at the moment of the run; nothing here is estimated, geocoded or inferred by a model, and this Actor returns no owner or personal information.
FAQ
What are the asterisks in Crexi's data, and what do you do with them?
Crexi puts some listing attributes behind its own paywall, and instead of leaving them empty it returns a string of asterisks: 'Year Built': '', 'APN': '********', 'Cap Rate': '*'. Over 12 retail listings sampled on 2026-09-07 that happened on 9 of the 9 listings that carried Year Built, 6 of 6 for APN, and every occurrence of Cap Rate, Parking, Tenancy, Units, Beds, Net Rentable and Price per SqFt. This Actor drops them, so a field is either a real published value or absent. It matters more than it sounds: '**' is a non-empty string, so it passes an is-not-null filter, sorts as text, and quietly ruins any count of how complete your data is.
How many listings can one search return?
Up to 1,499 per location, and that ceiling is Crexi's rather than ours — the API rejects any request where offset plus count reaches 1500. The catalogue held 242,488 listings on 2026-09-07, and a single city can exceed the window: Austin matched 2,367 with no type filter. When a search matches more than can be paged, the run returns a free row saying how many matched against how many were reachable, so you know to narrow by property type, city or price band rather than assuming you have everything.
Can I filter by price, or by lease versus sale?
Price yes, lease-versus-sale no. Crexi's API accepts askingPriceFrom and askingPriceTo and then ignores them — with or without a band the match count is identical — so price is filtered here, on the values actually returned. Its isLease parameter behaves the same way, and rather than offer a switch that silently does nothing, this Actor does not have one. Setting any price band excludes listings marketed without a published price, since 'call for offers' cannot satisfy a band.
Do I get broker email addresses and phone numbers?
No, and no Crexi scraper can give you them from this API — the broker endpoint publishes a first and last name, the brokerage, a headshot, a public profile id and a listing count, and no contact fields at any tier. What you get is the broker's name, their brokerage, a link to their public Crexi profile and how many listings they currently hold, which is enough to identify and rank who is active in a market. Anything advertising CRE broker emails is getting them from somewhere other than here.
Which property types can I search?
Crexi's own eleven, spelled its way: Land, Retail, Office, Industrial, Multifamily, MixedUse, SpecialPurpose, Hospitality, SelfStorage, MobileHomePark and SeniorLiving. Their live counts on 2026-09-07 were Land 118,855, Retail 57,038, Office 38,854, Industrial 29,049, Multifamily 28,964, MixedUse 22,304, SpecialPurpose 15,999, Hospitality 5,711, SelfStorage 2,367, MobileHomePark 1,097 and SeniorLiving 838. A value Crexi does not recognise is rejected by Crexi with an error, so this Actor checks first and returns a free row naming the valid ones rather than failing the run.
What happens if Crexi is down or changes its response?
You get one free, unbilled row saying so — notice_type 'blocked' for an outage or refusal, 'source_changed' if the response no longer carries the result envelope this Actor reads. That distinction is the point: a commercial-listing scraper that starts returning nothing still completes as a SUCCEEDED run, so nothing on the Store's own failure rate can reveal it, and 'the source moved' and 'there are no listings here' look identical in a dataset unless one of them says which it is.
Do the coordinates come from Crexi or from a geocoder?
From Crexi. Latitude, longitude and county are on its own listing record, so every row carries a point the source itself published rather than one derived from an address string. That matters for mapping: a geocoded address can land on a street centroid or a city centroid and still look plausible.
How do I get only listings that are new since my last run?
Every row carries activated_on, the date Crexi made the listing live, and updated_on for its last change. Run on a schedule and filter on activated_on downstream. Rows carry Crexi's own stable listing id, so de-duplicating between runs is exact rather than address matching.
Do I pay per location or per listing?
Per listing returned. Submitting ten cities that hold 1,000 listings between them costs the same as one city with 1,000. The result cap applies per location rather than per run, so a busy city cannot use up the run and leave the others looking empty. Detail and broker enrichment add one request each per listing but no extra charge, and marker rows are free.
Is a proxy needed?
No. Crexi's search API answered a plain client in about 0.24 seconds from an ordinary connection, so the proxy input is off by default and enabling it only adds latency.
Which actor to choose
Other Actors in the portfolio that pair with this one:
- Zillow & Redfin Property Scraper — You need residential comparables alongside the commercial inventory.
- Business Email & Phone Contact Details Scraper — You have the brokerages from these listings and now need contact details for outreach.
Guides & use cases
Written up on scrapebench.dev — the bench that runs and verifies this actor against the live source every night:
- How-to: How to run Crexi Commercial Real Estate Listings & Broker Scraper
- Use case: Building a County-Level Commercial Inventory Map from Crexi
More actors, coverage and nightly verification results: scrapebench.dev
Works with AI assistants (MCP)
Callable as an MCP tool, so Claude, Cursor, VS Code Copilot and other MCP clients can run it directly. Grab the config from the MCP tab on this page — Apify hosts the server and keeps that snippet current, and OAuth signs you in on first connect, so no API token goes in your config file.
Then just ask:
"Find retail and office listings in Austin, Texas under $2 million on Crexi, with the county and the listing broker for each."
Locations are free text — a city, a county ('harris county') or a state. Property types must be Crexi's own spellings, e.g. MixedUse and SelfStorage as one word. Runs started this way bill exactly like any other run.