Immowelt Scraper — Germany Real Estate Listings | $1.19/1K avatar

Immowelt Scraper — Germany Real Estate Listings | $1.19/1K

Pricing

from $1.00 / 1,000 immowelt scraper — germany real estate listings | $1.19/1ks

Go to Apify Store
Immowelt Scraper — Germany Real Estate Listings | $1.19/1K

Immowelt Scraper — Germany Real Estate Listings | $1.19/1K

Scrape Immowelt.de (German real estate portal) from a search-results URL you paste. Returns title, price, rooms, living space m², location, provider/agent contact, images, and listing URL.

Pricing

from $1.00 / 1,000 immowelt scraper — germany real estate listings | $1.19/1ks

Rating

0.0

(0)

Developer

Vitalii Bondarev

Vitalii Bondarev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Immowelt Listings Scraper

Scrape Immowelt.de (German real estate portal) from a search-results URL you paste — no need to configure filters in this actor, just set them on immowelt.de and copy the resulting URL.

Features

  • Scrape any Immowelt search (buy or rent, any city/price/room filter you set on their site)
  • Returns per-listing: price, rooms, living space m², location, provider/agent contact, images, and listing URL
  • Uses Immowelt's own embedded Next.js __NEXT_DATA__ search-results JSON — no HTML scraping, no browser
  • Pay per result — you only pay for listing records actually extracted
  • Automatic pagination up to maxItems, with residential-proxy session rotation on a block

Input

FieldTypeDefaultDescription
searchUrlstring(required)An immowelt.de search-results URL. Set your filters on immowelt.de, then copy the URL from your browser.
maxItemsinteger100Max listings to return (0 = unlimited)
proxyConfigurationproxyRESIDENTIAL DEApify Residential proxy, Germany

Why a search URL instead of filter fields?

Traction-proven Store competitors for Immowelt (igolaizola/immowelt-scraper, azzouzana/immowelt-scraper, ninhothedev/immowelt-scraper) mostly accept either a location/locationID pair or a raw search URL. This actor takes the URL directly — simplest, safest contract, and it avoids guessing Immowelt's internal location-ID scheme wrong.

Output fields

FieldDescription
listing_idImmowelt internal listing/online ID
urlDirect URL to the listing
title / description
price / price_display / price_typeprice_type is best-effort (kaufpreis/kaltmiete/warmmiete)
rooms / living_space_m2 / plot_size_m2
city / district / postal_code / street / country
latitude / longitude
provider_name / provider_phone / provider_typeListing agent/agency contact
images / image_count
energy_info / building_stateBest-effort; full energy certificate detail lives on the classified detail page
publication_date / update_date
page_number / source / parse_confidence / warnings / scraped_atProvenance/QA fields. source is next_data or ufrn_fetcher depending on which embedded blob supplied the record.

Access path

Immowelt has no public search API. It's a Next.js SPA — the search-results page embeds the result set as JSON, primarily via <script id="__NEXT_DATA__" type="application/json"> (standard Next.js page-data, parsed directly, no unescaping) at documented path props.pageProps.classifiedsData. This actor fetches the page with curl_cffi (Chrome TLS impersonation, no browser). As a fallback (only tried when __NEXT_DATA__ yields nothing), it also decodes a second observed bootstrap blob, window["__UFRN_FETCHER__"] = JSON.parse("..."), which uses the same double-encoding scheme as the sibling seloger-listings-scraper actor's initialData — the decode routine is the same shape, ported here rather than shared, per this fleet's per-actor _shared/ convention.

Apify RESIDENTIAL (DE) proxy is recommended for production reliability; third-party vendors document general anti-scraping blocking on this target though the specific mechanism (Cloudflare/DataDome/other) wasn't confirmed against a live run for this build.

Honest caveats (read before relying on this in production)

  • Field-name mapping is unverified against a live Immowelt response. The field names used here (hardFacts.facts[], hardFacts.price, location.address, gallery.images, provider, metadata.publishDate, …) come from ScrapFly's public engineering write-up on scraping Immowelt.de, not from an authenticated cloud run against the live site (out of scope for this build). normalize.py is defensive: every field falls back to None and deducts parse_confidence rather than raising. Spot-check the exact field set against a real cloud run (with RESIDENTIAL DE proxy) before publishing or relying on this for paid delivery.
  • The exact pageProps wrapper key for the listings array is unconfirmed — the parser tries several candidate keys (classifiedsData, classifieds, searchResult, initialGeoSearchResult) then falls back to a tolerant structural walk (first list of dicts with an id plus a signal field), same pattern as the sibling seloger-listings-scraper and the fleet's existing immoscout24-listings actor.
  • hardFacts.facts[] label matching (rooms/living-space/plot-size) is heuristic (substring match on German/English label text), not a confirmed fixed key list — a mislabeled fact silently stays unmapped rather than crashing, which trades some recall for robustness under an unconfirmed schema.
  • Full energy certificate detail, exact address (house number), and construction-year data live on the classified detail page (props.pageProps.classified per the same source), not the search-results payload — this actor is search-summary-only; detail-page enrichment is a straightforward v2 addition once the search path is verified live.
  • Termination is by empty-page detection (30 results/page per source docs), not a parsed totalPages field, since the exact count-field name is also unconfirmed.

Tests

Unit tests (tests/) run entirely offline against synthetic fixtures — no live network calls: cd actors/REAL_ESTATE/immowelt-listings-scraper && python3 -m pytest -q.