immowelt Scraper
Property offers from immowelt.de and immowelt.at as clean JSON: price, price per m², rooms, living and plot area, energy class, condition, district...
Property offers from immowelt.de and immowelt.at as clean JSON: price, price per m², rooms, living and plot area, energy class, condition, district, photos; expose pages add year built, costs and features. Agency or private as a flag; contact data never collected. Pay per result.
$3.00 / 1,000 · Recently published - building its public record.
Run it on Apify → Free to try - runs bill per result on your own account.
What you give it
Every field is optional unless marked; sensible defaults do the rest.
| Field | Type | What it does | Default |
|---|---|---|---|
location |
string | The town, district or postcode to search: berlin, muenchen, frankfurt-am-main, berlin-koepenick, 10115, wien (with country at). Umlauts are written out for you. A search address copied from the site works too. Leave it out only when you re-check offers through listingIds. |
berlin |
country |
string | immowelt.de for Germany or immowelt.at for Austria. The columns are the same on both. | de |
offerType |
string | Offers for sale or for rent. | buy |
propertyTypes |
array | Apartments, houses, plots of land, or any mix. Defaults to apartments and houses. | ["apartment", "house"] |
listingIds |
array | Re-check offers you already know instead of searching: one per line, as the id at the end of the offer address (the exposeId of every dataset item), the Online-ID shown on the page (the listingId), or the offer's full address. Each one is read from its own page, so it carries the full description, the energy data, the costs and the feature list. An offer that is gone from the site is skipped, named in the log and not billed. When given, the search fields of this form are ignored and the run status says which; country still picks the site. Up to 50. |
[] |
priceMinEur |
integer | Only include offers priced at least this many euros (the purchase price, or the rent). | - |
priceMaxEur |
integer | Only include offers priced at most this many euros. | - |
roomsMin |
number | Only include offers with at least this many rooms. | - |
roomsMax |
number | Only include offers with at most this many rooms. | - |
livingAreaMinSqm |
integer | Only include offers with at least this living area in square metres. | - |
livingAreaMaxSqm |
integer | Only include offers with at most this living area in square metres. | - |
sortBy |
string | Order of results: newest (best for monitoring), price_asc, price_desc, or relevance (the site's own order). | newest |
maxItems |
integer | Stop after this many offers. Free-plan runs are capped at 5 items. The form starts at 25 for a cheap first run - that is the form's prefill, not a cap on your plan; clear it to use the default of 1000. The site serves every page of a query, so a whole town comes through when you raise it. | 1000 |
scrapeDetails |
boolean | The search card carries the price, rooms, area, floor, energy class, condition and a trimmed description. Turn this on to read each offer's own page for the full description, the location text, year built, heating, energy source and certificate, commission, running costs, the feature list, the agency's reference number and the site's own price-per-m² comparison for the area. One extra request per offer, so a run is slower. Agency names, contact persons, phone numbers, streets and coordinates are never read. | False |
reportFailures |
boolean | When a run fails, send the developer the actor name and build, an error category, the error message (truncated) and a one-way hash of your input - so a bug can be fixed without anyone asking you to reproduce it. Your input itself, your results and your identity are never sent, and successful runs send nothing at all. Switch this off and the actor behaves exactly the same. | True |
What you get back
One JSON object per result, with exactly these fields - no seller identities, no contact data, ever.
| Field | Type | Meaning |
|---|---|---|
listingId |
string | The site's Online-ID of the offer, shown on its page. |
exposeId |
string | The id in the offer's address. |
url |
string | Direct link to the offer. |
title |
string | The offer kind as the site titles it. |
headline |
string | The seller's headline. |
description |
string | The seller's description: trimmed on search rows, full text with Fetch expose pages or listingIds. |
offerType |
string | For sale or for rent. |
propertyType |
string | apartment, house or land. |
offerSubType |
string | The site's sub type: resale, new_build, and so on. |
priceCents |
integer | Purchase price or monthly rent in euro cents. |
currency |
string | Always EUR when a price is present. |
priceDisplay |
string | The price as the site displays it. |
pricePerSqmCents |
integer | Price per square metre in euro cents, as the site computes it. |
rooms |
number | Number of rooms. |
livingAreaSqm |
number | Living area in square metres. |
plotAreaSqm |
number | Plot area in square metres, houses and land. |
floor |
string | Floor as the site states it, e.g. EG, 1/3, 3. |
availability |
string | Availability as the site states it. |
energyClass |
string | Energy efficiency class. |
condition |
string | Condition of the property: the site's code on search rows (well_kept, need_of_renovation, ...), its label on expose pages. |
brokerageFee |
boolean | Whether a brokerage fee applies to the buyer. |
newBuildProject |
boolean | Whether the offer is part of a new-build project. |
postedAt |
string | When the offer was created (ISO timestamp). |
updatedAt |
string | When the offer was last updated. |
status |
string | The site's own status, e.g. published. |
countryCode |
string | DE or AT. |
postcode |
string | Postcode of the property. Municipality-level only: street and coordinates are never collected. |
city |
string | Town of the property. |
district |
string | District when the site names one. |
sellerType |
string | Whether the offer comes from an agency or a private owner. The only seller-related field in the output. |
imageUrls |
array | Photos of the offer, in the site's order. |
locationDescription |
string | The seller's text about the location. Expose pages only. |
additionalInfo |
string | The seller's further information. Expose pages only. |
yearBuilt |
integer | Year of construction. Expose pages only. |
heating |
string | Heating system as the site labels it. Expose pages only. |
energySource |
string | Energy source as the site labels it. Expose pages only. |
energyCertificate |
object | The energy certificate's fields as the site labels them (type, validity, source, ...). Expose pages only. |
commissionFee |
string | Buyer's commission as the site states it. Expose pages only. |
additionalCosts |
object | Running costs by label, e.g. Hausgeld. Expose pages only. |
features |
array | Feature list as the site labels it. Expose pages only. |
reference |
string | The agency's reference number for the offer. Expose pages only. |
areaPricePerSqmAverage |
number | The site's average price per m² for comparable offers in the area, in euros. Expose pages only. |
areaPricePerSqmLow |
number | The low end of that comparison, in euros. |
areaPricePerSqmHigh |
number | The high end of that comparison, in euros. |
Health
Recently published - building its public record. Live record, failures included: status page.
Full documentation, examples and the AI-assistant prompt live on the store page.
Questions
Is scraping immowelt legal?
This is not legal advice. The actor reads what any logged-out visitor sees on immowelt.de and immowelt.at, with no login, no CAPTCHA solving and no private endpoints, and it extracts no agency name, contact person, phone number, street or coordinates, so the output holds no personal data. Whether your own use of the offers is allowed under the site's terms and your jurisdiction's rules is yours to assess.
Which locations can I search?
Any town, district or postcode the site knows, in Germany on immowelt.de and in Austria on immowelt.at: berlin, muenchen, frankfurt-am-main, berlin-koepenick, 10115, wien, graz. Umlauts are written out for you, and a search address copied from the site works as well. An unknown place fails before the run starts, with the spelling rules in the message.
Can I get only the newest offers?
Sort by newest, keep maxItems to a page or two and schedule the run: each run returns the latest offers for the place, offer type, property types and filters you set, and every row carries postedAt and updatedAt, so a daily watch is one schedule away.
How much do 10,000 offers cost?
$30.00, billed per delivered offer at $3.00 per 1,000. That price covers the run's platform usage, and a run that fails or returns nothing bills nothing beyond the actor start.
Do I need residential proxies for immowelt?
No setup on your side: the site answers only consumer networks, so the actor's default proxy is already an Apify residential proxy, and the per-result price covers it. Leave the proxy setting as it is.
Does it return agent or owner phone numbers?
No. The only seller field is whether the offer comes from an agency or a private owner. Agency names, contact persons, phone numbers, streets and coordinates are never extracted, and a test on every build fails if one ever appears, so this is not a setting that can be switched off.
What does the expose page add?
Every search row carries the price, the price per square metre, rooms, living and plot area, floor, availability, energy class, condition, posting and update time, postcode, city, district and photos. Turn on scrapeDetails, or name offers in listingIds, and each row also carries the full description, the location text, year built, heating, energy source and certificate, the buyer's commission, running costs, the feature list, the agency's reference number and the site's own price-per-square-metre comparison for the area.