# atHome Scraper - Luxembourg Property Listings · $1.5/1K (`listingworks/athome-scraper`) Actor

Scrape atHome.lu property listings for any Luxembourg commune or quarter: price, bedrooms, area, date listed, agency and photo, newest first.

- **URL**: https://apify.com/listingworks/athome-scraper.md
- **Developed by:** [Yusuke Suda](https://apify.com/listingworks) (community)
- **Categories:** Real estate, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 1,000 result items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## atHome Scraper — Luxembourg property listings by commune or quarter

atHome (athome.lu) is Luxembourg's largest property portal. It carries listings from agencies, developers and
private owners, and from the French, German and Belgian border regions as well. Luxembourg City alone had more
than 2,600 flats for sale on it in September 2026. This Actor turns the site's lists into a clean table. Each row
gives:

- a short title, e.g. "Apartment, 2 bedrooms, 61 m² in Luxembourg-Merl"
- the price, or the monthly rent
- the number of bedrooms, and the rooms where the site gives them
- the living area in square metres
- the town or quarter, and the region
- when the listing first went online
- the agency marketing it, and, where the agency shows the address, the street, postcode and map point
- a photo and the link to the listing

Press Start. The prefilled input returns flats for sale in Luxembourg City, newest first.

### What a row looks like

```json
{
  "title": "Apartment, 2 bedrooms, 61 m² in Luxembourg-Merl",
  "property_type": "apartment",
  "listing_type": "sale",
  "price": 545000,
  "currency": "EUR",
  "bedrooms": 2,
  "rooms": 4,
  "living_area_sqm": 61,
  "address": "291, Route de Longwy",
  "postal_code": "1941",
  "city": "Luxembourg-Merl",
  "state": "Centre",
  "latitude": 49.6050397,
  "longitude": 6.0961188,
  "agency": "LA IMMO S.a.r.l.",
  "posted_at": "2026-09-21T09:32:26+00:00",
  "updated_at": "2026-09-21T12:50:32",
  "source_url": "https://www.athome.lu/vente/appartement/luxembourg/id-9346870.html",
  "image_urls": ["https://i1.static.athome.eu//images/annonces2/image_//63/f9/e8/….jpg"],
  "external_id": "9346870"
}
```

#### The seller and the address

Most listings come from estate agencies and developers. For those, `agency` is the name the site shows.

Agencies choose whether the site shows a listing's address. The Actor follows that choice:

- **Address shown:** `address` (the street), `postal_code`, `latitude` and `longitude` are filled.
- **Address hidden:** those four fields stay empty, and only the town or quarter and the region are given.
  Luxembourg postcodes often cover a single street, so the postcode is treated like the street.

Some listings come from private owners. For those, the Actor publishes no seller at all:

- `agency` is empty. The owner's name is in the site's page data, but it is never collected.
- There is no street, postcode or map point, because for a private owner that is their home.
- No phone number or e-mail address is collected for anyone. The Actor reads the lists only and never opens a
  listing page.

A seller is named only when the site files them as an agency and does not flag them as a private seller.

#### Dates

`posted_at` is when the listing first went online, in UTC, to the second. `updated_at` is when it was last edited,
as the site writes it. The lists are read in the site's "Date - la plus récente" order, which is by `posted_at`.

#### Bedrooms, rooms and area

`bedrooms` is the site's bedroom count. `rooms` is filled only where the site gives a room count as well. Most
Luxembourg listings give bedrooms only. A studio with no bedroom count has an empty `bedrooms`, not a zero.
`living_area_sqm` is the living area. The site also has a land-area figure whose unit cannot be told from the
list, so it is not published.

#### Prices

`price` is the asking price for a sale and the monthly rent for a let, in euros. A listing with no price, or
"price on request", has an empty `price`, not a zero. A new-development project that is listed as a whole, e.g.
"Maison Béatrice (new development)", also has an empty `price`. Its units have different prices.

### What people use it for

Price monitoring for Luxembourg property by commune and quarter. Comparing asking prices and rents across
Luxembourg City quarters, Esch-sur-Alzette and the rest of the country. A daily feed of what is new, using
`postedAfter`. Tracking which agencies list what, and where.

### Input

| Field | What it does |
|---|---|
| `location` | A commune or town as the site writes it (`Luxembourg`, `Esch-sur-Alzette`, `Differdange`, `Strassen`), or a commune and one of its quarters (`luxembourg/kirchberg`, `luxembourg/bonnevoie`). Accents and capitals are fine. |
| `listingType` | `sale` (the default) or `rent`. |
| `propertyType` | `apartment` or `house`. Leave it empty for apartments. |
| `postedAfter` | Only keep listings that went online at or after this time (ISO 8601). The list is read newest first, so the run stops shortly after passing this date. Handy for daily runs that should return only what is new. |
| `maxItems` | Hard stop, so your bill is predictable. |
| `proxyConfiguration` | Off by default. Most runs do not need one. |

If the site does not know the place you give, the run fails and tells you. This check matters on atHome: for a
place it does not recognise, the site quietly answers with every listing on the portal, border regions
included, and the Actor refuses that page.

### Pricing

$1.50 per 1,000 listings, dropping to $0.75 per 1,000 on higher Apify plans, plus $0.005 each time a run
starts. Platform usage is not passed on to you.

You are charged for rows you actually receive. If you set a maximum charge for the run, it stops cleanly at
that limit instead of overshooting it.

### Scope and limits

Public listings only, from the site's lists by type, sale or rent, and place, which atHome's robots.txt allows.
The pages it disallows (search and results paths, agency pages, listing print and PDF views) are never
requested, and neither is the site's internal API. The Actor reads one page every 2 seconds, twice the delay
the robots.txt asks for. That makes 20 listings every 2 seconds, or about 1,000 in under 2 minutes.

Apartments and houses are covered. Land, offices, shops and parking exist on the site but are not offered here
yet. The full description, the energy rating, the floor and the year built are not collected. Prices are in
euros.

If athome.lu changes its page structure, the run goes red. It does not return zero rows and report success. A
silent scraper is worse than a broken one, because you find out weeks later. The Actor also checks that every
page answers the question it asked (type, sale or rent, place, order and page number) and fails rather than
delivering a page for something else.

A run that is blocked or cut short partway also goes red, even though the rows it did collect are in the
dataset and yours to keep. Red here means "this is not the complete answer", not "you lost the data". On a
schedule, a run that quietly came back short is the thing you most need to hear about.

Every run also publishes the site's own result count next to the rows it delivered, so you can see "100 rows
of 2,636 the site reports" without going back to the site to check. That number is what the site says, not a
promise about what one run returns.

### Same data, other countries

This Actor shares its output shape with the Immoweb Scraper (Belgium), the Ohne-Makler Scraper and the Immowelt
Scraper (Germany), the Bezrealitky Scraper (Czech Republic) and the Willhaben Immobilien Scraper (Austria). A
parser you write for one keeps working on the others.

### Support

Open an issue on this Actor with the run ID and your input. Answered within one business day.

# Actor input Schema

## `location` (type: `string`):

A commune or town as the site writes it (Luxembourg, Esch-sur-Alzette, Differdange, Strassen), or a commune and one of its quarters (luxembourg/kirchberg, luxembourg/bonnevoie). A place the site does not know fails the run rather than returning the whole portal.

## `listingType` (type: `string`):

Property for sale (vente) or for rent (location).

## `propertyType` (type: `array`):

Which lists to walk: apartment, house. Leave empty for apartments.

## `postedAfter` (type: `string`):

Return only listings first put online at or after this ISO 8601 date-time, e.g. 2026-09-01T00:00:00Z. The list is read newest first, so the run stops once it is past this date.

## `sinceDays` (type: `integer`):

Keep only listings posted in the last N days, counted in UTC from the day the run starts: 1 = yesterday and today. Made for a daily schedule. Ignored when Posted after is set.

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

Stop after this many listings. atHome.lu serves 20 per page, one page every 2 seconds.

## `proxyConfiguration` (type: `object`):

Off by default. Turn on (residential, Luxembourg) only if runs start getting blocked with 403/429.

## Actor input object example

```json
{
  "location": "Luxembourg",
  "listingType": "sale",
  "propertyType": [
    "apartment"
  ],
  "postedAfter": "",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

All atHome.lu listings from this run: what each property is, what it costs, where, and when it was listed.

## `pricing` (type: `string`):

The same listings reduced to the fields used for price analysis and market monitoring.

## `agencies` (type: `string`):

The same listings focused on the agency or developer marketing them (empty for private owners).

## `runReport` (type: `string`):

Pages read, records delivered, errors, and the verdict (ok, degraded or broken).

# 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 = {
    "location": "Luxembourg",
    "propertyType": [
        "apartment"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("listingworks/athome-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 = {
    "location": "Luxembourg",
    "propertyType": ["apartment"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("listingworks/athome-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 '{
  "location": "Luxembourg",
  "propertyType": [
    "apartment"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call listingworks/athome-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,listingworks/athome-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/dSdeRG6aK7ZuV0F9u/builds/iNeDu7X6BlpGwei43/openapi.json
