LoopNet Scraper - Commercial Properties, Prices & Brokers avatar

LoopNet Scraper - Commercial Properties, Prices & Brokers

Pricing

from $1.20 / 1,000 results

Go to Apify Store
LoopNet Scraper - Commercial Properties, Prices & Brokers

LoopNet Scraper - Commercial Properties, Prices & Brokers

Scrape LoopNet commercial listings across the US, including office, retail, industrial, multifamily, land and hotels. Search by city or URL and extract 25+ fields including price, size, address, broker contacts and photos, with optional detail enrichment.

Pricing

from $1.20 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

40

Total users

5

Monthly active users

a day ago

Last modified

Share

LoopNet Scraper: Commercial Property Listings, Prices & Broker Contacts

LoopNet Scraper pulls commercial property listings from LoopNet across the United States and Canada (loopnet.com) and the United Kingdom and international markets (loopnet.co.uk): offices, retail, industrial, multifamily, land, hotels, restaurants, healthcare and more. Search by location and filters, or paste your own LoopNet search or listing URLs. Every listing comes back with 30+ fields including address, price, size, broker contacts, photos and a full description, plus one normalised deal sourcing block so US and UK rows share the same column names. Export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • Two markets, one actor. Choose loopnet.com (US / Canada) or loopnet.co.uk (UK / international), and URL mode auto-detects the site per pasted link.
  • Two modes. Search by location and filters, or paste specific search or listing URLs, with multiple URLs supported in one run.
  • 30+ fields per listing. Address, price, size, year built, building class, broker contacts, photos, coordinates and more.
  • One normalised deal sourcing contract. Every listing also carries a commercial block with the same column names on both LoopNet edges, so a downstream pipeline never has to branch on which site a row came from.
  • Optional detail enrichment. Turn on fetchDetails to add coordinates, street address, broker phone, cap rate and occupancy per listing, only when you need them.
  • Built for schedules. Incremental mode returns only new and changed listings on recurring runs, and Resume continues one interrupted run without re-collecting what it already saved.
  • Failures are reported as failures. A run that could not reach LoopNet fails with a clear message instead of quietly returning an empty dataset.

Use Cases

  • Deal sourcing and acquisitions teams: build a normalised feed of for-sale and for-lease listings across markets and property types to find on-market and off-market deals.
  • Commercial brokers and analysts: track competing listings, asking prices and size ranges for a city, submarket or property type.
  • Site selection for retailers and franchises: filter available retail and industrial space by size and location to shortlist candidate sites.
  • Investment research: aggregate asking prices, cap rates and occupancy where the source discloses them, to build market comparables.
  • Real estate tech and CRM pipelines: feed listings straight into your own database or CRM, or push them into Notion, Airtable or Linear through the MCP connector.

Data You Get

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

FieldExample
id"00000001"
url"https://www.loopnet.co.uk/listing/sample-road-london/00000001/"
title"Sample Logistics Park, Unit 1"
listingType"for-lease"
propertyType"industrial-properties"
listingTypeName"Industrial to Let"
addressRaw"London, AA0 0AA"
city"London"
statenull (US rows carry a state; UK rows fill this with the county/region only when fetchDetails is on)
zipCode"AA0 0AA"
country"GB"
price / priceRaw13.25 / "£13.25 - £15.25 sq ft pa"
size / sizeSqftMin / sizeSqftMax"1,000 - 25,000 sq ft" / 1000 / 25000
yearBuilt / buildingClass2005 / "Class A" (mainly on the US edge, or with fetchDetails on)
brokerNames["Sample Agency", "Example Partners"]
description"Full listing description text appears here."
primaryPhoto"https://images.loopnet.co.uk/i2/000000000/117/sample.jpg"
scrapedAt"2026-01-01T00:00:00.000Z"
detailStatus"not_requested", "enriched" or "failed", depending on whether fetchDetails was on and whether the detail page came back
commercialthe normalised deal sourcing block described below

With fetchDetails on, rows also carry latitude/longitude, street, brokerPhone, capRate and occupancy when the source publishes them. With incrementalMode on, every row also carries changeType, changedFields, firstSeenAt and lastSeenAt.

The commercial row contract

LoopNet's two edges disagree on which fields they fill in: the US site populates spaceUse, propertyTypeName and state, while the UK site populates none of those and uses a postcode instead. So every row also carries a commercial object, a normalised shape with the same column names on both edges. It is purely additive: every field above is still there, unchanged, and every value in this block is derived from those fields. Pick the Deal sourcing contract view on the Output tab (or ?view=deal-sourcing on the dataset API) to get just these columns.

