# Flatfox Rentals Scraper (Switzerland: apartments and houses) (`swissalpinedata/swiss-rentals-scraper`) Actor

Scrapes Swiss apartment and house listings (rent and sale) from Flatfox's public API, with filters for city, ZIP, canton, price and rooms.

- **URL**: https://apify.com/swissalpinedata/swiss-rentals-scraper.md
- **Developed by:** [WebAlpine Studio](https://apify.com/swissalpinedata) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Swiss Rentals Scraper do?

Swiss Rentals Scraper collects **apartment and house listings for rent or sale in Switzerland** from [Flatfox](https://flatfox.ch), one of the country's largest listing portals with roughly 36,000 active listings, and returns them as clean, flat JSON records. Filter by city, ZIP code, canton, price range, number of rooms and object category. Prices and living areas are the **real values**, not the randomised preview numbers Flatfox serves to casual scrapers.

The Actor talks only to Flatfox's public JSON API. No browser, no HTML parsing, no login, no proxies. A typical run with a city filter and 50 to 100 results finishes in under 15 seconds.

### Why this actor

- Public data only: the public JSON API of Flatfox, one of the larger Swiss real estate portals. Useful as a Homegate alternative data source for Swiss rental and sale listings, but note that it covers Flatfox listings only, not Homegate, ImmoScout24 or Comparis.
- No login, no browser and no proxy. Plain HTTP requests, a typical run finishes in seconds.
- Structured fields with real values: price, rooms, living area, address, ZIP, canton, coordinates, year built, agency, images and description.

### Why use Swiss Rentals Scraper?

- **Market research**: track asking rents and sale prices per city, ZIP or canton over time by scheduling the Actor daily.
- **Relocation and property services**: feed fresh listings into your own alerts, CRM or client reports.
- **Data analysis**: pull thousands of structured records with coordinates, rooms, surface, year built and agency into CSV or Excel in one run.
- **Developers**: call it through the Apify API and get JSON back, with pagination, filtering and deduplication already handled.

### How to use Swiss Rentals Scraper

1. Open the Input tab and choose Rent or Sale.
2. Optionally enter a city (e.g. Zürich, Bern, Lausanne), an exact ZIP code, or pick a canton.
3. Optionally set a price range, a room range and an object category (apartment, house or any).
4. Set Max items to the number of listings you want. The newest listings come first.
5. Click Start. Results appear in the Output tab and can be downloaded as JSON, CSV, Excel or HTML, or fetched through the API.

### Input

| Field | Type | Description |
| --- | --- | --- |
| `offerType` | string | `RENT` or `SALE`. Default `RENT`. |
| `city` | string | City or municipality name, e.g. `Zürich`. Accent-insensitive, so `Zurich` also works. Leave empty for all of Switzerland. |
| `zip` | string | Exact 4-digit Swiss postal code, e.g. `8005`. |
| `canton` | string | Two-letter canton code, e.g. `ZH`, `BE`, `VD`, `GE`, `TI`. |
| `minPrice` / `maxPrice` | integer | Price range in CHF. Monthly rent for `RENT`, total price for `SALE`. |
| `minRooms` / `maxRooms` | number | Room count range, half rooms allowed, e.g. `3.5`. |
| `objectCategory` | string | `APARTMENT`, `HOUSE` or `ANY`. `ANY` also returns shared flats, parking, commercial space and plots. Default `ANY`. |
| `maxItems` | integer | Stop after this many listings. Default 100, maximum 10,000. |

Example input for three-room flats in canton Bern up to CHF 2,500:

```json
{
  "offerType": "RENT",
  "canton": "BE",
  "minRooms": 3,
  "maxPrice": 2500,
  "maxItems": 100
}
```

### Output

Each dataset item is one listing as a flat JSON record. Example from a real run (canton Bern, rent, 3+ rooms, up to CHF 2,500):

```json
{
  "source": "flatfox",
  "listing_id": "86384926",
  "url": "https://flatfox.ch/en/flat/hauptstrasse-4-3706-leissigen/86384926/",
  "title": "Hauptstrasse 4, 3706 Leissigen - CHF 1’850",
  "offer_type": "RENT",
  "object_category": "APARTMENT",
  "object_type": "APARTMENT",
  "price_chf": 1850.0,
  "price_period": "month",
  "rent_net_chf": 1650.0,
  "rent_charges_chf": 200.0,
  "rooms": 4.0,
  "surface_m2": 85.0,
  "floor": 1,
  "year_built": 1988,
  "is_furnished": false,
  "is_temporary": false,
  "address": "Hauptstrasse 4, 3706 Leissigen",
  "street": "Hauptstrasse 4",
  "zip": "3706",
  "city": "Leissigen",
  "canton": "BE",
  "latitude": 46.6573878,
  "longitude": 7.7840874,
  "available_from": "2026-12-01",
  "published_at": "2026-09-22T13:48:30.538356+02:00",
  "images": [
    "https://cdn.flatfox.ch/t_listing_card_716x390/listings/v2/isx50985/4003492750/image/5473c310c0220c02506b8158b7b5ace6.png"
  ],
  "description": "Per 1. Dezember 2026 oder nach Vereinbarung vermieten wir eine charmante 4-Zimmer-Wohnung in der idyllischen Gemeinde Leissigen am Thunersee. \n\nDas erwartet Sie ...",
  "agency": "Ruchti Partner AG",
  "scraped_at": "2026-09-22T20:52:32.248740+00:00"
}
```

#### Data fields

| Field | Description |
| --- | --- |
| `source` | Always `flatfox`. |
| `listing_id` | Flatfox listing id, unique per record. |
| `url` | Public listing page. |
| `title` | Listing title. |
| `offer_type` | `RENT` or `SALE`. |
| `object_category` | `APARTMENT`, `HOUSE`, `SHARED`, `PARK`, `COMMERCIAL`, `PLOT` and others as used by Flatfox. |
| `object_type` | Finer type, e.g. `FLAT`, `ATTIC_FLAT`, `SINGLE_HOUSE`. |
| `price_chf` | Real display price in CHF, or `null` for price on request. |
| `price_period` | `month`, `total` (sale), `year_per_m2` (commercial) or `null`. |
| `rent_net_chf`, `rent_charges_chf` | Net rent and charges when Flatfox splits them. |
| `rooms`, `surface_m2`, `floor`, `year_built` | Numeric details, `null` when not provided. |
| `is_furnished`, `is_temporary` | Booleans from the listing. |
| `address`, `street`, `zip`, `city`, `canton` | Location. `canton` is derived from the ZIP code. |
| `latitude`, `longitude` | Coordinates as published by Flatfox. |
| `available_from` | Move-in date, ISO 8601 date. |
| `published_at` | Listing publication time, ISO 8601 with timezone. |
| `images` | List of image URLs. |
| `description` | Plain text description in the listing's language (German, French, Italian or English). |
| `agency` | Advertising agency name, or `null` for private landlords. |
| `scraped_at` | Time the record was collected, ISO 8601 UTC. |

Fields the source does not provide are `null`. Nothing is invented.

### How long does a run take?

Measured on 22 September 2026:

| Input | Results | Duration |
| --- | --- | --- |
| Rent, Zürich, 50 items | 50 | 7 s |
| Rent, whole Switzerland, 100 items | 100 | 6 s |
| Rent, canton Bern, 3+ rooms, max CHF 2,500, 30 items | 30 | 18 s |
| Sale, houses, whole Switzerland, 20 items | 20 | 7 s |
| Rent, ZIP 8005, apartments up to 2.5 rooms, 100 items | 29 (all available) | 26 s |

The Actor finds candidates through Flatfox's map endpoint, which filters by price, rooms, offer type, category and area on the server, then fetches the exact details in batches of 100. It stops as soon as `maxItems` listings match, so small requests are fast. Runs that need thousands of results, or a very narrow filter inside a large area, take longer because more batches have to be checked. A polite delay of 0.3 to 1 second is kept between requests.

### Pricing

This Actor uses pay per result. You pay **USD 0.004 per listing**, which is **USD 4.00 per 1,000 results**. There is no charge per run or per request, and a run that returns no results produces no result charges.

| Results | Price |
| --- | --- |
| 100 | USD 0.40 |
| 1,000 | USD 4.00 |
| 10,000 | USD 40.00 |

A daily alert with the 25 newest listings in one city costs USD 0.10 per run, about USD 3 per month. Set `maxItems` to cap the cost of a run.

### Tips

- Set `city` or `zip` whenever you can. Both are geocoded once to a bounding box so only listings in that area are checked.
- Use `objectCategory: "APARTMENT"` or `"HOUSE"` to exclude parking, shared rooms and commercial space, which are common in the `ANY` results.
- Listings with no public price (price on request) never match a `minPrice` or `maxPrice` filter, so add a wide range only if you want to drop them.
- Results are ordered newest first, so `maxItems: 20` on a daily schedule is a cheap way to get the latest listings for an area.

### Legal

This Actor only reads Flatfox's public listing API, the same data shown to any visitor of flatfox.ch. It does not require a login and does not bypass any access control. It does not collect personal data about tenants or applicants; agency names are business information published on the listing. What you do with the data, and whether that use complies with Flatfox's terms and applicable law, is your responsibility.

### Limitations and known issues

- **Flatfox only.** homegate.ch, immoscout24.ch and newhome.ch answer 403 or 503 to automated requests even with browser-like headers. Support for them is planned as future work and would require a browser or proxy setup.
- **Location lookup.** City and ZIP inputs are geocoded through OpenStreetMap Nominatim. If a place cannot be found the run fails with a clear message so you can fix the spelling. If the geocoder is unreachable the Actor scans all of Switzerland and filters by name instead, which is slower but still correct.
- **City matching is by name.** The `city` filter matches the city field of the listing as entered by the landlord, so a listing in Zürich-Oerlikon labelled as "Oerlikon" is not returned for `city: "Zürich"`. Use a canton or ZIP for full coverage.
- **Canton is derived from ZIP.** A ZIP range table maps postcodes to cantons. A few border villages with ZIPs in a neighbouring canton's range may be assigned to that canton.
- **Coverage per run.** Discovery is capped at 400 map requests per run, which is far above what any real filter needs, but an unfiltered "everything in Switzerland" run with `maxItems: 10000` is limited by that cap and by the 10,000 item maximum.

### FAQ

**Are the prices real?** Yes. Flatfox serves randomised prices and living areas (roughly plus or minus 25 percent) in its listing feed and map pins to deter scrapers. This Actor uses those only to discover candidates and always re-fetches the exact values through the per-listing lookup before checking your filters and returning a record.

**Why does the API not filter by city?** Flatfox's listing feed accepts no location or price filters. The map endpoint does, but by coordinates, which is why the Actor geocodes your city or ZIP to a bounding box and then checks the city name on the exact data.

**Can I get all listings in Switzerland?** Yes, leave the location empty and set `maxItems` up to 10,000. Expect a few minutes, since each batch of 100 listings is one request.

**Something is wrong or missing.** Open an issue on the Actor's Issues tab with your input and the run id.

### Changelog

**0.1.x** (2026-09-25): README with concrete pricing and keywords (Swiss real estate, Homegate alternative). No change to the output.

**0.1** (2026-09-22): Initial release. Flatfox rent and sale listings with filters for city, ZIP, canton, price, rooms and object category. Server-side candidate discovery through the map endpoint, exact values through batched lookups, newest listings first.

# Actor input Schema

## `offerType` (type: `string`):

Rent or buy listings.

## `city` (type: `string`):

Filter by city or municipality name, e.g. Zürich, Bern, Lausanne. Accent-insensitive (Zurich matches Zürich). Leave empty for all of Switzerland.

## `zip` (type: `string`):

Filter by exact 4-digit Swiss postal code, e.g. 8005. Leave empty to skip.

## `canton` (type: `string`):

Filter by two-letter canton code, e.g. ZH, BE, VD, GE, TI. Leave empty to skip.

## `minPrice` (type: `integer`):

Minimum price in CHF (monthly rent or sale price, depending on offer type).

## `maxPrice` (type: `integer`):

Maximum price in CHF (monthly rent or sale price, depending on offer type).

## `minRooms` (type: `number`):

Minimum number of rooms (e.g. 3.5).

## `maxRooms` (type: `number`):

Maximum number of rooms (e.g. 5.5).

## `objectCategory` (type: `string`):

Restrict to apartments or houses. Any also includes shared flats, parking, commercial and plots.

## `maxItems` (type: `integer`):

Stop after this many listings have been collected. Newest listings come first.

## Actor input object example

```json
{
  "offerType": "RENT",
  "city": "Zürich",
  "canton": "",
  "objectCategory": "ANY",
  "maxItems": 100
}
```

# Actor output Schema

## `results` (type: `string`):

All records returned by this run, as JSON.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "offerType": "RENT",
    "city": "Zürich",
    "objectCategory": "ANY",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("swissalpinedata/swiss-rentals-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "offerType": "RENT",
    "city": "Zürich",
    "objectCategory": "ANY",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("swissalpinedata/swiss-rentals-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "offerType": "RENT",
  "city": "Zürich",
  "objectCategory": "ANY",
  "maxItems": 100
}' |
apify call swissalpinedata/swiss-rentals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,swissalpinedata/swiss-rentals-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/T4pV6gBejoQMFIFhs/builds/aAafVDcNe6AiqYEPM/openapi.json
