Sign inTry it

Find a WG room or flat on WG-Gesucht.

Searches WG-Gesucht, Germany's biggest flat-share site, like its list page: WG rooms, 1-room flats, flats or houses in a city (looked up with WG-Gesucht's own city search), with a maximum rent and a minimum size. Each result has the rent, size, WG size, district and street, available from (and until, for fixed-term lets), when it went online, a photo and the link. Commercial partner offers and paid placements are dropped by default. Newest first.

No reports yetRead-only, no login
Site
WG-Gesucht, Germany
Version
v1
Runs, last 7 days
No reports yet
sha256
da8f900d35bb…

Run it with your agent

after installing Wield

Ask in plain words. Your agent finds this recipe and calls it:

“Find a WG room or flat on WG-Gesucht.”

Read-only: it changes nothing on the site. No login needed.

{
  "tool": "run",
  "arguments": {
    "recipe_id": "wg-gesucht.de/search-rooms",
    "params": {
      "city": "München",
      "max_rent": 700,
      "min_size": 15
    }
  }
}

Requests

sent from your browser, in order
  1. 1GET/api/location/cities/names/{{params.city | trim | urlencode}}WG-Gesucht's own city search (/api/location/cities/names/<query>, the city box calls it). The first match gives the city id and the name for the list URL.
  2. 2GET/{{f.prefix}}-in-{{f.slug | urlencode}}.{{f.id}}.{{f.cat}}.1.{{f.page}}.html?categories[0]&city_id&noDeact&offer_filter&rMax&sMinThe server-rendered list page /<category>-in-<City>.<city_id>.<category_id>.1.<page>.html with the filter query the page itself builds. The path's city name must be the site's own spelling (umlauts as ae/oe/ue), or the site redirects and loses the page number; the one-item foreach builds it. Later pages are requested the way the page's own pagination links do (without offer_filter), or the site redirects to page 1.repeats, max 1

Parameters

from your agent
categoryenum "wg_room" | "one_room_flat" | "flat" | "house" = "wg_room"
citystringrequiredCity, e.g. 'Berlin', 'München', 'Frankfurt am Main', 'Wien'. The first match of WG-Gesucht's city search is used
include_partner_offersbooleanKeep offers from commercial partners (Sofortbuchung) and paid placements, marked = false
max_rentintegerEUR per month, total rent
min_sizeintegerm²
pageinteger = 1

Returns

to your agent
categorystring
citystringThe city WG-Gesucht matched, e.g. 'München (Bayern)'
offersobject[]available_from, available_until, district, flatmates, id, image, online, partner_offer, rent_eur, size_m2, street, title, type, url, wg_size
pageinteger

Where it can send

  • www.wg-gesucht.de

Anything else is blocked by the extension.

Reads from your session

Nothing. Your browser attaches the site's cookies by itself.

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • length(output.offers) > `5`
  • starts_with(output.city, 'München')
  • length(output.offers[?partner_offer]) == `0`
  • length(output.offers[?rent_eur > `700`]) == `0`
  • length(output.offers[?size_m2 < `15`]) == `0`
  • length(output.offers[?starts_with(url, 'https://www.wg-gesucht.de/wg-zimmer-in-') && rent_eur > `0` && available_from != `null`]) == length(output.offers)

Raw recipe

