# LoopNet Commercial Property Scraper (`parsebird/loopnet-scraper`) Actor

Scrape LoopNet US and UK commercial real estate listings, sale/lease details, tax records, and broker directories. Export as JSON, CSV, or Excel.

- **URL**: https://apify.com/parsebird/loopnet-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

### LoopNet Commercial Property Scraper

Extract commercial real estate data from **LoopNet** — the largest commercial property marketplace in the US, now covering LoopNet's UK site too. This LoopNet scraper pulls sale and lease listings, US tax/assessor property records, and commercial real estate broker directories into clean, structured JSON — no LoopNet API key required.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search by US state/city or UK city, paste any LoopNet search or listing URL, and get address, price, size, property type, broker, and a full property-facts table (sale terms, building class, tenure, year built) per listing.
</td>
</tr></table>

<br>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor: Use the Apify actor `parsebird/loopnet-scraper` via `ApifyClient` — example: `client.actor("parsebird/loopnet-scraper").call(run_input={"startUrls": [{"url": "https://www.loopnet.com/search/land/usa/for-sale/"}], "maxItems": 50})`; key inputs are `startUrls` (array of LoopNet search/listing/property-record/broker-directory URLs), `State` + `City` (string, search without a URL), `searchQuery` (string, free text like "office space Austin Texas"), `addresses` (array of strings, geocoded to the nearest city), `includeListingDetails` (boolean, fetch full property-facts table + description + photos), `moreResults` (boolean, page past the first few pages), `maxItems` (integer, cap per start URL); output fields include `propertyId`, `listingUrl`, `address`, `city`, `region`, `country`, `propertyType`, `transactionType`, `price`, `brokerName`, `brokerCompany`, `photo`/`photos`, and (when `includeListingDetails` is on) a `facts` object with the full property-facts table; get an API token at https://console.apify.com/account/integrations and see the full API spec on the actor's API tab.

### What does LoopNet Commercial Property Scraper do?

