# LoopNet Search By Urls & Keywords | Details | Agents | Contacts (`memo23/apify-loopnet-search-cheerio`) Actor

Unlock valuable commercial property data from LoopNet. Extract detailed listings and agents insights for smarter real estate decisions.

- **URL**: https://apify.com/memo23/apify-loopnet-search-cheerio.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Real estate, Lead generation, Jobs
- **Stats:** 397 total users, 22 monthly users, 86.2% runs succeeded, 22 bookmarks
- **User rating**: 4.97 out of 5 stars

## Pricing

from $1.50 / 1,000 results

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LoopNet US + UK + Realla Commercial Property Scraper

**One actor, two continents.** Scrape commercial real estate from **LoopNet (US)** and **LoopNet UK / Realla.co.uk** in the same run. Office, retail, industrial, land, coworking — for sale or to let — across all 50 US states and every UK city. Rich rows with address, lat/lng, sqft, asking rent/price, broker contact, photos, EPC rating (UK), property records (US). **Plus an instant, pre-harvested database of 54,000+ US commercial real-estate brokers** — name, company, and phone — served by state/city with zero scraping. $1.50 per 1,000 results, pure HTTP, no browser.

#### How it works

![How LoopNet US + UK Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-loopnet.png)

#### ✨ Why use this scraper?

Building UK + US commercial-property data sets, tracking asking rents, sourcing brokers across both markets, or stress-testing valuations against live comparables? Most LoopNet scrapers are US-only or rebrand themselves under one country's flag. This actor is **the only Apify scraper that bundles LoopNet US + LoopNet UK (Realla) in a single run** — and the only one that still works in 2026 against CoStar's current Akamai stack.

- 🌍 **Two markets, one actor.** Paste US URLs (`/search/.../usa/`), UK URLs (`/search/commercial-property/{city}--united-kingdom/`), or both in the same `startUrls` list.
- 🇬🇧 **Realla.co.uk = LoopNet UK since 2018.** CoStar acquired Realla, consolidated inventory under LoopNet UK. This actor uses the live LoopNet UK endpoint (same backend that powers `realla.co.uk`).
- 📋 **Live `/services/search` JSON API.** Not DOM-scraping fragile placards — the actor extracts CSRF tokens + posts to LoopNet's own search endpoint (the one the website itself uses for pagination).
- 🏢 **Optional listing-detail enrichment.** Toggle `includeListingDetails: true` and each row carries full marketing description, photos, broker contact, lease terms, EPC rating (UK), parcel data + demographics (US).
- 🔁 **Akamai-cleared.** Apify Residential (default pool or US) gets through cleanly. Apify Residential **GB pool is on Akamai's blocklist** for this site — use the default pool or US instead.
- 📤 **Clean exports.** One row per property to the dataset. JSON during the run, CSV at the end.

#### ⚡ Instant Broker & Agent Database (no scraping, instant results)

Skip the crawl entirely. This actor also serves a **pre-harvested database of 54,000+ US commercial real-estate brokers** — every broker LoopNet lists across all 50 states + DC — returned **instantly**, filtered by location and firm. No proxies, no waiting, no blocking.

Set **`dbState`** (2-letter code, e.g. `TX`) — optionally narrow with `dbCity`, `dbCompany`, or `dbHasPhone` — and each matching broker comes back as one row:

- **Name, company, office location, listing count, profile + photo, languages**
- **Phone** — direct office / mobile numbers
- **Email** — where available (from LoopNet's own broker records)

| Input | Meaning |
|---|---|
| `dbState` | 2-letter state code — `CA`, `TX`, `NY`, … (setting this activates instant-DB mode) |
| `dbCity` | Optional city filter (substring, case-insensitive) |
| `dbCompany` | Optional brokerage / firm filter |
| `dbHasPhone` | `true` = only return brokers with a phone on file |

**Free vs. paid:** free-plan users get a capped preview with contact details (phone / email) hidden behind an upgrade prompt — the first couple of rows are shown in full so you can confirm the data is real. **Paid users get every matching broker with full, unmasked contact.** Billed per broker delivered.

#### 🎯 Use cases

| Team | What they build |
|---|---|
| **US CRE brokers & investors** | National search across LoopNet's US inventory — filter by state, market, sub-market, price band, sqft |
| **UK CRE analysts** | London / Manchester / Birmingham / Edinburgh / Glasgow asking-rent benchmarks for office, retail, industrial |
| **Multi-region funds** | Build comparable sets that span US + UK markets in one dataset (same row shape, regional fields where they apply) |
| **Property data platforms** | Power your listings UI with a fresh dual-market feed of commercial inventory |
| **Broker prospecting** | Extract broker name + agency + contact info from listing pages, pipeline by market or sector |
| **Recruiters & lead-gen** | Pull ready-made broker/agent lists by state, city, or firm from the **instant database** — name, company, phone — no crawl, no blocking |
| **Geospatial analytics** | Every detail row carries `Latitude` + `Longitude` (CoStar's verified geocoding) |

#### 📥 Supported inputs

| URL pattern | Region | Behaviour |
|---|---|---|
| `/search/commercial-real-estate/{state}/for-sale/` | US | Listing crawl, paginates `/2/`, `/3/`, … |
| `/search/{property-type}/{state}/{for-sale\|for-lease}/` | US | Property-type-filtered listing crawl |
| `/search/commercial-property/{city}--united-kingdom/for-{rent,sale}/` | UK | UK listing crawl |
| `/search/{office-properties\|industrial-space\|coworking-space}/{city}--united-kingdom/...` | UK | UK sub-category listing crawl |
| `/Listing/{slug}/{id}/` | US + UK | Direct property-detail URL — single row |
| `/portfolio-property/{slug}/{id}/` | US | One building inside a portfolio sale — single row, flagged `isPortfolioMember` |
| `/property/{slug}/{parcel-id}/` | US only | Tax/assessor property record (US-specific). The free lane usually cannot open these, so each record usually also bills `property-detail` |
| `/biz/{state}/{place}-businesses-for-sale/` and category pages such as `/biz/{state}/{place}/restaurants-and-food-businesses-for-sale/` | US | Businesses for sale: every listing in the search, 36 per paid page, with asking price, cash flow, revenue, location and broker. Rows have `listingType: "Business For Sale"` and a `businessId` |
| `/search/businesses-for-sale/{city-st}/`, `/search/restaurants-for-sale/{city-st}/` | US | LoopNet has no page at these; they are read as the matching `/biz/` business search |
| `/commercial-real-estate-brokers/...` | US | Broker directory crawl |
| `realla.co.uk` / `loopnet.co.uk` paths | UK | Accepted — recommend loopnet.com UK paths instead (where the listing JSON actually lives) |

Easiest workflow: apply filters in the browser, copy the resulting URL, paste into `startUrls`. The actor classifies each URL automatically.

#### 🔄 How it works (step by step)

1. **Classify** each `startUrl` — US vs UK, listing vs detail vs property-record vs broker page.
2. **Extract criteria** from the rendered HTML — CSRF token, property types, geographic IDs, listing-search-type flags.
3. **POST `/services/search`** — LoopNet's own JSON API, the same endpoint the site uses for pagination on both US and UK pages.
4. **Walk pagination** until `maxItems` per source URL is hit or results run out.
5. **(Optional) Enrich detail pages** when `includeListingDetails: true` — full marketing description, photos, lease terms, broker card, US property records, UK EPC rating.
6. **(Optional) Resolve broker contact** when broker URL is in the input — phone, email, agency, profile photo.
7. **Push to dataset, export at end** — JSON rows during the run, `data.csv` and `data.json` after.

#### ⚙️ Input parameters

##### Core

| Parameter | Type | Default | Description |
|---|---|---|---|
| `urls` (alias of `startUrls`) | array | — | Listing / detail / property-record / broker URLs. US + UK can be mixed freely. |
| `includeListingDetails` | boolean | `false` | When `true`, each row is enriched by visiting the detail page (description, photos, lease terms, broker card, EPC for UK / parcel records for US). Slower. Each full sheet a paid unblocker fetches bills `property-detail` ($0.05) on top of the row, currently most sheets; a row that cannot be fetched or afforded comes back as a free summary. |
| `maxItems` | integer | `10000` | Hard cap on rows **per source URL**. 3 URLs × `maxItems: 100` → up to 300 rows. Apify pay-per-result limits honoured. |
| `moreResults` | boolean | `false` | Not active. LoopNet caps one search at 750 results; split the search into narrower start URLs for more. |
| `proxy` | object | Apify Residential | **Note:** Apify Residential GB is Akamai-blocked for this site. Leave country empty (default pool) or use US. |

##### ⚡ Instant Broker Database mode (no scraping)

Serve brokers straight from the pre-collected database — instant, no proxies, nothing to block. Leave `startUrls` empty and set a state:

| Parameter | Type | Description |
|---|---|---|
| `dbState` | string | 2-letter US state code (`CA`, `TX`, `NY`, …). **Setting this alone activates instant-DB mode.** |
| `dbCity` | string | Optional city filter (case-insensitive substring). |
| `dbCompany` | string | Optional brokerage / firm filter (e.g. `CBRE`, `Cushman`). |
| `dbHasPhone` | boolean | `true` = only return brokers that have a phone on file. |
| `instantDatabase` | boolean | Explicitly force instant-DB mode (auto-on when `dbState` is set). |

##### Filter mode (used when `urls` is empty)

| Parameter | Type | Description |
|---|---|---|
| `keywords` | string | Free-text keyword (`warehouse`, `daycare`, `auto repair`). |
| `location` | string | City + state for US (`Sacramento, CA`); city + country for UK (`London, England`). |
| `propertyTypes` | array | `Office`, `Retail`, `Industrial`, `Land`, `Multifamily`, `Special Purpose`, `Health Care`, `Hospitality`, `Sports & Entertainment`. |
| `searchType` | string | `for-sale` or `for-lease`. |
| `PriceMin` / `PriceMax` | string | Price range. |
| `BuildingSizeRangeMin` / `BuildingSizeRangeMax` | string | Building size in sq ft. |
| `listedInLastDays` | integer | Only listings **listed or updated within the last N days** (e.g. `2` = last 2 days; `0`/omitted = all dates). Combine freely with property type, location, and price. Legacy `DateIndicator` select maps to the same filter. |
| `addresses` | array | Specific addresses to look up via property-record search (US-specific). |
| `State` / `City` | string | Geographic filter. |

##### Performance & misc

| Parameter | Type | Default | Description |
|---|---|---|---|
| `downloadImages` | boolean | `false` | Download property photos to Apify Key-Value Store. |
| `maxImages` | integer | `10` | Cap on photos downloaded per row (only with `downloadImages`). `photos[]` always lists the whole gallery. |
| `maxConcurrency` / `minConcurrency` | integer | `20` / `1` | Parallel HTTP request limits. Values below 20 are raised to 20 at runtime. |
| `maxRequestRetries` | integer | `8` | Retries on Akamai 403s, proxy failures, HTTP/2 resets. |
| `enablePriceMonitoring` | boolean | `false` | Track price changes vs prior runs. |
| `monitoringMode` | boolean | `false` | Differential mode — emit only new/changed listings. |

#### 📊 Output overview

One row per commercial property. Two field-density tiers depending on `includeListingDetails`:

- **Light** (`false`) — listing-page placard data: `propertyId`, `listingUrl`, `propertyType`, `brokerName`, partial address, price text. Fast, ~10× throughput.
- **Full** (`true`) — adds: address parts + lat/lng, sqft, year built, lease terms, broker contact, photos, description (HTML), region-specific extras (EPC for UK / parcel records + demographics for US).

US and UK rows share the **same row shape** — the parser was built around a unified schema rather than two separate ones. Region-specific extras are emitted in nested fields (`propertyRecord` for US, `ukSpecifics` for UK) that are null in the other region.

#### 📦 Output sample — standard row (every run)

Each listing always returns these core fields, including geo-coordinates, size, price, currency and full broker contact — no extra setup:

When you set a building-size filter, a row LoopNet states no size for is kept (a missing size is not evidence of a small building) and carries `_sizeUnverified: true`, so you can tell it from a row that really passed the filter.

```jsonc
{
  "propertyId": "39543236",
  "listingUrl": "https://www.loopnet.com/Listing/39543236/",
  "address": "455 Somerset St W",
  "city": "Ottawa",
  "state": "ON",
  "zip": "K1R 5J7",
  "latitude": 45.41431,
  "longitude": -75.699453,
  "propertyType": "Apartments",
  "listingType": "For Sale",
  "price": "$1.6M USD",
  "priceText": "$1.575M USD",
  "currency": "USD",
  "totalSize": 5500,
  "sizeFormatted": "5,500 SF",
  "capRate": "5.47%",
  "stats": [["Apartments"], ["5,500", "SF Bldg"], ["6", "Units"], ["5.47%", "Cap Rate"]],
  "description": "An exceptional investment opportunity at 455-457 Somerset Street W…",
  "photo": "https://images1.loopnet.com/i2/…/image.png",
  "brokerName": "Adam Pearce",
  "brokerCompany": "SLEEPWELL REALTY GROUP LTD",
  "brokerTitle": "Realtor",
  "brokerEmail": "adam@sleepwellrealty.com",
  "brokerPhone": "613-521-2000"
}
```

The **full-detail** samples below show the extended per-listing schema (tax/parcel records, EPC & lease terms, demographics, `photos[]`, `rentPerSF`, and other deep fields) layered on top of the core row above.

#### 📦 Output sample — UK property (full mode)

```jsonc
{
  "propertyId": "40367610",
  "listingUrl": "https://www.loopnet.com/Listing/13-Gascoigne-Rd-Barking/40367610/",
  "address": "13 Gascoigne Road",
  "city": "Barking",
  "region": "London",
  "country": "United Kingdom",
  "postalCode": "IG11 7DR",
  "latitude": 51.5364,
  "longitude": 0.0807,
  "propertyType": "Industrial",
  "propertySubType": "Warehouse",
  "yearBuilt": "1985",
  "totalSize": 14580,
  "sizeFormatted": "14,580 SF",
  "listingType": "For Lease",
  "priceText": "£12.50/SF/YR",
  "currency": "GBP",
  "rentPerSF": 12.50,
  "brokerName": "Richard Harman",
  "brokerCompany": "Avison Young",
  "description": "<p>Prime industrial unit fronting Gascoigne Road in Barking…</p>",
  "photos": ["https://images1.loopnet.com/.../1.jpg", "…"],
  "ukSpecifics": {
    "leaseTerm": "5–10 years",
    "businessRates": "TBC",
    "serviceCharge": "TBC",
    "epcRating": "C"
  },
  "datePosted": "2026-04-12T00:00:00Z",
  "scrapedAt": "2026-05-16T12:00:00.000Z"
}
```

#### 📦 Output sample — US property (full mode)

```jsonc
{
  "propertyId": "31948105",
  "listingUrl": "https://www.loopnet.com/Listing/1435-River-Ave-Camden-NJ/31948105/",
  "address": "1435 River Ave",
  "city": "Camden",
  "region": "NJ",
  "country": "USA",
  "postalCode": "08105",
  "latitude": 39.9495,
  "longitude": -75.1075,
  "propertyType": "Industrial",
  "totalSize": 28000,
  "sizeFormatted": "28,000 SF",
  "listingType": "For Sale",
  "priceText": "$2,400,000",
  "currency": "USD",
  "brokerName": "Anthony DeMarco",
  "brokerCompany": "Wolf Commercial Real Estate",
  "description": "<p>Industrial property in Camden's River Ward…</p>",
  "propertyRecord": {
    "parcelId": "08-0123-04567",
    "yearBuilt": "1962",
    "assessedValue": "$1,850,000",
    "taxAmount": "$42,560",
    "zoning": "I-2 Heavy Industrial",
    "cbsa": "Philadelphia-Camden-Wilmington, PA-NJ-DE-MD",
    "submarket": "South Camden",
    "demographics": { "oneMile": { /* … */ }, "threeMile": { /* … */ } }
  },
  "scrapedAt": "2026-05-16T12:00:00.000Z"
}
```

#### 📦 Output sample — broker (Instant Database mode)

Set `dbState` (optionally `dbCity` / `dbCompany`) and each row is a broker pulled straight from the database — no crawling:

```jsonc
{
  "broker_id": "0phdch0b",
  "name": "Kevin Cross",
  "company": "Marcus & Millichap",
  "location": "Houston, TX",
  "city": "Houston",
  "state": "TX",
  "listing_count": 34,
  "phone": "+1 713-452-4200",
  "email": "kevin.cross@marcusmillichap.com",
  "languages": "English",
  "photo_url": "https://images1.loopnet.com/i2/…/image.jpg",
  "profile_url": "https://www.loopnet.com/commercial-real-estate-brokers/profile/kevin-cross/0phdch0b",
  "last_scraped_at": "2026-07-09T12:00:00.000Z"
}
```

Every Instant-DB broker carries `phone` + `company`; the `email` field is reserved for future enrichment and is currently returned empty on Instant-DB rows. (Emails do appear as `brokerEmail` on property rows, resolved from the listing's own broker block where LoopNet exposes it.) On free-plan runs `phone` is masked except the first couple of proof rows — paid runs return every broker in full.

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identity** | `propertyId`, `listingUrl`, `brandedName`, `metaTitle` |
| **Address + geo** | `address`, `city`, `region`, `country`, `postalCode`, `latitude`, `longitude` |
| **Property** | `propertyType`, `propertySubType`, `yearBuilt`, `totalSize`, `sizeFormatted`, `lotSize`, `buildingClass`, `zoning` |
| **Compensation** | `listingType` (`For Lease` / `For Sale`), `price`, `priceText`, `currency`, `rentPerSF`, `rentPeriod` |
| **Broker** *(on property rows)* | `brokerName`, `brokerCompany`, `brokerPhone`, `brokerEmail` |
| **Broker (Instant DB mode)** | `broker_id`, `name`, `company`, `location`, `city`, `state`, `listing_count`, `phone`, `email` (reserved — currently empty), `languages`, `photo_url`, `profile_url`, `last_scraped_at` |
| **Content + media** | `description` (full text), `descriptionHtml`, `highlights[]`, `attachments[]` (`{title, url, type}`: offering memorandum, flyers), `unitAmenities[]` / `siteAmenities[]` / `amenities[]`, `photos[]` (whole gallery, Large size), `photosCount` |
| **UK-specific** *(`ukSpecifics.*` when UK URL)* | `leaseTerm`, `availableDate`, `businessRates`, `serviceCharge`, `epcRating` |
| **US-specific** *(`propertyRecord.*` when US URL with tax-record path)* | `parcelId`, `assessedValue`, `taxAmount`, `zoning`, `cbsa`, `submarket`, `demographics.{oneMile,threeMile,fiveMile}`, `publicTransportation.{commuterRail,airport,freightPorts}` |
| **Timing** | `datePosted`, `dateOnMarket`, `dateUpdated` (ISO 8601), `scrapedAt` |

#### 💰 Pricing

**$1.50 per 1,000 results.** Pay only for rows in the dataset, not for crawl attempts.

| Event | Charged when | Rate |
|---|---|---|
| `apify-default-dataset-item` (Result) | Property row written to dataset | $1.50 / 1,000 |
| `apify-actor-start` (Infrequent) | Each run starts | $0.007 / run |
| `property-detail` (Full property page) | A full property page or `/property/` record that had to come through a paid unblocker (currently most full sheets with `includeListingDetails: true`, and most `/property/` records) | $0.05 each |
| `agent-record` (Broker record) | Broker row from the instant broker database | $0.0035 each |

Cost examples:

- 100 UK office properties in London → ~$0.15
- 1,000 US industrial properties across CA/NV/AZ → ~$1.50
- Daily monitoring: you pay only for listings that are new since your previous runs — 50 new rows a day is ~$0.08/day

`includeListingDetails: true` adds `property-detail` ($0.05) for each full sheet a paid unblocker fetches, which is currently most of them: LoopNet blocks the free lane for listing pages. A sheet the free lane does fetch costs the normal row price, and a row the paid chain cannot fetch, or that your max cost per run cannot cover, comes back as a free summary. `/property/` record URLs usually bill `property-detail` too (about $0.05 per record). `monitoringMode` is not charged separately — you pay for the new rows it delivers, and nothing for the listings it skips.

#### ❓ FAQ

**Why does the same actor handle US + UK + Realla?**
Because LoopNet's `/services/search` JSON API is locale-agnostic — it accepts whatever criteria the page renders. US pages render US criteria, UK pages render UK criteria, both feed the same backend. The actor doesn't have to "know" which country a URL belongs to.

**What is Realla?**
Realla.co.uk was an independent UK commercial property platform until CoStar Group acquired it in 2018. CoStar consolidated Realla's inventory under LoopNet UK. The `realla.co.uk` domain still resolves but serves SEO hub pages — actual listings render at `loopnet.com` with UK-locale paths (which is what this actor uses).

**Can I scrape `realla.co.uk` URLs directly?**
Technically yes (the URL classifier accepts them), but the page body is a marketing hub without embedded listing JSON, so the actor falls back to defaults. Use `loopnet.com/.../united-kingdom/...` URLs for real data.

**Does it work for `loopnet.ca` (Canada) or French Canada listings?**
Yes — the same architecture serves `loopnet.ca` (en-CA + fr-CA `/chercher/immobilier-commercial/`). Not officially covered in the title but the actor handles it if you paste those URLs.

**What's the realistic throughput?**
Default `maxConcurrency: 20`. ~5–15 properties/sec sustained on Apify Residential. 1,000 properties in 3–10 min; 10,000 in 30–60 min.

**Why is Apify Residential GB blocked?**
Akamai's bot policy on this site filters specific IP pools. The GB pool happens to be on it. Default residential pool (no country lock) or US pool works cleanly for both US and UK URLs.

**Can I get private listings, premium recruiter listings, or off-market deals?**
No. The actor only accesses publicly available pages — no authenticated endpoints, no broker-only views.

#### 💬 Support

- For issues or feature requests, please use the [**Issues**](https://console.apify.com/actors/pIVhuvHZkW2Llfjrr/issues) tab on the actor's Apify Console page.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, additional fields, country expansion (Canada, France, Spain commercial), or a private build: <muhamed.didovic@gmail.com>
- Need other CRE platforms scraped (Crexi, CoStar paid, Rightmove Commercial, Zoopla Commercial, OnTheMarket Commercial, Movehut, CommercialPeople)? Drop an email.
- For API access (no Apify fee, just a usage fee for the API): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

If this LoopNet US + UK + Realla scraper was useful, see other scrapers and actors at [memo23's Apify profile](https://apify.com/memo23) — real estate (residential + commercial), job boards, reviews, and more.

### Run status for API consumers (RUN_SUMMARY)

Every run writes a machine-readable record to its **default key-value store** under the key
`RUN_SUMMARY`, so an API consumer never has to parse logs to know what happened. Read it with:

```
GET https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/RUN_SUMMARY?token=...
```

`outcome` is one of:

| value | meaning |
|---|---|
| `ok` | Searches ran and returned data. |
| `empty` | Searches ran successfully and LoopNet genuinely matched **0 listings**. This is a valid result, not a fault. |
| `partial` | Data was returned but is known to be incomplete — compare `itemsReturned` with `expectedTotal`. |
| `failed` | No search completed successfully (upstream blocking). The run is also marked FAILED. |

The record also carries `itemsReturned`, `sourceUrls`, and a `perUrl` breakdown with `items`,
`outcome`, `expectedTotal` (LoopNet's own reported result count, when it publishes one) and
`truncated`. The same summary is mirrored into the run's `statusMessage`.

Note: `expectedTotal` reflects everything LoopNet has for that search, while `itemsReturned`
respects your `maxItems`. A run that returns fewer items than `expectedTotal` because you asked
for fewer is **not** truncated — `truncated` is only `true` when the actor could not retrieve
results it was asked for.

If a run ends in a hard kill (out-of-memory or platform timeout) no record is written, so treat a
**missing** `RUN_SUMMARY` on any non-`SUCCEEDED` run as a failure.

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/loopnet-scraper-ppe`).

**Purpose:** Scrapes commercial real-estate listings from LoopNet US and LoopNet UK / Realla — one dataset row per property (or per broker in Instant Database mode) — the one actor that covers both markets in a single run.

**Minimal input:**

```json
{
  "startUrls": [
    { "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/" }
  ],
  "maxItems": 25
}
```

Free-text variant: `{ "searchQuery": "office space Austin Texas", "maxItems": 25 }`. Instant broker-database variant (no scraping): `{ "dbState": "TX", "dbCity": "Houston" }`.

**Output:** one row per property — `propertyId`, `listingUrl`, `address`, `city`, `region`, `country`, `postalCode`, `latitude`, `longitude`, `propertyType`, `propertySubType`, `listingType`, `price`, `priceText`, `currency`, `totalSize`, `sizeFormatted`, `yearBuilt`, `description`, `photos`, `brokerName`, `brokerCompany`, `brokerPhone`, `brokerEmail`, `ukSpecifics {leaseTerm, businessRates, serviceCharge, epcRating}`, `propertyRecord {parcelId, assessedValue, taxAmount, zoning, submarket, demographics}`, `datePosted`, `scrapedAt`. Instant-DB broker rows: `broker_id`, `name`, `company`, `location`, `city`, `state`, `listing_count`, `phone`, `email` (reserved — currently empty), `languages`, `photo_url`, `profile_url`.

**Behaviors an agent should know:**

- Mode priority: `startUrls` wins over `searchQuery` / filter fields; setting `dbState` alone switches to Instant Database mode (no scraping, instant rows).
- `maxItems` caps rows **per start URL** (schema default 10000 ≈ everything) — always set it. LoopNet itself caps one search at 750 results, so a bigger market needs several narrower start URLs (by city or county); `RUN_SUMMARY` reports `truncated` with LoopNet's own total when a search hits that cap.
- `includeListingDetails: true` enriches each row via its detail page (description, photos, lease terms, broker contact, EPC/parcel data). Slower; each full sheet a paid unblocker fetches bills `property-detail` ($0.05), currently most of them.
- Proxy: Apify Residential by default; the GB pool is Akamai-blocked for this site — use the default pool or US.
- Billing: $1.50 / 1,000 dataset rows + $0.007 per run start; a full property page that needed a paid unblocker $0.05 each. Monitoring mode is not charged separately.
- Public pages only — no broker-only views or authenticated listings; on free plans, broker-DB phone is masked except the first proof rows.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is **not affiliated with, endorsed by, or sponsored by LoopNet, Realla, CoStar Group Inc.**, or any of their subsidiaries or related entities. All LoopNet-, Realla-, and CoStar-related trademarks, service marks, trade names, and logos are the property of their respective owners and are used here solely for descriptive purposes — to identify the public commercial-property listings from which this scraper extracts data.

This Actor accesses only publicly available commercial property listing pages on `www.loopnet.com`, `www.loopnet.co.uk`, `realla.co.uk`, and `loopnet.ca`. **You are solely responsible** for ensuring that your use of the data complies with each site's Terms of Service, applicable copyright law, the UK Database Directive, GDPR (where applicable), the US Computer Fraud and Abuse Act, and any other regulations that may apply to your jurisdiction or use case. Do not use this Actor to bulk-republish copyrighted content, to harass brokers or property owners, to circumvent any rate-limiting or technical protection measure intentionally imposed by the source sites, or to enable unsolicited outreach in violation of CAN-SPAM / UK PECR / GDPR consent rules.

The author provides this Actor "as is", without warranty of any kind, and disclaims any liability for damages arising from its use.

***

### SEO Keywords

loopnet scraper, loopnet api, loopnet.com scraper, loopnet uk scraper, loopnet.co.uk scraper, realla scraper, realla.co.uk scraper, costar uk data, us commercial real estate scraper, uk commercial property scraper, uk commercial real estate api, london commercial property api, manchester commercial property scraper, birmingham commercial property scraper, california commercial property scraper, texas commercial property scraper, ny commercial property scraper, fl commercial property scraper, us cre data, uk cre data, commercial property records us, parcel data scraper, broker directory loopnet, apify loopnet actor, lease vs sale commercial property, loopnet broker database, commercial real estate broker list, cre broker contact database, loopnet agent scraper, commercial real estate agent emails, broker phone list by state

# Actor input Schema

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

Mix any combination of: (a) US listing URLs (`/search/.../usa/for-sale/`), (b) US Listing detail URLs (`/Listing/{slug}/{id}/`), (c) US property records (`/property/{slug}/{parcel-id}/`), (d) businesses-for-sale, (e) US broker directory pages, (f) **UK listing URLs** (`/search/commercial-property/{city}--united-kingdom/...`), (g) UK detail listing URLs, (h) UK sub-category URLs (office / retail / industrial / land / coworking). `realla.co.uk` and `loopnet.co.uk` paths point at the same CoStar dataset since the 2018 Realla acquisition; use the loopnet.com URLs (where the listing JSON actually lives) for best results.

## `addresses` (type: `array`):

Addresses to scrape - should be in format 123 Main St, City, State

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

US state code, e.g. "CA", "TX", "NY". Setting this alone is enough to activate Instant Database mode.

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

Narrow to a city (case-insensitive substring). Leave empty to return the whole state.

## `dbCompany` (type: `string`):

Only return brokers whose company/brokerage name contains this text (case-insensitive), e.g. "CBRE" or "Cushman".

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

Return only brokers that have a phone number on file.

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

Serve results from the pre-collected broker database instead of live-scraping. Auto-enabled when you set a State above.

## `searchQuery` (type: `string`):

Free-text search, e.g. 'office space Canary Wharf London' or 'retail space Austin Texas'. The actor infers the property type and location, then searches LoopNet. Use this when you don't have a specific LoopNet search URL or address.

## `searchType` (type: `string`):

For-sale vs for-lease when running in Filter mode — i.e. searching by location / property type / free-text query WITHOUT a Start URL. Leave empty when you pass a Start URL: the transaction type is then taken from the URL's /for-lease/ or /for-sale/ segment and this field is ignored.

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

LoopNet answers any single search with at most 750 results. With this on, a search that fills that cap is asked again in narrower bands (and a band that fills the cap is split further), so a big market returns more than 750 rows. For-sale searches are banded by price. For-lease searches are banded by available space size, because LoopNet ignores price filters on lease searches. Slower: each band is its own walk. Listings LoopNet shows no price (sale) or no space size (lease) for cannot be reached this way — they only appear in the first, unfiltered pass.

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

Set to true if you want to include listing details of each search result. Visits each listing's detail page and adds full description, photos, lease terms, broker contact, EPC rating (UK) and property/parcel records (US). Slower. Each full sheet that has to come through a paid unblocker is billed as a full property detail ($0.05) on top of the result; LoopNet currently blocks the free lane for listing pages, so that is most sheets. A row the paid chain cannot fetch, or that your max cost per run cannot cover, comes back as a free summary instead. Default false.

## `includePortfolioProperties` (type: `boolean`):

When a LoopNet listing is a portfolio (multiple properties bundled under one URL), enable this to scrape each individual property as its own dataset record. Each child carries isPortfolioMember, parentPortfolioUrl, and parentPortfolioId. The portfolio page and each building page are fetched from the website; while LoopNet blocks the free lane, a page served by a paid unblocker bills property-detail ($0.05).

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

Maximum listings or items collected per start URL (each entry in startUrls). With multiple URLs, the run can produce up to this many items per URL (for example, 10 × 3 URLs → up to 30 total). If not defined, all items will be scraped.

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

Maximum number of pages that can be processed at the same time. Values below 20 are raised to 20 at runtime.

## `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. Default 8 — gives Akamai-blocked sessions enough chances to retire and get a fresh residential IP from the proxy gateway, without burning cost on truly broken requests (100 was the old default and was wasteful).

## `PriceMin` (type: `integer`):

Minimum price to scrape.

## `PriceMax` (type: `integer`):

Maximum price to scrape.

## `BuildingSizeRangeMin` (type: `integer`):

Minimum building size to scrape.

## `BuildingSizeRangeMax` (type: `integer`):

Maximum building size to scrape.

## `PriceRangeRateType` (type: `string`):

Price range rate type to scrape.

## `CondosFilter` (type: `string`):

Condos filter to scrape.

## `DateIndicator` (type: `string`):

Date entered to scrape.

## `listedInLastDays` (type: `integer`):

Only return listings listed or updated within the last N days (e.g. 2 = last 2 days). 0 or empty = all dates. This is the clear way to filter by recency and takes precedence over the legacy 'Date Entered' (DateIndicator) select. Combine freely with property type, location, and price filters.

## `State` (type: `string`):

Select your state

## `City` (type: `string`):

Enter City to scrape.

## `firebaseAppCheckToken` (type: `string`):

Advanced / optional — leave this blank. LoopNet's mobile API uses a short-lived Firebase App Check token, and we manage that token centrally on our side, so you do NOT need to provide, provision, or refresh anything — the scraper handles it automatically. This field only exists for the rare case where you already have your own fresh token and want to supply it.

## `maxUnblockerRequests` (type: `integer`):

When the mobile API is blocked (no/expired App Check token), the actor falls back to scraping the website via a paid unblocker. This caps how many such requests one run may make, so a token outage can't run up a surprise bill. Default 60.

## `freeBrowserSearch` (type: `boolean`):

Internal fallback for the search step; off by default. Not user-configurable.

## `monitoringMode` (type: `boolean`):

Only deliver listings that no earlier run of your Apify account delivered. The first run delivers everything it finds; later runs deliver only new listings, so a daily run bills only for what is new. History is kept per account in the key-value store "<your user id>-LOOPNET-SEEN-LISTINGS"; delete that store to start over. Applies to search URLs, free-text searches, addresses and favorites folders, not to listing URLs you pass directly. Default false.

## `enablePriceMonitoring` (type: `boolean`):

If checked, it will only scrape newly listings compared to what has been scraped in previous runs. (Note: this toggle enables price monitoring — price changes of listings are tracked against prior runs. Default false.)

## `transactionTrackingMode` (type: `boolean`):

When enabled, the dataset emits ONLY the closed listings (not the full inventory). Each output item includes the original listing details plus closeStatus (removed / pending / under_contract / sold / leased), closeDetectedAt, firstSeenAt, lastSeenAt, and previousPrice. The snapshot is auto-keyed by a hash of the input (search URLs / filters), so the same scheduled input always finds its prior snapshot.

## `downloadImages` (type: `boolean`):

Set to true if you want to download images to Apify's Key-Value Store so you can download them to your computer

## `maxImages` (type: `integer`):

Maximum number of images to download per listing.

## `storeName` (type: `string`):

Rule for naming: it can only contain letters 'a' through 'z', the digits '0' through '9', and the hyphen ('-') but only in the middle of the string (e.g. 'my-value-1')
Assign a custom name to the Key-Value Store where your scraped listings will be saved. This ensures:

1. **Persistent Storage**: Enables long-term retention of listings, beyond default storage limits.
2. **Project Management**: Separate datasets by using unique names for different projects or analyses.
3. **Data Reuse**: Easily reference and reuse stored data without overwriting.
   (If left blank, the default storage will be used with standard retention limits.)

## `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><p>(Note: for this actor, export the cookies from loopnet.com — the crexi.com mentions above are a legacy leftover. Optional; most runs need no cookies.)</p>
## `proxy` (type: `object`):

Proxy servers used to hide the scraper's origin. Leave this on the default — the actor supplies its own residential exits and does NOT require any Apify proxy group. Turning Apify proxy ON, or selecting a group your plan does not include, makes the run fail input validation before it starts.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.loopnet.com/search/land/usa/for-sale/?sk=9546877f65c7a27eccfaa3321135d1dc"
    },
    {
      "url": "https://www.loopnet.com/Listing/1435-River-Ave-Camden-NJ/31948105/"
    },
    {
      "url": "https://www.loopnet.com/property/900-n-18th-st-kansas-city-ks-66102/20209-054121/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/manchester-gtm--united-kingdom/for-sale/"
    },
    {
      "url": "https://www.loopnet.com/search/office-properties/birmingham-wmd--united-kingdom/for-rent/"
    },
    {
      "url": "https://www.loopnet.com/Listing/13-Gascoigne-Rd-Barking/40367610/"
    },
    {
      "url": "https://www.loopnet.com/biz/california/los-angeles-county-businesses-for-sale/"
    },
    {
      "url": "https://www.loopnet.com/commercial-real-estate-brokers/united-states/ak/"
    }
  ],
  "addresses": [
    "2300 Craftsman Cir, Hyattsville, MD 20781"
  ],
  "dbHasPhone": false,
  "instantDatabase": false,
  "moreResults": false,
  "includeListingDetails": false,
  "includePortfolioProperties": false,
  "maxItems": 10000,
  "maxConcurrency": 20,
  "minConcurrency": 1,
  "maxRequestRetries": 8,
  "CondosFilter": "0",
  "DateIndicator": "0",
  "State": "none",
  "maxUnblockerRequests": 60,
  "freeBrowserSearch": false,
  "monitoringMode": false,
  "enablePriceMonitoring": false,
  "transactionTrackingMode": false,
  "downloadImages": false,
  "maxImages": 10,
  "cookies": [],
  "proxy": {
    "useApifyProxy": false
  }
}
```

# 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": [
        {
            "url": "https://www.loopnet.com/search/land/usa/for-sale/?sk=9546877f65c7a27eccfaa3321135d1dc"
        },
        {
            "url": "https://www.loopnet.com/Listing/1435-River-Ave-Camden-NJ/31948105/"
        },
        {
            "url": "https://www.loopnet.com/property/900-n-18th-st-kansas-city-ks-66102/20209-054121/"
        },
        {
            "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
        },
        {
            "url": "https://www.loopnet.com/search/commercial-property/manchester-gtm--united-kingdom/for-sale/"
        },
        {
            "url": "https://www.loopnet.com/search/office-properties/birmingham-wmd--united-kingdom/for-rent/"
        },
        {
            "url": "https://www.loopnet.com/Listing/13-Gascoigne-Rd-Barking/40367610/"
        },
        {
            "url": "https://www.loopnet.com/biz/california/los-angeles-county-businesses-for-sale/"
        },
        {
            "url": "https://www.loopnet.com/commercial-real-estate-brokers/united-states/ak/"
        }
    ],
    "addresses": [
        "2300 Craftsman Cir, Hyattsville, MD 20781"
    ],
    "listedInLastDays": 0,
    "maxUnblockerRequests": 60,
    "cookies": [],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/apify-loopnet-search-cheerio").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": [
        { "url": "https://www.loopnet.com/search/land/usa/for-sale/?sk=9546877f65c7a27eccfaa3321135d1dc" },
        { "url": "https://www.loopnet.com/Listing/1435-River-Ave-Camden-NJ/31948105/" },
        { "url": "https://www.loopnet.com/property/900-n-18th-st-kansas-city-ks-66102/20209-054121/" },
        { "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/" },
        { "url": "https://www.loopnet.com/search/commercial-property/manchester-gtm--united-kingdom/for-sale/" },
        { "url": "https://www.loopnet.com/search/office-properties/birmingham-wmd--united-kingdom/for-rent/" },
        { "url": "https://www.loopnet.com/Listing/13-Gascoigne-Rd-Barking/40367610/" },
        { "url": "https://www.loopnet.com/biz/california/los-angeles-county-businesses-for-sale/" },
        { "url": "https://www.loopnet.com/commercial-real-estate-brokers/united-states/ak/" },
    ],
    "addresses": ["2300 Craftsman Cir, Hyattsville, MD 20781"],
    "listedInLastDays": 0,
    "maxUnblockerRequests": 60,
    "cookies": [],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/apify-loopnet-search-cheerio").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.loopnet.com/search/land/usa/for-sale/?sk=9546877f65c7a27eccfaa3321135d1dc"
    },
    {
      "url": "https://www.loopnet.com/Listing/1435-River-Ave-Camden-NJ/31948105/"
    },
    {
      "url": "https://www.loopnet.com/property/900-n-18th-st-kansas-city-ks-66102/20209-054121/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/manchester-gtm--united-kingdom/for-sale/"
    },
    {
      "url": "https://www.loopnet.com/search/office-properties/birmingham-wmd--united-kingdom/for-rent/"
    },
    {
      "url": "https://www.loopnet.com/Listing/13-Gascoigne-Rd-Barking/40367610/"
    },
    {
      "url": "https://www.loopnet.com/biz/california/los-angeles-county-businesses-for-sale/"
    },
    {
      "url": "https://www.loopnet.com/commercial-real-estate-brokers/united-states/ak/"
    }
  ],
  "addresses": [
    "2300 Craftsman Cir, Hyattsville, MD 20781"
  ],
  "listedInLastDays": 0,
  "maxUnblockerRequests": 60,
  "cookies": [],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call memo23/apify-loopnet-search-cheerio --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/apify-loopnet-search-cheerio"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RuOxoBM1bnc5pQ3TJ/builds/3wK82IqeArUHxhLb5/openapi.json
