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

45

Total users

6

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, plus the listing page's full photo gallery in photos (often 10 to 40 images, where a results card shows one or two), unitAmenities and siteAmenities (the page's own two amenity groups; amenities stays their union), dateUpdated (the page's "Last Updated" date) and, on loopnet.com, transportation: the nearby transit, bus, commuter rail and airport stops the listing page shows, each with its drive time and distance. Every row also carries searchPosition, the listing's position (1, 2, 3...) on the results page it was read from. 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.

With fetchDetails on, a listing may also carry propertyFacts, highlights, amenities (unitAmenities/siteAmenities unioned), documents, locationScores, brokers (one entry per broker on the listing, each with name/title/phone/company/companyUrl), and, for lease listings, spaces (one entry per available unit/space, with size, term and rental rate). Multi-property US sale listings also carry isPortfolio, portfolioPropertyCount and portfolioProperties.

Dataset views and the run summary

Besides the default row-per-listing view, the Output tab offers: Changes (?view=changes), incremental-mode-only rows showing changeType/changedFields/previousPrice/previousSiteListingStatus/firstSeenAt/lastSeenAt for monitoring a recurring search; Deal sourcing contract (?view=deal-sourcing), the normalised commercial.* columns described above, one row per listing; Property details (?view=property-details); Brokers (?view=brokers), one row per broker on a listing (name/title/phone/company); and Spaces (?view=spaces), one row per available unit/space on a lease listing (size/term/rental rate). Pick a view from the Output tab dropdown or append ?view=<name> to the dataset API URL.

A per-run summary (sources searched, listings pushed/enriched/rejected, whether the 750-result cap or price-band splitting was hit, and whether each source reached the end of its catalogue) is written to the run's key-value store under the key OUTPUT at the end of every run, alongside the overall totals already visible in the run log.

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
}

Locations: a plain name, or the exact LoopNet slug

Type a plain name - London, Los Angeles, New York, Paris, Toronto and other major markets on both sites resolve automatically through a list built from LoopNet's own "popular locations" pages. Not on that list yet? Paste the exact slug from a LoopNet URL instead, exactly as it appears in the address bar - for loopnet.com a city slug like los-angeles-ca or new-york-ny (or usa for nationwide), for loopnet.co.uk a full slug like london-england--united-kingdom (or united-kingdom for nationwide). A bare city name with no state/region - london, los-angeles - is NOT a valid slug on either site and returns a 404-style empty search; this actor resolves those specific plain names automatically, and warns loudly in the run log (naming this escape hatch) for any other name it doesn't recognize instead of silently returning nothing.

Supported URL shapes

Every shape below is live, auto-detected per URL (no site input needed in URL mode), and exercised by its own test_plan.json case:

ShapeExampleNotes
.com search results (SERP)https://www.loopnet.com/search/commercial-real-estate/los-angeles-ca/for-lease/listingType/propertyType are read from the URL, not the input.
.com search results, a US state slughttps://www.loopnet.com/search/commercial-real-estate/ca/for-sale/A bare 2-letter state slug (e.g. ca, tx) works the same as a city slug.
.com search results + live filter/sort params...for-sale/?min-price=1000000&max-price=2000000&price-type=sf&min-size=5000&min-cap-rate=5_5&is-portfolio=exclude&keyword=warehouseThese are the params the site itself honours (verified live: the response echoes the same price/size/keyword back in its own filter state) - not the old sk=/price-min/bsf-min trio below, which the site silently ignores. The actor's own minPrice/maxPrice/priceType/minSqft/minCapRate/portfolioFilter/keyword inputs build the identical params in search mode and also apply on top of a pasted URL carrying them (both modes).
.com search results + an inert legacy param (harmless, no effect)...for-lease/?sk=PriceHighToLow&price-min=100000&bsf-min=1000sk is the site's own saved-search state key (set by its UI, not a sort name); price-min/bsf-min are dead query names from an older site version. All three are preserved verbatim on a pasted URL but do not filter anything - use the live param names in the row above instead.
.com search results + a real saved-search state key...for-sale/?sk=1ff2e71097507fb8dc56538d9837600c&e=uA real sk value (minted by the site's own UI when a user saves a search) IS honoured server-side - this actor cannot mint one, but preserves whatever key a pasted URL already carries.
.com auctionshttps://www.loopnet.com/search/commercial-real-estate/usa/auctions/listingType resolves to auction. The UK site has no auction surface.
.com individual listinghttps://www.loopnet.com/Listing/434-Urenda-Loop-Carrizo-Springs-TX/41597858/Fetched by the numeric id in the URL, never by the slug text - a listing whose title/address changed since the URL was copied still resolves correctly. Always billed as a detail fetch (see below).
.co.uk search results, a cityhttps://www.loopnet.co.uk/search/commercial-property/london-england--united-kingdom/for-rent/
.co.uk search results, nationwidehttps://www.loopnet.co.uk/search/commercial-property/united-kingdom/for-rent/
.co.uk individual listinghttps://www.loopnet.co.uk/listing/10-prestons-rd-london/35346928/Same by-id guarantee as the .com listing shape above.
.com search results, a page-N URLhttps://www.loopnet.com/search/commercial-real-estate/los-angeles-ca/for-lease/2/A pasted /N/ URL starts at page N and continues forward.
.com property-type categoryhttps://www.loopnet.com/search/office-space/los-angeles-ca/for-lease/Property type is read from the URL.
.com search results, nationwide for-salehttps://www.loopnet.com/search/commercial-real-estate/usa/for-sale/
.com search results + ?sk=x&sb=1https://www.loopnet.com/search/commercial-real-estate/los-angeles-ca/for-sale/?sk=x&sb=1Query string is preserved verbatim; see the saved-search key rows above.
.co.uk search results, a page-N URLhttps://www.loopnet.co.uk/search/commercial-property/london-england--united-kingdom/for-rent/2/Starts at page N.
.co.uk property-type categoryhttps://www.loopnet.co.uk/search/office-space/london-england--united-kingdom/for-rent/
.co.uk search results, nationwide for-salehttps://www.loopnet.co.uk/search/commercial-property/united-kingdom/for-sale/
Tracking / UTM params on any search or listing URL...for-lease/?utm_source=newsletter&utm_medium=emailPassed straight through to the fetch; they don't affect parsing.
A non-listing LoopNet page (businesses-for-sale, broker profile/directory, tax-parcel record)https://www.loopnet.com/biz/businesses-for-sale, .../commercial-real-estate-brokers/profile/..., .../commercial-real-estate-brokers/united-states/ca/, .../property/900-n-18th-st-kansas-city-ks-66102/20209-054121/Not a commercial-property results page this actor can parse (own CoStar vertical, broker page, or tax record - no listing/search-result markup) - logs a loud warning ("did not look like a LoopNet results page") rather than silently returning 0 results. A /property/ parcel page in particular embeds a "similar listings" carousel for other, unrelated listings, which this actor explicitly excludes so it is never mistaken for that URL's own search results.

Default URLs. URL mode run with urls omitted or left unedited now scrapes the 12 example URLs (one per shape above) in order until maxListings (default 20) is reached, so the last examples may be cut at the default. Each listing appears at most once per run: a listing that an earlier example URL's results page already listed is skipped, even if it was not saved because of the per-URL share of Max listings, so the page-2 and individual-listing examples can return no rows in this default run. Paste a URL on its own to scrape it fully. Leaving the list untouched scrapes these examples instead of scraping nothing. Clear the list and paste your own links to scrape only those.

A pasted individual listing URL (the two "individual listing" rows above) is always fetched and always billed as a detail-enrichment row, regardless of the Fetch detail pages toggle - there is no results-page card to fall back on for a single pasted listing, so this is the one case where that toggle doesn't change what happens.

LoopNet's map/draw-area search is client-side JS state (the area is derived from the resolved location, not a URL parameter), not a separate pastable link - there is no /map/ or ?bbox= URL shape to support.

loopnet.com lists at most 750 results for any one search (30 pages of 25); a search matching more than that logs a warning and returns only the first 750. Turn on splitLargeSearches to walk a capped for-sale search again in price bands and reach listings beyond the first 750; a search that is still capped after banding is reported as such rather than silently truncated.

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, partially rejected, or started from a pasted URL's page 2+ run leaves previously tracked listings' state as is instead of guessing they are gone.

In URL mode, the search scope that keys the automatic state includes the price/size filters below (they apply to a pasted results URL too, see "Filters and sort" above), not just the pasted URLs themselves, so changing a filter starts a fresh baseline instead of reusing one that would otherwise look like every now-excluded listing had disappeared. An explicit stateKey always wins over the automatic scope; it is only EXPIRED-safe when every run that shares it also shares the same filters/mode/URLs/fetchDetails, sharing one stateKey across genuinely different scopes reintroduces the same false-EXPIRE risk on purpose.

Three fields are always returned but never, by themselves, make a listing UPDATED: searchPosition (it moves whenever other listings are added or re-ranked), dateUpdated (the site bumps it for edits that change none of the fields this actor reads; a real price or description change is still caught by those fields) and transportation (a nearby-stops panel the site computes around the listing). The first run after an upgrade that starts filling a field the previous version left empty (for example the title and price of the site's compact results cards, or the full photo gallery) does not re-report your tracked listings as UPDATED either.

ignoreFieldsForChanges excludes specific fields from change detection ONLY, the field still comes back in every row, it is just never, by itself, the reason a listing is classified UPDATED. This actor's own fields measured stable across repeat scrapes are already excluded automatically with no input needed; use this when you personally observe a different field drifting for your search. Accepts a plain field name (exposureLevel) or a dotted path into the nested commercial block (commercial.primaryImage), or commercial.* to ignore every field in that block at once. Turning this on, or changing it, never triggers a one-time UPDATED wave of its own.

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. A plain name (London, Los Angeles, New York...) resolves automatically on major markets; see "Locations: a plain name, or the exact LoopNet slug" above. Otherwise, the exact slug: US los-angeles-ca, or usa for nationwide; UK london-england--united-kingdom, or united-kingdom for nationwide. 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.
urlsarray12 example URLs, one per shape (scraped in order until Max listings)URL mode only. LoopNet search or listing URLs; the site is auto-detected per URL. See "Supported URL shapes" above for the full list (SERP, auctions, individual listing, both sites). 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, and always billed as a detail fetch regardless of fetchDetails.
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.
priceTypestringtotalFor-sale searches on loopnet.com. Whether minPrice/maxPrice above is the total asking price (default), or a price per sq ft, per acre or per unit. A per-unit filter is applied by the site; this actor does not re-filter it against the card's total price.
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. On loopnet.com for-sale searches the site itself applies price, size and most-recent order, so the run reads listings in that order across all pages (with maxListings 50 and price high to low you get the 50 most expensive). On loopnet.com for-lease searches the site applies most recent and rent order; size order is applied within each results page. On loopnet.co.uk and auction searches the order is applied within each results page only.
minCapRatenumber(none)For-sale searches on loopnet.com. Only listings with a published cap rate at or above this percentage, e.g. 5.5.
maxCapRatenumber(none)For-sale searches on loopnet.com. Only listings with a published cap rate at or below this percentage.
keywordstring(none)Search mode on loopnet.com. Free-text keyword the site matches against the listing text, e.g. "parking" or "drive-in".
listedInLastDaysinteger(none)Only listings put on the market within this many days. loopnet.com applies it site-side (search mode and pasted loopnet.com results URLs), so every page already matches. loopnet.co.uk applies it to the "Date on Market" each results card prints; cards without a date are left out. Leave empty for all dates.
portfolioFilterstringincludeFor-sale searches on loopnet.com. Include multi-property portfolio sales (default), show only them, or leave them out.
condosFilterstringincludeFor-sale searches on loopnet.com. Include condo units (default), show only condos, or leave them out.
subTypestringanyloopnet.com for-sale searches only. Narrows the search to one property sub-type the site lists: warehouses, data centers, flex, cold storage, medical offices, strip malls, banks, gas stations, hotels, self-storage, mobile home parks, farms and more (51 in all). It replaces the property type (each sub-type belongs to one). The site has no sub-types for lease, auction or loopnet.co.uk searches, so it is ignored there with a warning.
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.
splitLargeSearchesbooleanfalseloopnet.com lists at most 750 results for one search (see "Supported URL shapes" above). When a for-sale search hits that cap and Max listings asks for more, walk it again in price bands (splitting any band that is still capped) to reach listings beyond the first 750. Listings with no published price fall in no band. Off by default.
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.
ignoreFieldsForChangesarray(none)Incremental mode only. Field names (or dotted nested paths like commercial.primaryImage, or commercial.*) to exclude from change detection. The field is still returned, it just never drives an UPDATED classification.
proxyobjectApify ResidentialConnection settings. Both loopnet.co.uk and loopnet.com work on Apify Residential out of the box (see "Plan Requirement" below); free plans have no Apify proxy and automatically fall back to a backup connection, so supply your own residential proxy URLs here for guaranteed access on any plan.
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 runs on the default Apify Residential proxy connection, which works for both loopnet.co.uk (UK / international) and loopnet.com (US / Canada); your own proxy URLs are optional. The actor requests pages with LoopNet's own mobile-app client profile: on 2026-10-13 pages were served on both Apify Datacenter and Residential connections on both sites, while a plain desktop-browser style request is refused on both. The default stays Residential, and LoopNet changes what it accepts from time to time, so a run can still be refused on some days. Free plans have no Apify proxy at all: if your plan's Apify Residential connection is refused, the run automatically continues on a backup connection instead of failing outright, and some pages may still be unavailable on that backup connection. For guaranteed residential access, upgrade your plan at apify.com/pricing or supply your own proxy URLs. Your own proxy URLs, or an explicitly disabled connection, are used exactly as given with no automatic backup. If a run ever does fail with a connection message, retry later or supply your own residential proxy URLs in the Connection field.

FAQ

How much does it cost?

You pay per listing returned, plus a small per listing surcharge for every listing enriched with a detail-page fetch. That happens whenever fetchDetails is on, and also for a pasted individual listing URL even with fetchDetails off, since there is no results-page card to fall back on for a single pasted listing (see "Supported URL shapes" above). 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.

Are there limitations I should know about?

No login or paywall gates any field this actor reads - everything documented above is public. Several filters are sale-only or lease-only and say so in their own description: minCapRate/maxCapRate/priceType/keyword/portfolioFilter/condosFilter/subType apply to for-sale searches on loopnet.com only, auction listings exist on loopnet.com only (the UK site has no auction surface), and spaces (per-unit availability) only appears on lease listings. Pricing is sometimes withheld by the listing itself rather than by this actor: priceAvailability and commercial.financialsMasked/maskedFinancialFields tell you, per row, whether a figure was published at all.

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 Thailand Property & Projects
Scrape hipflat.co.th property listings and new-project data across Thailand: price, price...
🏨 Wego Scraper
Scrape Wego hotels by city or search URL. Get rates, providers, booking links...
🏨 Trip.com Hotels, Rooms & Reviews Scraper
Pull structured hotel listings from trip.com with prices, room types, amenities...
🏨 Expedia Hotels Scraper
From $1/1K. Scrape Expedia.com hotel listings and reviews for any destination. Extract...
🏨 Yanolja Scraper
Scrape Yanolja (NOL), Korea's largest accommodations marketplace, by region or URL. Every...
🏨 Hostelworld Scraper
Scrape Hostelworld hostels, hotels, guesthouses, B&Bs, apartments and campsites by city...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 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 contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.