Crexi Scraper - Commercial Property Listings for Sale avatar

Crexi Scraper - Commercial Property Listings for Sale

Pricing

from $1.00 / 1,000 listing results

Go to Apify Store
Crexi Scraper - Commercial Property Listings for Sale

Crexi Scraper - Commercial Property Listings for Sale

Scrape crexi.com commercial listings: asking price, cap rate, square footage, units, year built, lot size, APN, zoning, address, coordinates, status, photos plus agent and brokerage contacts and 100+ fields. Search by city, ZIP or keyword with type, price and sort filters, or paste URLs.

Pricing

from $1.00 / 1,000 listing results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

7

Total users

5

Monthly active users

7 days ago

Last modified

Share

Crexi Scraper: Commercial Property Listings, Pricing & Broker Contacts

Crexi Scraper turns Crexi into structured commercial real estate data you can pull on demand. Search any city, ZIP or keyword with property type, price and sort filters, or paste listing URLs directly, and get a clean JSON record per listing: asking price, cap rate, square footage, units, year built, lot size, APN, zoning, full address with coordinates, status, the complete photo gallery, and the listing agent and brokerage contact details. Resume an interrupted crawl, or turn on Incremental mode for recurring monitoring, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Two ways to start. Search by location, property type and price filters, or paste crexi.com listing URLs directly. No need to build search queries by hand.
  • Deep per-listing detail. Square footage, units, year built, stories, lot size, cap rate, net operating income, APN, zoning and the full marketing description.
  • Agent and brokerage contact cluster on every listing, including license numbers and the public profile id.
  • The complete photo gallery, not just the thumbnail.
  • Filter and sort control. Property type, asking-price band, priced-only, and four sort orders in either direction.
  • Resume or monitor. Resume an interrupted crawl with a pasted run id, or turn on Incremental mode for recurring runs that return only what is new or changed.
  • Optional export into the apps you already use, via MCP connectors, without ever changing the dataset.

Use Cases

  • Commercial real estate investors: track new listings and price or cap-rate changes across markets to spot deals early.
  • Brokerages and appraisers: build comparable-listing and market datasets by property type and location.
  • PropTech and data teams: feed listing data into internal tools, dashboards or CRMs through the API or MCP connectors.
  • Market researchers: monitor inventory levels, pricing and days-on-market trends over time with Incremental mode.
  • Lead generation: collect agent and brokerage contact details tied to currently active listings.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
id1000000
name"Maple Court Apartments"
property_type"Multifamily"
status"Active"
askingPrice4250000
capRate6.25
squareFootage48000
specifications.units64
yearBuilt1998
stories3
lotSize2.4
netOperatingIncome265000
apn"000-000-000"
zoning"R-4"
fullAddress"100 Main St, Austin, Travis County, TX 78701"
city / state"Austin" / "TX"
latitude / longitude30.2672 / -97.7431
urlCrexi link to the listing
imagesfull gallery image URLs (when Fetch full details is on)
brokerageName"Example Commercial Realty"
agent_info.name"Jane Doe"
agent_info.phone"+10000000000"

Each listing also carries subtypes, marketingDescription, licenseNumbers, numberOfAssets, createdOn, activatedOn, updatedOn, detailFetched and a set of boolean flags such as isSold and isPrivate; detail-only fields stay empty when Fetch full details is off, since only the search card is returned in that case.

How to Use

  1. Pick a mode: search (build from your locations and filters) or url (paste crexi.com listing URLs).
  2. For search mode, set Locations or keywords and any of property types, price band or sort order.
  3. Turn on Fetch full details for square footage, cap rate, gallery and agent contact, and set Max items to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search by location and property type:

{
"mode": "search",
"locations": ["Austin, TX"],
"propertyTypes": ["Multifamily"],
"maxItems": 20,
"fetchDetails": true
}

Search a price band, priced listings only, sorted by cap rate:

{
"mode": "search",
"locations": ["Dallas, TX"],
"priceMin": 1000000,
"priceMax": 25000000,
"includeUnpriced": false,
"sortBy": "capRate",
"sortDirection": "Descending",
"maxItems": 50
}

Paste listing URLs directly:

{
"mode": "url",
"urls": [
"https://www.crexi.com/properties/1000000/austin-maple-court-apartments",
"https://www.crexi.com/properties/1000001/dallas-oak-plaza"
],
"fetchDetails": true
}

Monitor a search on a schedule and get only what changed:

{
"mode": "search",
"locations": ["Austin, TX"],
"propertyTypes": ["Multifamily"],
"maxItems": 200,
"incrementalMode": true
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/crexi-commercial-listings-scraper").call(
run_input={"mode": "search", "locations": ["Austin, TX"], "maxItems": 20}
)
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["name"], listing["askingPrice"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/crexi-commercial-listings-scraper').call({
mode: 'search',
locations: ['Austin, TX'],
maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Resume and recurring updates

  • Resume (resumeFromRunId) continues ONE specific interrupted crawl: paste a previous run id or dataset id and the actor skips every listing already collected there, so a large pull that got cut off can finish without duplicating or re-charging what it already returned.
  • Incremental mode (incrementalMode) is for running the SAME search again and again, for example daily. The actor remembers what it saw itself, in its own storage, so there is no id to paste. The first run returns everything as NEW. Later runs return NEW and UPDATED listings; UNCHANGED listings are suppressed and not billed unless emitUnchanged is on. Each returned record also gets changeType, changedFields, firstSeenAt and lastSeenAt. Turning on emitExpired also returns, and bills, listings no longer found, marked EXPIRED, but only after a run that fully scanned the tracked search; a run capped by Max items, or combined with Resume, never produces EXPIRED rows. REAPPEARED is only produced for a listing that was previously marked EXPIRED this way and is then found again on a later run; a search that has never used emitExpired will never see a REAPPEARED row, since nothing was ever marked gone in the first place. stateKey names or shares the stored state; leave it empty and the actor derives one automatically from the search or URL and detail settings, so different searches never mix state with each other. Turning on Incremental mode together with Resume on a search that already has saved state fails the run immediately, before anything is collected or charged. With Incremental mode off, output is exactly as before.

Send results into your apps (MCP connectors)

Optionally send the scraped listings into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape, and the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each listing, not the full JSON. Each listing becomes one entry with a title and its key fields, asking price, property type, square footage, cap rate, year built, address, status, brokerage, agent and URL, flattened to plain text, plus the opening of the marketing description. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, API & Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. If the picker is empty, you have not authorized a connector yet.
  3. For Notion, also set notionParentPageUrl to the page where listing pages should be created; Notion gets a full page per listing, other connectors get a best-effort write or digest.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch builds searches from your locations and filters, url loads the listing URLs you paste.
locationsarray[] (prefill: ["Austin, TX"])Locations or keywords to search, for example Austin, TX or 90001. Each entry is its own search. Empty searches all listings nationwide. Search mode only.
propertyTypesarraynoneProperty types to narrow the search, for example Multifamily, Office, Retail, Industrial, Land. Search mode only.
priceMinintegernoneOnly return listings with an asking price at or above this amount.
priceMaxintegernoneOnly return listings with an asking price at or below this amount.
includeUnpricedbooleantrueInclude listings without a published asking price (auctions, call-for-offers).
sortBystringrankrank (best match), price, activatedOn (newest), or capRate.
sortDirectionstringDescendingDescending or Ascending.
urlsarraynone (prefill: one example crexi.com listing URL)crexi.com listing detail URLs to load. URL mode only; filter fields are ignored.
resumeFromRunIdstringnonePaste a previous run id or dataset id to continue a large crawl without returning or re-charging for listings already collected there. For recurring monitoring of the same search, use Incremental mode instead.
incrementalModebooleanfalseTurn on for recurring monitoring. Returns only NEW/UPDATED listings (plus REAPPEARED where it applies) after the first run; state is remembered by the actor itself.
stateKeystringnoneName a monitoring campaign to keep its state stable, or deliberately share state across differently-configured runs. Leave empty to derive a key automatically from the search or URL and detail settings. Incremental mode only.
emitUnchangedbooleanfalseAlso return, and bill, listings unchanged since the last run, marked UNCHANGED. Incremental mode only.
emitExpiredbooleanfalseAlso return, and bill, listings no longer found, marked EXPIRED. Only produced after a run that fully scanned the tracked search, not when Max items capped it or Resume was used. Incremental mode only.
fetchDetailsbooleantrueLoad each listing page for square footage, units, year built, stories, lot size, cap rate, APN, marketing description, the full image gallery and agent and brokerage contact details. Adds a small per-item charge.
maxItemsinteger20The single cap on the run: stop after this many listings, across all searches and URLs. 0 = unlimited.
maxPagesintegernone (unlimited; defers to Max items)Optional safety bound on result pages per search. Left empty or 0, it does not cap the run; the run stops at Max items.
proxyobject{"useApifyProxy": true}Connection settings. The default tier is the lowest-cost option and works on every plan.
maxResidentialMBinteger0When using a Residential connection group, cap residential traffic at this many MB, then automatically switch to the lower-cost tier. 0 = unlimited.
mcpConnectorsarraynoneOptional MCP connectors to pipe results into (Notion, Linear, Airtable, Apify). Never changes the dataset.
notionParentPageUrlstringnoneNotion page URL or id under which listing pages are created. Notion connector only.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"id": 1000000,
"name": "Maple Court Apartments",
"url": "https://www.crexi.com/properties/1000000/austin-maple-court-apartments",
"property_type": "Multifamily",
"subtypes": ["Apartment Building"],
"status": "Active",
"askingPrice": 4250000,
"capRate": 6.25,
"squareFootage": 48000,
"specifications": { "units": 64, "year_built": 1998 },
"yearBuilt": 1998,
"stories": 3,
"lotSize": 2.4,
"netOperatingIncome": 265000,
"apn": "000-000-000",
"zoning": "R-4",
"marketingDescription": "Well-maintained 64-unit garden-style community in central Austin.",
"fullAddress": "100 Main St, Austin, Travis County, TX 78701",
"city": "Austin",
"state": "TX",
"zip": "78701",
"latitude": 30.2672,
"longitude": -97.7431,
"images": [
"https://images.crexi.com/assets/1000000/placeholder_3000x2000_resize.jpg"
],
"brokerageName": "Example Commercial Realty",
"agent_info": { "name": "Jane Doe", "company": "Example Commercial Realty", "phone": "+10000000000" },
"firstName": "Jane",
"lastName": "Doe",
"publicProfileId": "janedoe",
"licenseNumbers": ["TX 000000"],
"numberOfAssets": 12,
"scrapedAt": "2026-01-01T00:00:00.000Z"
}

