Funda in Business Scraper - Commercial Property & Agents
Pricing
from $1.00 / 1,000 property scrapeds
Funda in Business Scraper - Commercial Property & Agents
Scrape Funda in Business commercial listings: offices, retail, industrial, catering and more. Full detail pages, pricing, floor areas, energy labels, coordinates, images, and agent/agency contacts with ratings. Dual search and URL modes, deep filters, and forward pagination.
Pricing
from $1.00 / 1,000 property scrapeds
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
3
Monthly active users
13 days ago
Last modified
Categories
Share
Funda in Business Scraper: Commercial Property Listings & Agent Contacts
Funda in Business Scraper turns fundainbusiness.nl into structured data for the Dutch commercial property market. Get offices, retail units, industrial halls, catering venues, practice spaces, building plots and investment objects, each with pricing, floor area, energy label, map coordinates, a full photo set, and the listing agent and agency, including agency ratings and reviews when you opt in. Search by city and filters, or paste your own listing and search-result URLs, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Dual input modes. Search mode builds listing URLs from location and filter fields. URL mode scrapes the listing or search-result links you already have.
- Deep filters. Property category, buy or rent, price and area ranges, energy label, construction period, surrounding context, building features, parking, publication date, auction and open day windows, and nine sort orders.
- Full detail-page enrichment. Complete description, every characteristic grouped by section (transfer, construction, areas, layout, energy), map coordinates, all photos and the listing agent's phone number.
- Agency profiles with reviews. Opt in to add each listing's agency contact details, address, employee count, average rating and individual reviews.
- Rich nested output. Pricing, location, property characteristics, media and agency relationships come back as one structured record, not a flat row.
- Built for schedules. Incremental mode tracks a search over time and returns only new and changed listings on recurring runs, and a rejected run fails loudly instead of returning an empty dataset.
- Optional app export. Pipe results into Notion, Linear, Airtable or Apify through MCP connectors after the scrape.
Use Cases
- Commercial brokers and agencies: track competing listings and new inventory across Dutch cities to spot pricing and availability trends.
- Investors and asset managers: build a searchable database of office, retail, industrial and investment properties with pricing, area and location for deal sourcing.
- Market research and PropTech: monitor supply, energy labels and construction periods across the commercial market for reports and models.
- Lead generation: collect listing agent and agency contact details, plus agency ratings, for outreach.
- Recurring monitoring: schedule the actor with Incremental mode to catch only new and updated listings in a target market without re-downloading everything each run.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
record_id | "00000001" |
entity.title | "Sample Street 1, Amsterdam" |
entity.description | "Full listing description..." |
entity.category | "Office" |
listing.deal_type | "rent" |
listing.is_featured | false |
listing.available_from | "Per direct beschikbaar" |
pricing.price / pricing.price_text | 3250 / "EUR 3.250 /mnd" |
pricing.currency | "EUR" |
property.property_type | "office" |
property.usage_types | ["Office", "Retail"] |
property.floor_area | 98 |
property.energy_label | "A" |
property.construction_year | "2020" |
location.city / location.region | "Amsterdam" / "Noord-Holland" |
location.latitude / location.longitude | 52.0000 / 4.0000 |
media.image_count | 6 |
media.image_urls | array of photo URLs |
relationships.agency.name | "Sample Brokers" |
relationships.agency.phone | "+310000000000" |
relationships.agency.email | "agent@example.com" (agency enrichment on) |
relationships.agency.reviews.average_score | 8.6 (agency enrichment on) |
source_context.source_url | listing detail page URL |
source_context.enrichment_status | "enriched" or "basic" |
Every record also carries a property block with construction_type and features (the full grouped characteristics from the detail page), an availability block with status and available_from, and an attributes.kenmerken_summary with the raw search-card characteristics. With agency enrichment on, relationships.agency also carries address, description, employee_count, and the full employees and reviews.latest lists.
How to Use
- Pick a mode:
search(filters) orurl(paste links). - Fill in the fields for that mode: locations and filters for search, or listing and search-result URLs for URL mode.
- Turn on Fetch full detail pages and Include agency profile and reviews for full enrichment, or leave them off for a lighter run.
- Set Max items to control run size and cost, then click Start.
Search a city for offices for rent, cards only:
{"mode": "search","locations": ["Amsterdam"],"propertyType": "office","dealType": "rent","maxItems": 50,"fetchDetails": false}
Search with deep filters and full enrichment:
{"mode": "search","locations": ["Rotterdam", "Utrecht"],"propertyType": "retail","dealType": "buy","minPrice": 100000,"maxPrice": 2000000,"minArea": 80,"energyLabel": ["a", "b", "c"],"sortBy": "sale_price","fetchDetails": true,"includeAgencyDetails": true,"maxItems": 100}
Scrape from URLs (multiple, paginated):
{"mode": "url","urls": ["https://www.fundainbusiness.nl/kantoor/amsterdam/","https://www.fundainbusiness.nl/winkel/rotterdam/"],"maxPages": 5,"maxItems": 100,"fetchDetails": true}
Track a search on a schedule, only changes each run:
{"mode": "search","locations": ["Amsterdam"],"propertyType": "office","incrementalMode": true}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/fundainbusiness-nl-commercial-property-scraper").call(run_input={"mode": "search", "locations": ["Amsterdam"], "propertyType": "office"})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["entity"]["title"], listing["pricing"]["price_text"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/fundainbusiness-nl-commercial-property-scraper').call({mode: 'search',locations: ['Amsterdam'],propertyType: 'office',});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Which filters apply in which mode
Every filter from Property type down to Sort by is posted to the Funda in Business search form, so it only narrows results in search mode. URL mode never sends that form and ignores them. Only highlighted listings is the exception: Funda in Business has no server-side option for it, so the run applies it to every result page it walks, which means it also narrows a search-result URL you pasted in URL mode. A pasted single-listing URL is scraped directly and is never dropped by this filter.
Property type and Buy or rent do one extra thing in both modes: their values are copied onto every record as labels (property.property_type, source_context.search.property_type, source_context.search.deal_type, and the listing.deal_type fallback used when a listing's price text does not say whether it is for sale or for rent). In URL mode they label the output without filtering it, so leave them at their defaults there unless you want that label.
Resume and recurring updates
There are two different things here, pick the one that matches what you are doing:
- A crawl stopped partway through and should continue: use Resume from a previous run (
resumeFromRunId). Paste a run or dataset ID and this run skips listings already collected there, returning only what is left, so you never pay twice for the same crawl. An unreadable ID fails the run with a clear message instead of silently re-scraping and re-billing everything. - Run the same search on a schedule and get only the changes: turn on Incremental changes for scheduled runs (
incrementalMode). The actor remembers the previous run of the same search by itself, so you never paste an ID. The first run for a search returns every listing asNEW. Later runs return onlyNEWandUPDATEDlistings by default, withchangedFieldslisting what changed on anUPDATEDrow. Listings that are unchanged are suppressed and not charged unless you turn on Emit unchanged listings. Classification happens after any detail-page enrichment, so a change visible only on the detail page still gets caught. REAPPEAREDandEXPIREDare a pair, and neither is part of the everyday default flow.EXPIREDis only produced once a run has fully scanned the tracked search with Emit expired listings turned on, never when Max items capped the run and never on a resumed run. A listing only comes back asREAPPEAREDon a later run if one of those complete scans had already marked itEXPIREDand it then shows up again. If you never turn on Emit expired listings, a listing that temporarily disappears and reappears is simply classifiedUNCHANGEDorUPDATEDlike any other listing, neverREAPPEARED.- State is kept separately per mode, location or URL set, and filter setup, automatically. Set State key to name or deliberately share a monitoring campaign; leave it empty and the actor derives one for you.
Send results into your apps (MCP connectors)
You can optionally pipe each run's results into the apps you already use through 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 listing, a title plus its key fields (price, area, energy label, city, agency and phone) flattened to plain text, not the full JSON. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify then Settings then API & Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the Pipe results into your apps input field. If the picker is empty, you have not authorized a connector yet.
- For Notion, also set Notion parent page (
notionParentPageUrl) to the page where item pages should be created.
Leave the field empty to skip; it never changes the dataset output.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search builds URLs from filters; url scrapes pasted links. |
locations | array | none (prefill: Amsterdam) | Cities, towns or areas to search (search mode). Each becomes a separate search; left empty, the run searches all of the Netherlands. |
propertyType | string | all | Commercial category, for example office, retail, catering. Filters only in search mode; also copied onto every record as a label in both modes. |
dealType | string | both | Buy, rent, or both. Filters only in search mode; also copied onto every record as a label, and as the price-text fallback, in both modes. |
keyword | string | none | Optional free-text term to narrow results (search mode only). |
minPrice | integer | none | Lowest price or rent (search mode). For rent, read together with Rent price basis. |
maxPrice | integer | none | Highest price or rent (search mode). |
rentPriceBasis | string | per_month | How rent price bounds are applied: per month, per year, or per square metre. |
minArea | integer | none | Smallest floor area in square metres (search mode). |
maxArea | integer | none | Largest floor area in square metres (search mode). |
publicationDate | string | any | Only listings published within this window (search mode). |
surrounding | array | none | Filter by the type of area the property sits in, for example town centre or office park (search mode). |
amenities | array | none | Require one or more building features (search mode). |
availability | array | none | Filter by availability signals, for example available now or turnkey (search mode). |
parking | string | any | Minimum parking capacity (search mode). |
constructionType | string | any | Existing or new construction (search mode). |
propertyAge | array | none | Construction period buckets (search mode). |
energyLabel | array | none | Energy labels A to G (search mode). |
auctionDate | string | any | Upcoming auction window (search mode). |
openDay | string | any | Open day availability (search mode). |
includeSoldRented | boolean | false | Also include historical listings already sold or rented (search mode). |
sortBy | string | relevance | Result ordering; nine options (search mode). |
urls | array | none (prefill: https://www.fundainbusiness.nl/kantoor/amsterdam/) | Funda in Business listing or search-result URLs to scrape (URL mode). |
highlighted | boolean | false | Only featured listings. Applies in both search mode and URL mode, except a pasted single-listing URL. |
resumeFromRunId | string | none | Continue one specific interrupted or previous run; listings already collected there are skipped. |
incrementalMode | boolean | false | Turn on for scheduled runs of the same search; classifies each listing as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. |
stateKey | string | none | Optional name for a monitoring campaign; auto-derived from your mode, location or URL and filter settings when left empty. |
emitUnchanged | boolean | false | Incremental mode only. Also return, and bill, listings unchanged since the last run. |
emitExpired | boolean | false | Incremental mode only. Also return, and bill, listings from a previous run no longer found, once a run fully scans the tracked search. |
language | string | nl | Language of the listing pages, Dutch or English. |
fetchDetails | boolean | true | Include the full description, all characteristics, coordinates, all images and the agent phone for each listing. |
includeAgencyDetails | boolean | false | Enrich each listing's agency with contact details, address, ratings and reviews from its profile page. |
maxItems | integer | 20 | Maximum listings to return across the whole run; the single cap; set 0 for unlimited. |
maxPages | integer | 200 | Safety ceiling on result pages walked per search; leave at the default, the run stops at Max items. |
proxy | object | Apify Proxy (automatic) | Connection settings. The default works automatically; you can pin a specific country if needed. |
mcpConnectors | array | none | Optional: send a summary of each listing to apps you authorized under Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap 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.
{"record_type": "property_listing","record_id": "00000001","source_context": {"source_domain": "fundainbusiness.nl","source_url": "https://www.fundainbusiness.nl/kantoor/amsterdam/object-00000001-sample-street-1/","enrichment_status": "enriched","page_number": 1,"position": 1,"scraped_at": "2026-01-01T00:00:00+00:00","language": "nl","country": "NL"},"entity": {"title": "Sample Street 1, Amsterdam","description": "Full listing description appears here when Fetch full detail pages is on.","url": "https://www.fundainbusiness.nl/kantoor/amsterdam/object-00000001-sample-street-1/","category": "Office"},"listing": {"deal_type": "rent","is_featured": false,"source_category": "Kantoor","available_from": "Per direct beschikbaar"},"pricing": { "price": 3250, "currency": "EUR", "price_text": "EUR 3.250 /mnd" },"location": { "city": "Amsterdam", "region": "Noord-Holland", "latitude": 52.0000, "longitude": 4.0000 },"property": { "property_type": "office", "floor_area": 98, "energy_label": "A", "construction_year": "2020" },"media": { "image_count": 6, "image_urls": ["https://cloud.funda.nl/valentina_media/000/000/000_1440x960.jpg"] },"relationships": {"agency": {"name": "Sample Brokers","url": "https://www.fundainbusiness.nl/makelaar/0000-sample-brokers/","phone": "+310000000000","email": "agent@example.com","reviews": { "total": 2, "average_score": 8.6, "formatted_average_score": "8,6" }}}}
Plan Requirement
This actor runs on any Apify plan. The default connection setting works automatically, and a run escalates to a more reliable connection tier on its own when requests are rejected. For larger or frequent monitoring, pinning the residential proxy group under Connection can help; select it there if needed.
FAQ
How much does it cost?
Each returned listing is billed as a dataset item, and each listing whose full detail page was actually fetched and returned adds a detail-enrichment charge. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.
Is it legal to scrape Funda in Business?
This actor collects only publicly available property listing data. You are responsible for how you use it: follow Funda in Business's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing photos and agency information may be subject to third-party rights.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental changes for scheduled runs. Each run then returns only new and updated listings by default, and unchanged ones are not billed.
What is the difference between Resume and Incremental mode?
Resume from a previous run continues one specific interrupted crawl from a pasted run or dataset ID and never repeats what that run already collected. Incremental changes for scheduled runs is for running the same search again and again, for example daily, without pasting anything: the actor remembers the previous run itself and returns only what changed. Use Resume after an interruption, and Incremental mode for ongoing monitoring.
Why did my run fail instead of returning an empty dataset?
If every page fetch for a search was rejected, the run stops with a clear message instead of quietly returning zero listings, so "no listings match this search" is never confused with "nothing could be read." Run it again in a few minutes. In URL mode, a pasted listing URL that comes back as a clean 404 is treated as a normal outcome, the listing was removed or sold, not a failure; only fetches that exhaust every retry count toward that failure message.
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 listing summaries into Notion, Linear or Airtable.
๐ Want more real estate data?
Pair this actor with these related scrapers from the same team:
| ๐ CommercialGuru SG Property Listings & Agent Contacts Scraper Scrape commercialguru.com.sg Singapore listings at scale. Extract prices, PSF, floor... | ๐ Marktplaats.nl Scraper From $1/1K. Scrape Marktplaats.nl listings by keyword or URL. Extract title, price... |
| ๐ Immowelt.de Scraper Scrape detailed property listings from Immowelt.de into clean structured data. Extract... | ๐ Fotocasa.es From $1/1K. Scrape Spain property listings from fotocasa.es. Get price, surface, rooms... |
| ๐ Homely.com.au Scrape Homely.com.au properties for sale, rent, and sold, plus agent finder, suburb... | ๐จ LoopNet From $1.2/1K. Scrape LoopNet across the US including office, retail, industrial... |
๐ Browse all abotapi scrapers
๐ฌ Support & custom scrapers
- ๐ Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- ๐ ๏ธ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- โญ Enjoying it? A quick review on the actor page helps other users find it.