Served as canonical JSON from /api/v1/recipes/wg-gesucht.de/search-rooms, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/wg-gesucht.de/search-rooms | shasum -a 256
# da8f900d35bb3d5358de69fa5897120294299e3bdb3322bc5ca8655f8ede7523
wg-gesucht.de/search-rooms.json, v1
{
  "description": "Searches WG-Gesucht, Germany's biggest flat-share site, like its list page: WG rooms, 1-room flats, flats or houses in a city (looked up with WG-Gesucht's own city search), with a maximum rent and a minimum size. Each result has the rent, size, WG size, district and street, available from (and until, for fixed-term lets), when it went online, a photo and the link. Commercial partner offers and paid placements are dropped by default. Newest first.",
  "effect": "read",
  "id": "wg-gesucht.de/search-rooms",
  "keywords": [
    "wg-gesucht",
    "wg",
    "wg-zimmer",
    "zimmer",
    "wohngemeinschaft",
    "mitbewohner",
    "1-zimmer-wohnung",
    "wohnung mieten",
    "zwischenmiete",
    "befristet",
    "flat share",
    "room",
    "student housing",
    "berlin",
    "münchen",
    "hamburg",
    "köln"
  ],
  "output": {
    "schema": {
      "properties": {
        "category": {
          "type": "string"
        },
        "city": {
          "description": "The city WG-Gesucht matched, e.g. 'München (Bayern)'",
          "type": "string"
        },
        "offers": {
          "items": {
            "properties": {
              "available_from": {
                "description": "YYYY-MM-DD",
                "type": [
                  "string",
                  "null"
                ]
              },
              "available_until": {
                "description": "YYYY-MM-DD for fixed-term (befristet) lets, else null",
                "type": [
                  "string",
                  "null"
                ]
              },
              "district": {
                "description": "City and district as shown, e.g. 'Berlin Friedrichshain'",
                "type": [
                  "string",
                  "null"
                ]
              },
              "flatmates": {
                "description": "Occupied / total places, e.g. '1/2'",
                "type": [
                  "string",
                  "null"
                ]
              },
              "id": {
                "type": "string"
              },
              "image": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "online": {
                "description": "Online since, as shown, e.g. '6 Min.', '2 Stunden', '3 Tage'",
                "type": [
                  "string",
                  "null"
                ]
              },
              "partner_offer": {
                "description": "Commercial partner offer (Sofortbuchung) or paid placement",
                "type": "boolean"
              },
              "rent_eur": {
                "description": "Total monthly rent ('ab' prices: the lowest)",
                "type": [
                  "number",
                  "null"
                ]
              },
              "size_m2": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "street": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "type": {
                "description": "e.g. '3er WG', '1-Zimmer-Wohnung'",
                "type": [
                  "string",
                  "null"
                ]
              },
              "url": {
                "type": "string"
              },
              "wg_size": {
                "description": "People in the WG, from '3er WG'",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "type": "array"
        },
        "page": {
          "type": "integer"
        }
      },
      "required": [
        "city",
        "category",
        "offers"
      ],
      "type": "object"
    },
    "value": "let $keep = params.include_partner_offers == `true` in {city: steps.city.label || steps.city.name, category: params.category || 'wg_room', page: params.page || `1`, offers: map(&(let $o = @ in let $d = split($o.details || '', ' · '), $t = split($o.dates || '', ' - '), $p = split(replace($o.price || '', 'ab ', ''), ' ')[0] in {id: $o.id, title: $o.title || `null`, rent_eur: $p && to_number(replace(replace($p, '.', ''), ',', '.')) || `null`, size_m2: $o.size && to_number(replace(split($o.size, ' ')[0], ',', '.')) || `null`, type: $d[0] && trim($d[0]) || `null`, wg_size: $d[0] && contains($d[0], 'er WG') && to_number(split(trim($d[0]), 'er')[0]) || `null`, district: $d[1] && trim($d[1]) || `null`, street: $d[2] && trim($d[2]) || `null`, available_from: $t[0] && contains($t[0], '.') && join('-', reverse(split(trim($t[0]), '.'))) || `null`, available_until: $t[1] && contains($t[1], '.') && join('-', reverse(split(trim($t[1]), '.'))) || `null`, flatmates: $o.flatmates || `null`, online: $o.online || `null`, partner_offer: contains($o.class || '', 'campaign_click') || contains($o.class || '', 'premium_sticky_asset'), image: $o.image || `null`, url: join('', ['https://www.wg-gesucht.de', $o.href])}), steps.search[0].offers || `[]`)[?$keep || !partner_offer]}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "category": {
        "default": "wg_room",
        "enum": [
          "wg_room",
          "one_room_flat",
          "flat",
          "house"
        ],
        "type": "string"
      },
      "city": {
        "description": "City, e.g. 'Berlin', 'München', 'Frankfurt am Main', 'Wien'. The first match of WG-Gesucht's city search is used",
        "maxLength": 60,
        "minLength": 2,
        "type": "string"
      },
      "include_partner_offers": {
        "default": false,
        "description": "Keep offers from commercial partners (Sofortbuchung) and paid placements, marked",
        "type": "boolean"
      },
      "max_rent": {
        "description": "EUR per month, total rent",
        "minimum": 0,
        "type": "integer"
      },
      "min_size": {
        "description": "m²",
        "minimum": 0,
        "type": "integer"
      },
      "page": {
        "default": 1,
        "maximum": 20,
        "minimum": 1,
        "type": "integer"
      }
    },
    "required": [
      "city"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "The city box calls /api/location/cities/names/<query> (services.location.getCitiesBySearchQuery in /js/lib/Services.lib.js; no token needed): city_id, city_name, city_and_state. The list pages are server-rendered: /wg-zimmer-in-<City>.<id>.0.1.<page>.html (1-zimmer-wohnungen …1, wohnungen …2, haeuser …3), filters as the page's own form sends them (offer_filter=1, city_id, noDeact=1, categories[], rMax, sMin); its pagination links drop offer_filter (with it, page 2+ redirects to page 1). The City part must be the canonical spelling (Muenchen): 'München' gives 404 and other names 301 to the canonical URL with the page reset. Cards: a.offer_list_item; 'campaign_click' cards are WG-Gesucht Pro partner offers (e.g. HousingAnywhere, Sofortbuchung) and 'premium_sticky_asset' cards are paid placements; both dropped by default. Advertisers' names are left out. Answers servers.",
    "recorded_at": "2026-11-07T21:41:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "DE",
    "id": "wg-gesucht.de",
    "language": "de",
    "name": "WG-Gesucht",
    "origin": "https://www.wg-gesucht.de",
    "origins": [
      "https://www.wg-gesucht.de"
    ]
  },
  "steps": [
    {
      "description": "WG-Gesucht's own city search (/api/location/cities/names/<query>, the city box calls it). The first match gives the city id and the name for the list URL.",
      "expect": {
        "assert": "length(body._embedded.cities) > `0`",
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "id": "_embedded.cities[0].city_id",
          "label": "_embedded.cities[0].city_and_state",
          "name": "_embedded.cities[0].city_name"
        }
      },
      "id": "city",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "url": "/api/location/cities/names/{{params.city | trim | urlencode}}"
      }
    },
    {
      "description": "The server-rendered list page /<category>-in-<City>.<city_id>.<category_id>.1.<page>.html with the filter query the page itself builds. The path's city name must be the site's own spelling (umlauts as ae/oe/ue), or the site redirects and loses the page number; the one-item foreach builds it. Later pages are requested the way the page's own pagination links do (without offer_filter), or the site redirects to page 1.",
      "expect": {
        "content_type": "html",
        "status": [
          200
        ]
      },
      "extract": {
        "html_items": {
          "offers": {
            "fields": {
              "badge": {
                "selector": ".user-badge span"
              },
              "class": {
                "attr": "class",
                "selector": ":scope"
              },
              "dates": {
                "selector": ".middle-row > div:nth-child(2)"
              },
              "details": {
                "attr": "title",
                "selector": ".card-details-text"
              },
              "flatmates": {
                "selector": ".flatmates_pill span"
              },
              "href": {
                "attr": "href",
                "selector": ":scope"
              },
              "id": {
                "attr": "data-id",
                "selector": ":scope"
              },
              "image": {
                "attr": "data-src",
                "selector": "img.sp-image"
              },
              "online": {
                "selector": ".online-since-icon ~ .card-subtitle"
              },
              "price": {
                "selector": ".price-row .card-main-text"
              },
              "size": {
                "selector": ".size-value"
              },
              "title": {
                "selector": ".card-title-text"
              }
            },
            "max": 40,
            "selector": "a.offer_list_item"
          }
        }
      },
      "foreach": {
        "as": "f",
        "in": "[{prefix: (params.category == 'one_room_flat' && '1-zimmer-wohnungen') || (params.category == 'flat' && 'wohnungen') || (params.category == 'house' && 'haeuser') || 'wg-zimmer', cat: (params.category == 'one_room_flat' && '1') || (params.category == 'flat' && '2') || (params.category == 'house' && '3') || '0', id: steps.city.id, slug: replace(replace(replace(replace(replace(replace(replace(replace(replace(steps.city.name, 'ä', 'ae'), 'ö', 'oe'), 'ü', 'ue'), 'Ä', 'Ae'), 'Ö', 'Oe'), 'Ü', 'Ue'), 'ß', 'ss'), ' ', '-'), '/', '-'), page: to_string((params.page || `1`) - `1`), first: (params.page || `1`) == `1` && '1' || `null`}]",
        "max": 1
      },
      "id": "search",
      "parse": "html",
      "request": {
        "headers": {
          "Accept": "text/html"
        },
        "method": "GET",
        "query": {
          "categories[0]": "{{f.cat}}",
          "city_id": "{{f.id}}",
          "noDeact": "1",
          "offer_filter": "{{f.first}}",
          "rMax": "{{params.max_rent}}",
          "sMin": "{{params.min_size}}"
        },
        "url": "/{{f.prefix}}-in-{{f.slug | urlencode}}.{{f.id}}.{{f.cat}}.1.{{f.page}}.html"
      }
    }
  ],
  "task": "Find a WG room or flat on WG-Gesucht",
  "tos": {
    "notes": "Terms not reviewed yet for automated access. One person's search: 2 requests, the same ones the city box and the list page make; no messages, no login. robots.txt allows the list pages. Contacting landlords stays on wg-gesucht.de.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.offers) > `5`",
      "starts_with(output.city, 'München')",
      "length(output.offers[?partner_offer]) == `0`",
      "length(output.offers[?rent_eur > `700`]) == `0`",
      "length(output.offers[?size_m2 < `15`]) == `0`",
      "length(output.offers[?starts_with(url, 'https://www.wg-gesucht.de/wg-zimmer-in-') && rent_eur > `0` && available_from != `null`]) == length(output.offers)"
    ],
    "example_params": {
      "city": "München",
      "max_rent": 700,
      "min_size": 15
    },
    "max_ms": 5000
  },
  "version": 1
}