[LoopNet](https://www.loopnet.com) lists hundreds of thousands of commercial properties for sale and lease across the US and UK, plus a public directory of commercial real estate brokers. This scraper automates pulling that data at scale:

- 🏢 **US + UK commercial listings** — office, retail, industrial, land, multifamily, hospitality, and specialty properties, for sale or for lease
- 📄 **Full listing details** — description, property-facts table (price, size, sale/lease terms, tenure, year built, building class), photos, and portfolio child properties, when you turn on "Fetch full listing details"
- 🧾 **US tax/assessor property records** — parcel data, zoning, CBSA, submarket, and 1/3/5-mile demographics from LoopNet's `/property/` pages
- 👤 **Broker directory** — name, company, location, phone, and languages from LoopNet's public `/commercial-real-estate-brokers/` pages
- 🔎 **Multiple ways to search** — paste a LoopNet URL, pick a US State/City, type a free-text query like "retail space Austin Texas", or supply street addresses (geocoded to their city)
- 📅 **Scheduled monitoring** — re-run on a schedule and get only new listings, price-change flags, or a feed of listings that disappeared (closed/sold/leased) since the last run

Since LoopNet has no public API, this actor reads the same server-rendered pages a browser does and normalizes them into rows — the closest thing to a **LoopNet API** you'll find, ready to plug into a spreadsheet, database, or BI tool.

### Supported LoopNet URLs

| URL pattern | Region | Behavior |
|---|---|---|
| `/search/{property-type}/{state}/for-sale\|for-lease/` | US | Search, paginates `/2/`, `/3/`, … |
| `/search/{property-type}/{city}--united-kingdom/for-sale\|for-rent/` | UK | Search, same pagination |
| `/Listing/{slug}/{id}/` | US + UK | Single listing — full property-facts table |
| `/property/{slug}/{parcel-id}/` | US only | Tax/assessor property record |
| `/commercial-real-estate-brokers/...` | US | Broker directory, paginates `/2/`, `/3/`, … |

US property-type slugs: `commercial-real-estate` (all types), `office-space`, `retail-space`, `industrial-properties`, `land`, `multifamily-properties`, `hospitality-properties`, `specialty-properties`. UK property-type slugs: `commercial-property` (all types), `office-space`, `retail-space`, `industrial-space`, `land`, `coworking-space`. LoopNet's `/biz/businesses-for-sale/` section is a separate, fully client-rendered app with no server-rendered listing data and is **not** supported by this actor.

### Input parameters

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| startUrls | array | No | — | LoopNet search, listing, property-record, or broker-directory URLs |
| searchQuery | string | No | — | Free text, e.g. "office space Austin Texas" |
| addresses | array | No | — | Street addresses, geocoded to their city |
| searchType | string | No | for-sale | for-sale / for-lease / auctions (Filter mode only) |
| State | string | No | none | US state, for searching without a URL |
| City | string | No | — | Narrows State to one city |
| maxItems | integer | No | 10000 | Max items per start URL |
| moreResults | boolean | No | false | Page past the first few pages |
| includeListingDetails | boolean | No | false | Fetch each listing's full page |
| includePortfolioProperties | boolean | No | false | Include portfolio child properties |
| listedInLastDays | integer | No | 0 | Keep only recently listed properties (needs listing details) |
| PriceMin / PriceMax | integer | No | — | Post-filter on scraped price |
| BuildingSizeRangeMin / Max | integer | No | — | Post-filter on scraped building size |
| monitoringMode | boolean | No | false | Push only listings new since the last run |
| enablePriceMonitoring | boolean | No | false | Flag price changes vs. the last run |
| transactionTrackingMode | boolean | No | false | Push only listings that disappeared since the last run |
| downloadImages | boolean | No | false | Save photos to a key-value store |
| maxUnblockerRequests | integer | No | 60 | Cost cap on proxy requests |
| proxy | object | No | Unblocker | Proxy configuration — keep the default |

See the Input tab for the full list, including performance tuning (`maxConcurrency`, `maxRequestRetries`) and image options (`maxImages`, `storeName`).

### Output example

```json
{
  "propertyId": "37936068",
  "listingUrl": "https://www.loopnet.com/Listing/14211-14301-Arnold-Avenue/37936068/",
  "address": "14211 & 14301 Arnold Avenue",
  "city": "Glen Ellen",
  "region": "CA",
  "country": "US",
  "propertyType": "",
  "transactionType": "For Sale",
  "price": "$8,025,000",
  "brokerName": "Marshall Kelly",
  "brokerCompany": "Keegan & Coppin Inc.",
  "photo": "https://images1.loopnet.com/i2/.../image.jpg",
  "facts": {
    "totalBuildingSize": "18,354 SF",
    "totalLandArea": "3.99 AC",
    "saleType": "Investment or Owner User",
    "saleStatus": "Active"
  },
  "sourceCountry": "US",
  "scrapedAt": "2026-09-12T01:19:29.972Z"
}
```

`facts` only appears when `includeListingDetails` is on, and its keys vary by property type and country (a UK lease listing surfaces `tenure`/`tenancy`/`rentableBuildingArea` instead of `saleType`/`saleStatus`) — the actor exposes whatever LoopNet's own property-facts table contains rather than a fixed field list. Broker-directory rows and US property-record rows use a different shape — see the dataset preview after a run, or the API tab, for full examples. Download results as **JSON, CSV, Excel, HTML, or XML** from the Storage tab, or pull them via the API.

### Use cases

- Feed a CRE brokerage's internal deal-flow tool with new sale/lease listings by state or metro
- Build a market-comps dataset (price, price/SF, size, cap rate where listed) for underwriting
- Track a specific portfolio or competitor's listings for price changes and closings with monitoring mode
- Build a broker contact list by state for outbound prospecting
- Pull US tax/assessor data (zoning, CBSA, demographics) alongside listing data for site-selection research

### How it works

1. Give the actor **Start URLs** (LoopNet search/listing/property-record/broker-directory pages), a **State**/**City**, a **searchQuery**, or **addresses**.
2. It resolves any query/address/State input into a LoopNet search URL, then requests each page through Apify's Unblocker proxy (LoopNet blocks every other proxy tier).
3. Search-result pages are parsed directly from server-rendered HTML — no LoopNet login required.
4. When `includeListingDetails` is on, each listing's own page is fetched for the full property-facts table, description, and photos.
5. Results are pushed to the dataset as they're found; with `monitoringMode` / `enablePriceMonitoring` / `transactionTrackingMode`, each run is diffed against the previous run's snapshot.
6. Download the dataset as JSON, CSV, or Excel, or read it through the [Apify API](https://docs.apify.com/api/v2) / [integrations](https://apify.com/integrations) (Zapier, Make, Google Sheets, and 30+ more).

### How much does it cost to scrape LoopNet?

This actor uses Apify's **pay-per-event** pricing — you pay per scraped item, not per platform compute unit. Plain search results are inexpensive; turning on `includeListingDetails` costs far more per item because each one needs its own extra page fetch through the paid Unblocker proxy (the only proxy tier LoopNet doesn't block) — factor that in before enabling it on a large run.

| Event | Fires when | Free | Bronze | Silver | Gold |
|---|---|---|---|---|---|
| `listing-scraped` | Once per property/listing/property-record row pushed | $1.39 | $1.29 | $1.19 | $0.99 |
| `listing-detail-scraped` | In addition to `listing-scraped`, when `includeListingDetails` fetched that item's own page | $45.00 | $39.00 | $37.00 | $35.00 |
| `monitoring-listing-scraped` | Once per row pushed while `monitoringMode` or `transactionTrackingMode` is on (cheaper — lower volume by design) | $0.99 | $0.89 | $0.89 | $0.89 |
| `broker-scraped` | Once per broker-directory row pushed | $3.49 | $3.29 | $3.09 | $2.89 |

Prices are per 1,000 events. Set a **Max cost per run** limit in the Console (Actor run → Limits) so an unexpectedly large search — especially one with `includeListingDetails` on — can't run past your budget; the actor also checks Apify's spending-limit signal after every charge and stops immediately once it's reached.

### Input / Output

Configure Start URLs, State/City, or a search query in the Input tab — the schema includes prefilled example values so a default run works immediately. Every run's results land in the Storage tab, downloadable as JSON, CSV, Excel, HTML, or XML, or queryable live via the [Apify API](https://docs.apify.com/api/v2).

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/loopnet-scraper").call(run_input={
    "startUrls": [{"url": "https://www.loopnet.com/search/office-space/tx/for-lease/"}],
    "maxItems": 200,
    "includeListingDetails": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["address"], item["price"])
```

#### JavaScript

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: "<YOUR_API_TOKEN>" });
const run = await client.actor("parsebird/loopnet-scraper").call({
    startUrls: [{ url: "https://www.loopnet.com/search/office-space/tx/for-lease/" }],
    maxItems: 200,
    includeListingDetails: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Is it legal to scrape LoopNet?

Scraping publicly available data is generally legal, but you're responsible for how you use it. This actor only reads pages LoopNet serves to any visitor without logging in — it does not bypass a login wall, CAPTCHA-solve to access gated content, or access data behind LoopNet's CoStar account login (that's why broker phone/email on listing pages, which LoopNet gates behind a login, are not included — see the FAQ). Always review [LoopNet's Terms of Use](https://www.loopnet.com/terms-of-use/) and comply with applicable law (including GDPR for UK/EU data) before scraping or reusing this data. See Apify's [web scraping legality guide](https://apify.com/is-web-scraping-legal) for more.

### Related Actors

- [BizBuySell Scraper](https://apify.com/parsebird/bizbuysell-scraper) — businesses-for-sale listings, a category LoopNet itself doesn't expose as scrapable data
- [Trulia Property Scraper](https://apify.com/parsebird/trulia-property-scraper) — US residential listings
- [Immobiliare.it Scraper](https://apify.com/parsebird/immobiliare-it-scraper) — Italian real estate
- [Homegate.ch Swiss Real Estate Scraper](https://apify.com/parsebird/homegate-ch-scraper) — Swiss real estate

### FAQ

**Why don't I see broker phone or email on listing rows?**
LoopNet only shows a broker's name/company/photo to anonymous visitors on the listing page itself — phone and email require being logged into a CoStar/LoopNet account, which this actor does not do. Broker **phone** numbers (not email) are available separately from LoopNet's public broker-directory pages (`/commercial-real-estate-brokers/...`), which this actor supports as its own row type.

**Why is `facts` sometimes empty?**
`facts` is only populated when `includeListingDetails` is on, since it comes from the listing's own page, not the search-result list.

**LoopNet blocks my own scraper — why does this actor work?**
LoopNet runs Akamai Bot Manager and returns "Access Denied" to ordinary datacenter and residential IPs (we verified this directly). This actor routes every request through Apify's paid **Unblocker** proxy group, which is why the default Proxy configuration should be left as-is.

**Does this cover LoopNet's UK site and Realla?**
Yes — UK searches and listings are supported via loopnet.com's own UK URLs. realla.co.uk and loopnet.co.uk point at the same underlying CoStar dataset since the 2018 Realla acquisition, but the listing data itself lives at loopnet.com UK URLs, so use those for best results.

**Can I schedule recurring runs?**
Yes — use Apify's [Scheduler](https://docs.apify.com/platform/schedules) to run daily or weekly, and turn on `monitoringMode` / `enablePriceMonitoring` / `transactionTrackingMode` to get only what changed each time.

**Something looks wrong or missing — how do I report it?**
Open an issue on the actor's Issues tab in Apify Console. LoopNet's page structure does change occasionally; report the URL that failed and we'll take a look.

# Actor input Schema

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

LoopNet search-result URLs, single listing URLs (/Listing/.../{id}/), US property-record URLs (/property/.../{parcel-id}/), or broker-directory URLs (/commercial-real-estate-brokers/...). Mix US and UK URLs freely — see the README for the full pattern table.

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

e.g. 'office space Austin Texas' or 'retail space London'. The actor infers the property type and location and builds a search from it. Use this only when you don't already have a Start URL.

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

Street addresses, e.g. '2300 Craftsman Cir, Hyattsville, MD'. LoopNet has no exact-address search, so each address is geocoded to its city and that city is searched.

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

For-sale vs. for-lease when searching by State/City, searchQuery, or addresses (no Start URL). Ignored for Start URLs — the URL's own /for-lease/ or /for-sale/ segment decides it.

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

Pick a US state to search without a Start URL. Combine with City to narrow it further.

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

Narrow the State search to one city, e.g. 'Austin'. Leave empty to search the whole state.

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

Maximum listings/records collected per Start URL. With 3 Start URLs, a run can produce up to this many items x 3.

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

Page through the full result set instead of stopping after a few pages. LoopNet itself stops listing results after roughly 500-750 per search.

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

Visit each listing's own page for the full description, photos, and property-facts table (sale/lease terms, building class, tenure, year built, and more). Slower and charged as a separate event per item.

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

When a listing bundles multiple properties (a portfolio), include each individual property's address, size, and coordinates. Only applies when 'Fetch full listing details' is on.

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

Keep only listings whose 'Date on Market' is within this many days. Requires the listing detail page, so it automatically turns on 'Fetch full listing details'. 0 = no date filter.

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

Drop results priced below this (checked against the scraped listing price).

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

Drop results priced above this (checked against the scraped listing price).

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

Drop results smaller than this. Most accurate when 'Fetch full listing details' is on.

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

Drop results larger than this. Most accurate when 'Fetch full listing details' is on.

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

Push and charge only listings that weren't seen on the previous run with the same input.

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

Add priceChanged/previousPrice fields when a listing's price differs from the previous run.

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

Instead of the normal output, push only listings that disappeared since the previous run (closeStatus: 'removed'), with firstSeenAt/lastSeenAt/previousPrice.

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

Save each listing's photos into an Apify key-value store instead of only linking to LoopNet's CDN.

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

Only used when 'Download photos' is on.

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

Optional. Name of the key-value store to save photos into (letters, digits, hyphens only). Leave empty to use the run's default store.

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

Maximum concurrent detail-page fetches. Values below 20 are raised to 20.

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

Minimum concurrent requests.

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

How many times to retry a page before giving up on it. LoopNet's Unblocker responses are frequently incomplete on the first try, so a low value will lose data.

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

Every request this actor makes uses Apify's paid Unblocker proxy group. This caps the total number of such requests in one run so a misconfigured input can't run up a surprise bill. 0 = unlimited.

## `proxy` (type: `object`):

loopnet.com blocks datacenter and residential proxy IPs outright (confirmed: both return Akamai's 'Access Denied' page). Only the Unblocker group gets through — keep it selected.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.loopnet.com/search/land/usa/for-sale/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
    }
  ],
  "addresses": [],
  "searchType": "for-sale",
  "State": "none",
  "maxItems": 20,
  "moreResults": false,
  "includeListingDetails": false,
  "includePortfolioProperties": false,
  "listedInLastDays": 0,
  "monitoringMode": false,
  "enablePriceMonitoring": false,
  "transactionTrackingMode": false,
  "downloadImages": false,
  "maxImages": 10,
  "maxConcurrency": 20,
  "minConcurrency": 1,
  "maxRequestRetries": 8,
  "maxUnblockerRequests": 60,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}
```

# Actor output Schema

## `dataset` (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/"
        },
        {
            "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
        }
    ],
    "searchQuery": "",
    "addresses": [],
    "City": "",
    "maxItems": 20,
    "storeName": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/loopnet-scraper").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/" },
        { "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/" },
    ],
    "searchQuery": "",
    "addresses": [],
    "City": "",
    "maxItems": 20,
    "storeName": "",
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/loopnet-scraper").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/"
    },
    {
      "url": "https://www.loopnet.com/search/commercial-property/london-england--united-kingdom/for-rent/"
    }
  ],
  "searchQuery": "",
  "addresses": [],
  "City": "",
  "maxItems": 20,
  "storeName": ""
}' |
apify call parsebird/loopnet-scraper --silent --output-dataset

```

## MCP server setup

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

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/eXUMvsRgaPF4XLHf7/builds/kwFZx7OUJMp8ObciI/openapi.json