Plan Requirement

This actor runs on any Apify plan. The default connection tier is the lowest-cost option and returns the same data, and the actor automatically tries a different connection when one is refused. A residential connection group is available if you prefer it: pick it under Connection and optionally set a residential traffic budget, and the run automatically switches back to the lower-cost tier once that budget is used.

FAQ

How much does it cost?

You pay per listing returned, with the optional detail fetch (square footage, cap rate, gallery, agent contact) billed only when it is switched on, and only for listings that are actually returned. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.

This actor collects only publicly available commercial listing data. You are responsible for how you use it: follow Crexi's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price and square footage are generally not protected, but photos, marketing descriptions and agent details may be subject to third-party rights.

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW and UPDATED listings by default, and unchanged ones are not billed unless you turn on emitUnchanged. A listing only comes back marked REAPPEARED if it was previously marked EXPIRED by a run that had emitExpired on and completed a full scan of the tracked search; if you never turn on emitExpired, a listing that drops out and later comes back is simply classified UPDATED or UNCHANGED like any other rescrape, never REAPPEARED.

What is the difference between Resume and Incremental mode?

Resume from a previous run continues ONE specific interrupted crawl using a pasted run or dataset id, and does not remember anything between separate scheduled runs. Incremental mode is for running the SAME search again and again, for example daily; the actor remembers what it saw itself, so there is no id to paste. Using both together on a search that already has saved incremental state fails the run immediately rather than mixing the two.

Why did my run fail instead of returning an empty dataset?

If every request was refused before any data could be read, the run fails with a clear connection-problem message, so "no listings today" is never confused with "nothing could be read". Check the connection warnings in the run log and try again. A genuinely empty search, where requests went through but the query just has no matches, succeeds with zero rows and a status message suggesting a broader location or different property types. An invalid Resume id also fails the run immediately, before anything is collected or charged.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each listing into Notion, Linear or Airtable once the run finishes.

๐Ÿ”— Want more real estate data?

Pair this actor with these related scrapers from the same team:

๐Ÿ  Redfin Scraper
Scrape redfin.com home listings: price, beds, baths, sqft, lot, year built, coordinates...
๐Ÿ  Apartments.com Scraper
From $1.50/1K. Scrape Apartments.com rentals by city, ZIP, neighborhood, address or URL...
๐Ÿ  Zumper
Scrape Zumper.com rental listings: apartments, houses, condos and rooms. Pulls 60+ fields...
๐Ÿ  Trulia Scraper
Scrape Trulia.com property listings by location, filters, or URL. Extract prices, beds...
๐Ÿ“‡ BizQuest Scraper
From $1/1K. Extract business-for-sale, franchise, and asset listings from BizQuest...
๐Ÿจ LoopNet
From $1.2/1K. Scrape LoopNet across the US including office, retail, industrial...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support & custom scrapers

  • ๐Ÿž Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • ๐Ÿ› ๏ธ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.