commercial.* fieldWhat it is
contractVersion"cre-1.0". Bumped only on a breaking shape change, never on an addition.
recordKey / listingId"loopnet.co.uk:00000001", and the bare id. recordKey is unique across both sites.
assetClass / assetClassRaw / assetClassSourceNormalised to office, retail, industrial, multifamily, land, hospitality, healthcare, restaurant, mixed-use, specialty or unknown, plus the raw label and which field it was read from.
dealType"sale", "lease" or "auction".
listingStatus"active", or "removed" on an EXPIRED row under incremental mode.
askingPrice / askingPriceCurrency / askingPriceBasis / askingPriceRawThe parsed figure, its currency read from the symbol the site printed, whether it is a total or a per sq ft / per month rate, and the original text.
priceAvailability"disclosed", "on_request" (the site showed a price on application style placeholder) or "not_published" (no price surface at all).
financialsMasked / maskedFinancialFieldsWhether an asking figure is published, and which of askingPrice, capRate, occupancy are empty on this row.
buildingSizeSqft (+ Min / Max) / landSizeAcres / sizeDisplaySize, numeric and as printed.
address / city / region / postalCode / countryLocation. region is the state on the US edge and the county/region on the UK edge.
hasCoordinatesBoolean flag so you can filter to mappable rows in one step.
brokerName / brokerNames / brokerageName / brokerageUrl / brokerPhone / hasBrokerContactBroker and brokerage, plus a flag for rows with a reachable phone number.
description / primaryImage / images / imageCountCopy and photos.

A few things worth knowing before you build a pipeline on it: capRate and occupancy are published only on a property's own detail page, so they stay empty unless fetchDetails is on, listedAt is filled only on the rare listing that prints its own publication date so treat scrapedAt (or firstSeenAt/lastSeenAt under incremental mode) as the reliable date field, and the top level currency field falls back to USD whenever the detail page does not declare a currency (always the case with fetchDetails off), so commercial.askingPriceCurrency (read from the printed symbol) is the more reliable currency column for UK rows.

How to Use

  1. Pick a mode: search (build a URL from filters) or url (paste your own LoopNet links).
  2. In search mode, choose the site/region, one or more locations, the listing type and property type. In URL mode, paste your links instead; the site, listing type and property type are read from each URL.
  3. Set the optional price, size and sort filters, and Max listings to control run size and cost. Turn on Fetch detail pages if you need coordinates, street address, broker phone, cap rate or occupancy.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search the UK site nationwide (industrial to let):

{
"mode": "search",
"site": "co-uk",
"locations": ["united-kingdom"],
"listingType": "for-lease",
"propertyType": "industrial-properties",
"maxListings": 20
}

Search a specific UK city:

{
"mode": "search",
"site": "co-uk",
"locations": ["london-england--united-kingdom"],
"listingType": "for-lease",
"maxListings": 20
}

Search the US site with detail pages enabled:

{
"mode": "search",
"site": "com",
"locations": ["los-angeles-ca", "new-york-ny"],
"listingType": "for-sale",
"propertyType": "office-space",
"fetchDetails": true,
"maxListings": 30
}

Paste your own URLs (site auto-detected per link), narrowed by size and sorted by size:

