Immowelt.de Scraper - Properties, Prices & Agent Contacts avatar

Immowelt.de Scraper - Properties, Prices & Agent Contacts

Pricing

from $0.80 / 1,000 results

Go to Apify Store
Immowelt.de Scraper - Properties, Prices & Agent Contacts

Immowelt.de Scraper - Properties, Prices & Agent Contacts

Scrape detailed property listings from Immowelt.de into clean structured data. Extract prices, GPS coordinates, rooms, living area, photos, energy class, property features, agent contact details, and more.

Pricing

from $0.80 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

5

Total users

0

Monthly active users

3 days ago

Last modified

Security

Limited permissions

Share

Immowelt Scraper: German Property Listings with Price, Agent & GPS Data

Immowelt Scraper turns immowelt.de into structured property data. Get price, price per m², rooms, living area, floor, energy class, full address, GPS coordinates, agent name, company, phone, website, rating, and a full image gallery for Buy and Rent listings across Germany. Search by state and city, paste a search URL you already refined in your browser, or monitor a saved search on a schedule and get back only what changed. Export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • 40+ fields per listing. Price, price per m², address, GPS coordinates, rooms, living area, floor, energy class, image gallery, agent name, company, phone, website, rating and more.
  • GPS coordinates on nearly every listing. Latitude and longitude are added automatically from Immowelt's own map data, on by default; very large searches (beyond roughly 2000 results) may have null coordinates on later listings.
  • Two ways to search. Pick a German state and city from dropdowns, or paste any Immowelt search URL you already refined in your browser.
  • Rich filter set. Price, rooms, living area, construction year and sort order, passed straight through to Immowelt so results match what the site itself would show.
  • Both Buy and Rent. Apartments, houses, plots and offices.
  • Auto pagination. Walks forward through every result page up to the limit you set, 30 listings per page.
  • Built for recurring monitoring. Incremental mode classifies each listing as new, updated, unchanged or gone since your last scheduled run, so a repeat search returns only what changed.

Use Cases

  • Real estate investors: track price per m² across cities and property types to find undervalued listings.
  • PropTech and market research teams: build a live feed of Buy and Rent listings with coordinates for mapping and comparison tools.
  • Relocation and rental agencies: monitor a specific city or filter combination for new listings the moment they appear, using a schedule with Incremental mode.
  • Lead generation: collect agent names, companies, phone numbers and websites from active listings for outreach.
  • Data teams: build historical datasets of price, size, energy class and location for pricing and valuation models.

Data You Get

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

FieldExample
id"26QPUH3FZ3H7"
urlImmowelt expose link for the listing
listingType"Buy" (also "Rent")
propertyType"APARTMENT" (also "HOUSE", "PLOT", "OFFICE")
title"Studio zum Kauf"
priceValue / priceDisplay545000 / "545.000 €"
pricePerSqm"12.520 €/m²"
rooms1
livingSpace43.5
floor"EG"
energyClass"C"
city / district / postcode"München" / "Altstadt-Lehel" / "80538"
latitude / longitude48.1344 / 11.5843 (added when GPS coordinates is on)
agentName / agentCompany"Frau Anna Beispiel" / "Beispiel Immobilien GmbH"
agentPhones / agentWebsite["+4989000000"] / agency website URL
agentRating / agentReviews4.3 / 47
imageCount13
imagesarray of full-size image URLs
hasFloorplan / has3DTourtrue / true
isNew / hasBrokerageFeefalse / false
origin"strict" (also "enlarged", "suggested", a filter-radius fallback)
creationDate / updateDateISO timestamps from Immowelt
changeType"NEW" / "UPDATED" / "UNCHANGED" / "REAPPEARED" / "EXPIRED". Only present when incrementalMode is on
scrapedAtISO timestamp of this scrape