{
"mode": "url",
"urls": [
"https://www.loopnet.co.uk/search/commercial-property/london-england--united-kingdom/for-rent/",
"https://www.loopnet.co.uk/search/office-space/manchester-gtm--united-kingdom/for-rent/"
],
"minSqft": 2000,
"sortBy": "size-desc",
"maxListings": 50
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/loopnet-scraper").call(run_input={
"mode": "search",
"site": "co-uk",
"locations": ["united-kingdom"],
"listingType": "for-lease",
"maxListings": 20,
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["title"], listing["priceRaw"], listing["size"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/loopnet-scraper').call({
mode: 'search',
site: 'co-uk',
locations: ['united-kingdom'],
listingType: 'for-lease',
maxListings: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

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

Resuming a full catalogue walk

For an unbounded pull (maxPages empty, maxListings set to 0), two things protect a long walk: resumeFromRunId lets you continue in a brand new run by pasting the id of a previous run or its dataset, and this run skips every listing id already saved there, appending only new listings. A checkpoint is also saved automatically as the run progresses, so if the run is interrupted by a platform migration, or you click Resurrect on a failed run, it picks back up in the same run without re-saving, or re-charging for, listings it already collected. No input is needed for this part, it is automatic.

Incremental mode for recurring monitoring

Distinct from resumeFromRunId above, which continues ONE specific interrupted run. incrementalMode is for scheduling this actor to run the same search again and again (daily or weekly) and getting only what changed. The first run returns every matching listing marked NEW. Later runs return only NEW, UPDATED and REAPPEARED listings, unchanged listings are suppressed (not pushed, not billed) unless you turn on emitUnchanged. State is kept per stateKey, or an automatic hash of the search scope, in a dedicated key value store, so it costs no extra requests against LoopNet. emitExpired only produces rows once a run has fully scanned the tracked search; a page capped, resumed, or partially rejected run leaves previously tracked listings' state as is instead of guessing they are gone.

Send results into your apps (MCP connectors)

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

What gets written to the connector: a condensed, human readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify > Settings > 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 items should be created.

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 a URL from the search fields below, url passes through your own URLs. The price, size and sort filters apply in both modes.
sitestringco-ukco-uk for UK / international listings, com for US / Canada listings. Auto-detected per link in URL mode.
locationsarray(none)Search mode only. US: city slugs like los-angeles-ca, or usa for nationwide. UK: united-kingdom for nationwide, or a full slug like london-england--united-kingdom. Multiple locations supported. Ignored in URL mode.
listingTypestringfor-saleSearch mode only. for-sale, for-lease (For Rent on the UK site) or auction (US site only). Ignored in URL mode, where it is read from each pasted URL.
propertyTypestringall-commercialSearch mode only. Office, retail, industrial, multifamily, land, hotels and more. Ignored in URL mode, where it is read from each pasted URL.
urlsarray(none)URL mode only. LoopNet search or listing URLs; the site is auto-detected per URL. The search mode fields above are ignored, but the price, size and sort fields below still apply to every pasted search URL. A pasted individual listing URL is saved as is.
minPriceinteger(none)Applies in both modes, including a pasted search URL. Keeps listings priced at or above this value. Listings with no total price shown are kept.
maxPriceinteger(none)Applies in both modes, including a pasted search URL. Keeps listings priced at or below this value. Listings with no total price shown are kept.
minSqftinteger(none)Applies in both modes, including a pasted search URL. Keeps listings sized at or above this value. Listings with no size shown are kept.
maxSqftinteger(none)Applies in both modes, including a pasted search URL. Keeps listings sized at or below this value. Listings with no size shown are kept.
sortBystringdefaultApplies in both modes, including a pasted search URL. Orders the listings collected from each results page: site default, most recent, or price/size ascending or descending.
fetchDetailsbooleanfalseAdds coordinates, street address, broker phone, cap rate, occupancy and other detail page fields per listing.
maxPagesinteger(none)Safety ceiling on results pages walked per location or URL. Leave empty to walk every result page; pages stop early once Max listings is reached.
maxListingsinteger20Stop after this many listings across all searches. 0 means unlimited.
resumeFromRunIdstring(none)A previous run id or dataset id to continue a full catalogue walk across separate runs. Listings already collected there (matched by id) are skipped.
incrementalModebooleanfalseTurn on for recurring, scheduled monitoring of the same search. Classifies each listing as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED against the actor's own remembered state.
stateKeystring(none)Incremental mode only. Names a monitoring campaign so its state stays stable, or to deliberately share state across differently configured runs. Left empty, a key is derived automatically from the search scope.
emitUnchangedbooleanfalseIncremental mode only. Also return, and bill, listings that have not changed since the last run, marked UNCHANGED.
emitExpiredbooleanfalseIncremental mode only. Also return, and bill, listings that were tracked before but are no longer found, marked EXPIRED. Only produced once a run fully scans the tracked search.
proxyobjectApify ResidentialConnection settings. loopnet.co.uk works on Apify Residential out of the box; loopnet.com refuses Apify connection ranges, so supply your own residential proxy URLs here for reliable US results.
mcpConnectorsarray(none)Optional. Send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only. Page under which item pages are created.
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": "00000001",
"url": "https://www.loopnet.co.uk/listing/sample-road-london/00000001/",
"title": "Sample Logistics Park, Unit 1",
"listingType": "for-lease",
"propertyType": "industrial-properties",
"propertyTypeName": null,
"spaceUse": null,
"listingTypeName": "Industrial to Let",
"exposureLevel": "featured",
"addressRaw": "London, AA0 0AA",
"street": null,
"city": "London",
"state": null,
"zipCode": "AA0 0AA",
"country": "GB",
"marketId": null,
"propertyId": null,
"latitude": null,
"longitude": null,
"price": 13.25,
"priceRaw": "£13.25 - £15.25 sq ft pa",
"priceUnit": "per_sqft_year",
"priceLabel": null,
"listedAt": null,
"currency": "USD",
"size": "1,000 - 25,000 sq ft",
"sizeSqft": 25000,
"sizeSqftMin": 1000,
"sizeSqftMax": 25000,
"sizeAcres": null,
"yearBuilt": null,
"buildingClass": null,
"capRate": null,
"occupancy": null,
"brokerNames": ["Sample Agency", "Example Partners"],
"brokerCompanyUrl": null,
"brokerName": "Sample Agency",
"brokerCompany": null,
"brokerPhone": null,
"description": "Full listing description text appears here.",
"primaryPhoto": "https://images.loopnet.co.uk/i2/000000000/117/sample.jpg",
"photos": ["https://images.loopnet.co.uk/i2/000000000/117/sample.jpg"],
"scrapedAt": "2026-01-01T00:00:00.000Z",
"detailStatus": "not_requested",
"commercial": {
"contractVersion": "cre-1.0",
"recordKey": "loopnet.co.uk:00000001",
"listingId": "00000001",
"sourceSite": "loopnet.co.uk",
"sourceUrl": "https://www.loopnet.co.uk/listing/sample-road-london/00000001/",
"assetClass": "industrial",
"assetClassRaw": "Industrial to Let",
"assetClassSource": "listingTypeName",
"dealType": "lease",
"listingStatus": "active",
"askingPrice": 13.25,
"askingPriceCurrency": "GBP",
"askingPriceBasis": "per_sqft_year",
"askingPriceRaw": "£13.25 - £15.25 sq ft pa",
"priceAvailability": "disclosed",
"financialsMasked": false,
"maskedFinancialFields": ["capRate", "occupancy"],
"capRate": null,
"occupancy": null,
"buildingSizeSqft": 25000,
"buildingSizeSqftMin": 1000,
"buildingSizeSqftMax": 25000,
"landSizeAcres": null,
"sizeDisplay": "1,000 - 25,000 sq ft",
"address": "London, AA0 0AA",
"city": "London",
"region": null,
"postalCode": "AA0 0AA",
"country": "GB",
"latitude": null,
"longitude": null,
"hasCoordinates": false,
"listedAt": null,
"brokerName": "Sample Agency",
"brokerNames": ["Sample Agency", "Example Partners"],
"brokerageName": null,
"brokerageUrl": null,
"brokerPhone": null,
"hasBrokerContact": false,
"description": "Full listing description text appears here.",
"primaryImage": "https://images.loopnet.co.uk/i2/000000000/117/sample.jpg",
"images": ["https://images.loopnet.co.uk/i2/000000000/117/sample.jpg"],
"imageCount": 1
}
}

Plan Requirement

This actor needs an Apify Residential proxy connection. loopnet.co.uk (UK / international) runs on the default Residential connection. loopnet.com (US / Canada) often refuses Apify connections; if a US run fails with a connection message, retry later or supply your own residential proxy URLs in the Connection field for reliable US results. Regional routing is handled automatically, so leave the connection as is for most UK runs.

FAQ

How much does it cost?

You pay per listing returned, plus a small per listing surcharge only for listings enriched with fetchDetails on. The Pricing tab shows the current rates. Use Max listings to cap the cost of any run.

This actor collects only publicly available commercial property listings. You are responsible for how you use the data: follow LoopNet's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price and size are generally not protected, but photos and broker-provided copy may carry 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. The first scheduled run returns everything as NEW; every later run returns only NEW, UPDATED and REAPPEARED listings, and unchanged listings are not billed unless you turn on emitUnchanged.

What is the difference between Resume and Incremental mode?

resumeFromRunId continues ONE specific interrupted run: paste a previous run or dataset id and this run skips every listing id already saved there. incrementalMode is for running the SAME search again and again on a schedule; it keeps its own state between runs and classifies each listing as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. Use Resume to finish an interrupted one-off pull, and Incremental mode for ongoing monitoring.

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

If every result page was refused by the site, the run fails with a message naming the affected site rather than reporting a false "no listings found". That is a connection problem, so retry later, or supply your own residential proxy URLs. If the search itself genuinely matches nothing, for example an overly narrow price or size filter, the run still succeeds with an empty dataset and a status message suggesting a broader search.

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 results into Notion, Linear or Airtable.

🔗 Want more travel data?

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

🏨 Hipflat Scraper [
Scrape hipflat.co.th property listings and new-project data across Thailand: price, price...
🏨 Expedia Hotels Scraper
From $1/1K. Scrape Expedia.com hotel listings and reviews for any destination. Extract...
🏨 Rakuten Travel Scraper
Scrape Rakuten Travel, Japan's largest domestic hotel-booking site, by prefecture...
🏨 Yanolja Scraper
Scrape Yanolja (NOL), Korea's largest accommodations marketplace, by region or URL. Every...
🏨 Vrbo Scraper
Extract vacation rental data from Vrbo.com by location, region, coordinates, property...
🏨 Rover Pet Care Scraper
Scrape Rover.com pet-care providers: sitter search by city, rates per stay type, ratings...

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