Every listing also carries legacyId (Immowelt's internal id used to build the URL), plotArea (houses and plots only), addressPublished (whether Immowelt is showing the exact street), agentType (AGENCY or PRIVATE), agentAddress, and imagesAnnotated (each image URL paired with its room classification, such as kitchen or bathroom). Turning on Visit each listing's detail page additionally fills constructionYear, energyValue and the long description; without it these three stay null. In incremental mode, changedFields lists which fields changed since the last run, and firstSeenAt / lastSeenAt track when the listing first appeared and was last seen.

How to Use

  1. Pick a Search mode: Filter mode (state plus city from dropdowns) or URL mode (paste Immowelt search URLs).
  2. Fill in the fields for that mode: for Filter mode, one or more locations, Buy or Rent, property type, and any price, room, living space or construction year filters; for URL mode, paste one or more search URLs.
  3. Set Max total listings (and optionally Max pages per search) to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search by location:

{
"mode": "filter",
"locations": [
{ "state": "berlin", "city": "Berlin" }
],
"listingType": "Buy",
"propertyType": "Apartment",
"maxListings": 100
}

Search with filters:

{
"mode": "filter",
"locations": [{ "state": "bayern", "city": "München" }],
"listingType": "Buy",
"propertyType": "Apartment",
"priceMin": 400000,
"priceMax": 800000,
"roomsMin": 2,
"roomsMax": 3,
"livingSpaceMin": 50,
"livingSpaceMax": 100,
"sortBy": "PriceAsc",
"maxListings": 200
}

Direct URL with auto pagination:

{
"mode": "url",
"urls": [
"https://www.immowelt.de/classified-search?distributionTypes=Rent&estateTypes=Apartment&locations=AD08DE1113&numberOfRoomsMin=2&spaceMin=60"
],
"maxPages": 20
}

Recurring monitoring of a saved search:

{
"mode": "filter",
"locations": [{ "state": "berlin", "city": "Berlin" }],
"listingType": "Buy",
"propertyType": "Apartment",
"maxListings": 300,
"incrementalMode": true
}

The first run of this last example returns every listing as NEW. Schedule it and every later run instead returns only NEW and UPDATED listings for that same search, with UNCHANGED ones suppressed from the dataset by default.

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/immowelt-de-scraper").call(run_input={
"mode": "filter",
"locations": [{"state": "berlin", "city": "Berlin"}],
"listingType": "Buy",
"propertyType": "Apartment",
"maxListings": 100,
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["title"], listing["priceDisplay"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/immowelt-de-scraper').call({
mode: 'filter',
locations: [{ state: 'berlin', city: 'Berlin' }],
listingType: 'Buy',
propertyType: 'Apartment',
maxListings: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

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

URL mode: supported URL shapes

URL mode with the urls field left untouched now scrapes the three example URLs below (one per supported shape) instead of doing nothing. Replace or clear the list to scrape your own searches.

ShapeExampleBehaviour
Search path (/suche/<kaufen or mieten>/<type>/<state or city>/<place>/<id>)https://www.immowelt.de/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634Supported. The page is read and its search is carried over as a query search: place, every listed offer type (including auctions), property types and every other filter the page echoes back (project types, sub-types, furnished, features, build state, energy class, price, rooms, space and year ranges). All result pages are walked. The run compares the result count of the query search with the count shown on your page and logs a warning when they differ; paste the /classified-search URL from your browser to scrape an exact set. Sorting and any option the page does not echo are not carried over.
Older plural slug (/suche/<city>/wohnungen/mieten)https://www.immowelt.de/suche/berlin/wohnungen/mietenSupported. The site redirects it to the search path above and the redirect is followed.
Query search (/classified-search?...)https://www.immowelt.de/classified-search?distributionTypes=Buy&estateTypes=Apartment&locations=AD08DE8634Supported, including &page=N.
Single listing (/expose/<id>)https://www.immowelt.de/expose/<id>Skipped with a warning. Turn on listing details to get full listing pages from a search.
Mobile host (m.immowelt.de)https://m.immowelt.de/Skipped with a warning. The mobile host has no pages.

If none of the URLs can be used, or no Filter-mode city name matches, the run fails with a clear message instead of finishing empty.

Locations and disambiguation

The state is what tells same-named towns apart: Germany has several towns sharing a name, so { "state": "bayern", "city": "Neustadt" } and { "state": "sachsen", "city": "Neustadt" } resolve to two different towns and return two different result sets. When a state has more than one town matching what you typed, the closest match is used and the full resolved name is written to the run log, so you can see exactly which one you got.

Max pages, max listings, and resuming a full-catalogue walk

Max pages per search and Max total listings cap a single run. Leave Max pages per search empty to walk every result page; Max total listings defaults to a hard cap of 20, and 0 removes it (still bounded by Max pages if that is set).

For an unbounded pull, two things protect a long run:

  • resumeFromRunId lets you continue in a brand-new run: paste the ID of a previous run (or its dataset), and this run skips every id already saved there, appending only new listings.
  • A checkpoint is saved automatically as the run progresses. If the run is interrupted by an Apify platform migration, or you click Resurrect on a failed run, it picks back up from where it left off in the same run, without re-saving already-collected listings. No input is needed for this; it is automatic.

Resume and incremental mode

These are two different features that both sound like "continue a search":

  • Resume (resumeFromRunId) continues ONE interrupted crawl. Paste a previous run or dataset ID and this run only adds listings it has not already saved there.
  • Incremental mode (incrementalMode) is for a search you run again and again on a schedule. The actor remembers its own baseline in its own storage, keyed by stateKey (or auto-derived from the search scope), and classifies every scraped listing as NEW, UPDATED (with changedFields), or UNCHANGED (suppressed from the dataset and not billed unless emitUnchanged is on). Every field of the listing row is compared except scrapedAt, isNew (a freshness flag that flips by itself over time) and any field you list in ignoreFieldsForChanges; ignored fields stay in the output and are left out of the comparison and changedFields. Nested fields use dots (imagesAnnotated.description), and changing the list never causes a one-time wave of UPDATED rows. A listing is only classified EXPIRED once a run reaches the natural end of that search's results with emitExpired on; a run capped by Max total listings or Max pages, one that starts from a pasted URL with page=N above 1, or one continuing via resumeFromRunId, skips EXPIRED detection, since it never proved the listing is actually gone. REAPPEARED only happens to a listing that was previously marked EXPIRED on an earlier complete scan and is then found again; it is not something that happens "by default" on an ordinary recurring run where nothing was ever marked expired.
  • Combining incrementalMode with resumeFromRunId is only supported to bootstrap the very first incremental run from a prior full-catalogue crawl. Once a baseline exists for a state key, the run fails fast asking you to remove resumeFromRunId or pick a different stateKey.

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 haven't 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
modestringfilterFilter mode (state plus city dropdowns) or URL mode (paste search URLs).
locationsarrayno default (prefill: state berlin, city Berlin)Locations to search. Filter mode only.
listingTypestringBuyBuy or Rent. In Filter mode this builds the search. In URL mode it never filters: the value is read from each pasted URL when the URL states one, and this field is only the fallback label for URLs that do not.
propertyTypestringApartmentApartment, House, Plot, or Office. Filter mode only.
priceMinintegerno defaultMinimum price in EUR. Filter mode only. Leave empty for no minimum.
priceMaxintegerno defaultMaximum price in EUR. Filter mode only. Leave empty for no maximum.
roomsMinintegerno defaultMinimum number of rooms. Filter mode only.
roomsMaxintegerno defaultMaximum number of rooms. Filter mode only.
livingSpaceMinintegerno defaultMinimum living area in m². Filter mode only.
livingSpaceMaxintegerno defaultMaximum living area in m². Filter mode only.
constructionYearMinintegerno defaultEarliest construction year. Filter mode only.
constructionYearMaxintegerno defaultLatest construction year. Filter mode only.
sortBystringDefaultSort order for results. Filter mode only; in URL mode the sort is taken from your URL.
urlsarraythree example search URLs (one per supported shape)One or more Immowelt search URLs. URL mode only. If a URL contains page=N, scraping starts at page N and walks forward. Leaving the field untouched in URL mode scrapes these three examples.
maxPagesintegerno default (empty = walk every result page)How many result pages to walk per location or URL, 30 listings per page. Applies to both modes.
maxListingsinteger20Hard cap across the whole run. 0 = unlimited, still bounded by Max pages if set.
includeCoordinatesbooleantrueAdd latitude and longitude to each listing. Minimal overhead: about one extra request per search page.
fetchDetailsbooleanfalseVisit each listing's detail page for the long description and a couple of extra fields; multiplies proxy bandwidth roughly tenfold, so leave it off unless you need the long description. Each expose page that loads bills the detail-enrichment event (Pricing tab).
proxyobjectno default (prefill: Apify RESIDENTIAL, country DE)Connection settings. A German residential proxy gives the cleanest data.
mcpConnectorsarrayno defaultOptional: send a summary of each listing to apps you authorized under Integrations.
notionParentPageUrlstringno defaultNotion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.
resumeFromRunIdstringno defaultA previous run ID or dataset ID to continue a full-catalogue walk across separate runs.
incrementalModebooleanfalseRecurring monitoring of the same search: classify every listing as NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED against this actor's own remembered baseline.
ignoreFieldsForChangesarray[]Incremental mode only: field names (dots for nested) that never count as a change. scrapedAt and isNew are always ignored.
stateKeystringno defaultManually name the incremental baseline. Leave empty to auto-derive one from the search scope.
emitUnchangedbooleanfalseAlso save UNCHANGED listings to the dataset. Returns and bills every listing every run.
emitExpiredbooleanfalseAlso save an EXPIRED row for a previously tracked listing that no longer appears, once a run reaches a complete scan.

Output Example

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

{
"id": "EXAMPLE0001",
"legacyId": "00000000-0000-0000-0000-000000000000",
"url": "https://www.immowelt.de/expose/00000000-0000-0000-0000-000000000000",
"listingType": "Buy",
"origin": "strict",
"propertyType": "APARTMENT",
"title": "Studio zum Kauf",
"priceValue": 545000,
"priceCurrency": "EUR",
"priceDisplay": "545.000 €",
"pricePerSqm": "12.520 €/m²",
"rooms": 1,
"livingSpace": 43.5,
"plotArea": null,
"floor": "EG",
"constructionYear": null,
"energyClass": "C",
"energyValue": null,
"country": "DEU",
"city": "München",
"district": "Altstadt-Lehel",
"postcode": "80538",
"street": null,
"latitude": 48.1344,
"longitude": 11.5843,
"addressPublished": false,
"agentName": "Frau Anna Beispiel",
"agentCompany": "Beispiel Immobilien GmbH",
"agentType": "AGENCY",
"agentPhones": ["+4989000000"],
"agentWebsite": "https://www.example-immobilien.de/",
"agentProfileUrl": "https://www.immowelt.de/profil/0000000000000000000000000000",
"agentRating": 4.3,
"agentReviews": 47,
"agentAddress": "Beispielstraße 1, 80331 München",
"imageCount": 2,
"images": ["https://mms.immowelt.de/3/c/e/b/sample1.jpg", "https://mms.immowelt.de/e/a/d/d/sample2.jpg"],
"hasFloorplan": true,
"has3DTour": true,
"hasBrokerageFee": false,
"isExclusive": false,
"isNew": false,
"creationDate": "2026-04-13T10:41:40.410Z",
"updateDate": "2026-04-13T10:41:54.893Z",
"description": null,
"scrapedAt": "2026-04-21T08:45:02.602Z"
}

Plan Requirement

The default connection setting is Apify Residential, country DE, and it is the recommended one: immowelt.de protects its query-search pages (/classified-search) and single listing pages (/expose/...) with a bot check, and those need a residential connection. The older /suche/... search pages are open and can also be read on a non-residential connection, but do not rely on that for the other shapes. If your Apify plan does not include residential proxy access, the run logs "Apify free plans do not include residential proxies" and continues on a backup connection; pages the backup connection cannot load stay unavailable, and the run fails rather than finishing empty (see the FAQ). You can also uncheck "Use Apify proxy" under Proxy & connection and paste your own proxy URLs (they are used as given, with no backup connection). The Pricing tab shows the current rates.

FAQ

How much does it cost?

You pay per listing returned. The Pricing tab shows the current rates. Use Max total listings to cap the cost of any run, and leave fetchDetails off unless you need the long description, since it multiplies the work per listing.

With fetchDetails on, every listing whose expose page loads also bills the actor's detail-enrichment event — its price is on the Pricing tab. Listings whose expose page could not be read ship with the search-page fields and are never billed for it, and rows suppressed as unchanged by an incremental (scheduled) run are not billed for it either.

This actor collects only publicly available property listing data. You are responsible for how you use it: follow immowelt.de's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price, rooms and address are generally not protected, but photos and agent branding 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 mode. Each run then returns only new and updated listings for that search, and unchanged ones are suppressed from the dataset (and not billed) unless you turn emitUnchanged on.

What's the difference between Resume and Incremental mode?

They solve different problems. Resume (resumeFromRunId) continues ONE interrupted full-catalogue crawl: paste the ID of an earlier run and this run only adds listings it has not already saved there. Incremental mode (incrementalMode) is for a search you run again and again on a schedule: it remembers its own baseline and reports only what is new, updated, or gone since the previous scheduled run. Use one or the other, not usually both; combining them is only supported to bootstrap the very first incremental run from a prior full crawl.

What happens when immowelt.de blocks every request?

A run that could not load a single results page ends as Failed with a status message, never as Succeeded with an empty dataset. The messages are:

  • Account without proxy access: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required."
  • Free plan, backup connection could not load the pages: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Immowelt pages."
  • Any other case: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

If the plan has no residential access the log also shows a boxed warning ("The selected connection is unavailable to this run ... Continuing on a backup connection; some pages may still be unavailable."), and when the backup connection serves a page it logs "Served over the backup connection (the default connection was unavailable)." If some pages load and others are blocked, the actor keeps what it collected and logs which pages were skipped. A search that loads fine but matches nothing new finishes as Succeeded with no rows.

Which dataset views are available?

Three: Listings (overview), Details & agent, and Changes (incremental), which shows changeType and changedFields. A summary of the run is also saved under the OUTPUT key of the run's key-value store.

What does incremental mode ignore?

scrapedAt and isNew never count as a change. Add more field names (dots for nested) to ignoreFieldsForChanges to ignore other noisy fields; the baseline is then compared on the remaining fields.

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 real estate data?

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

🏠 ImmobilienScout24.de Scraper
Extract property listings from immobilienscout24.de, Germany's #1 real estate platform...
🏠 SeLoger Scraper
Scrape SeLoger.com properties for sale and rent. Search by location with price, room and...
🏠 Fotocasa.es
Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths...
🏠 Pap.fr
Extract property listings from pap.fr. Get fully-detailed listings with price, address...
🏠 Funda in Business Scraper
Scrape Funda in Business commercial listings: offices, retail, industrial, catering and...
🏠 Otodom.pl Scraper
Scrape Otodom.pl properties for sale and rent, including apartments, houses, plots...

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