# LUN.ua Ukraine Real Estate Scraper: Listings & New Builds (`recordsdata/lun-ua-scraper`) Actor

Scrape lun.ua Ukraine real estate: sale, rent and daily-rent ads with price history, areas, coordinates and photos, plus new-build projects, developers, promotions and floor plans. Filter by city, type and rooms. No login or API key. Export CSV, Excel, JSON, XML.

- **URL**: https://apify.com/recordsdata/lun-ua-scraper.md
- **Developed by:** [RecordsData](https://apify.com/recordsdata) (community)
- **Categories:** Real estate, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $22.00 / 1,000 property ads

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

![RecordsData](https://api.apify.com/v2/key-value-stores/AAm3a1h3Z9nYfrvh9/records/banner?v=3)

## 🏠 LUN.ua Real Estate Scraper: Ukraine Listings, New Builds & Developers

> **LUN.ua Real Estate Scraper exports property ads from lun.ua, the Ukrainian real estate aggregator, as structured data: price and price history, rooms, areas, floor, address, coordinates, photos, seller type and the agency behind each ad. It also returns new-build projects, developers, developer promotions and floor plans. Export CSV, Excel, JSON or XML. No login, no API key, no proxy.**

The LUN.ua Real Estate Scraper turns the Ukrainian property market into a dataset you can filter, sort and join. On 2026-10-29 the site's own counter showed 51,773 apartments for sale in Kyiv (21,207 after the site groups duplicate ads), 27,528 apartments for rent in Kyiv and 1,609 daily rentals. The Actor reads the pages lun.ua publishes for every visitor, with plain requests, a few at a time. A 3-listing run finishes in about 2 seconds.

### 🎯 What does the LUN.ua scraper do?

- Scrapes **lun.ua property ads**: apartments, houses, townhouses, cottages, country houses and dachas, land plots and commercial property, for sale, monthly rent and daily rent, in 22 regional centres (Kyiv, Lviv, Odesa, Kharkiv, Dnipro and 17 more), with the towns around each city or the whole region.
- Reads **new-build projects** (price ranges, units, construction status, houses, developer, financing terms, photos), **developers**, **developer promotions** and **floor plans**.

### 📊 LUN.ua property data: which fields do you get?

Every row is one record with `recordType` set to `listing`, `project`, `developer`, `promotion` or `layout`. The dataset has 169 columns; a listing row carries 50 to 80 of them, depending on what the ad states. Fields the ad does not state are left out.

**Listing rows (`recordType: listing`)**, the main fields:

| Field | Type | Example |
|---|---|---|
| `listingId` | string | `4730833957` |
| `operation` / `propertyType` | string | `sale` / `apartment` |
| `price` / `currency` | number / string | `235000` / `USD` |
| `pricePerM2` | number | `3357` |
| `previousPrice` / `priceChange` | number | earlier amount and signed change |
| `priceHistory` | array | list of earlier amounts |
| `rooms` | integer | `2` |
| `areaBuilt` / `areaLiving` / `areaKitchen` | number | `70` / `35` / `30` |
| `floor` / `totalFloors` / `yearBuilt` | integer | `18` / `25` / `2020` |
| `address` / `city` / `district` | string | `Червоної Калини просп., 56` / `Львів` / `Сихівський` |
| `housingComplex` | string | `ЖК Avalon Up` |
| `latitude` / `longitude` | number | `49.795` / `24.052` |
| `isPrivateSeller` | boolean | `false` |
| `agencyName` / `agentVerified` | string / boolean | `АН Новий Дім` / `true` |
| `images` / `imageCount` | array / integer | photo URLs / `28` |
| `publishedAt` / `updatedAt` | string | `2026-10-15T10:52:44Z` |
| `originSite` | string | `rieltor.ua` |

**Project rows (`recordType: project`)**, new-build complexes:

| Field | Type | Example |
|---|---|---|
| `projectId` | string | `7` |
| `title` | string | `ЖК Іспанський` |
| `salesStatus` / `constructionStatus` | string | `all_sold` / `built` |
| `priceFromUah` / `priceFromUsd` | number | lowest amount in each currency |
| `houses` / `sections` / `totalFloors` | integer | `1` / `3` / `14` |
| `installmentMonths` | integer | `12` |
| `developerName` | string | `Прогрес-Буд` |

**Developer rows (`recordType: developer`)**:

| Field | Type | Example |
|---|---|---|
| `developerId` | string | developer id on lun.ua |
| `title` | string | developer name |
| `projectCount` | integer | number of projects |
| `housesInProgress` / `housesBuilt` | integer | houses under construction and finished |
| `foundedYear` | integer | year founded |

**Promotion rows (`recordType: promotion`)**:

| Field | Type | Example |
|---|---|---|
| `promotionId` | string | promotion id |
| `label` | string | promotion text |
| `startDate` / `endDate` | string | promotion window |
| `isActive` | boolean | `true` |
| `projectName` / `projectUrl` | string | project the promotion belongs to |

**Floor-plan rows (`recordType: layout`)**:

| Field | Type | Example |
|---|---|---|
| `layoutId` | string | floor plan id |
| `roomTypePriceFromUah` / `roomTypePriceFromUsd` | number | lowest amount of the room type |
| `areaMin` / `areaMax` | number | area range in square meters |
| `floorMin` / `floorMax` | integer | floor range |
| `completionQuarter` | string | planned completion |

### ⚙️ LUN.ua scraper input

| Field | Type | Default | Meaning |
|---|---|---|---|
| `recordTypes` | array | `["listings"]` | What to collect: `listings`, `projects`, `developers`, `promotions`, `layouts` |
| `startUrls` | array | empty | lun.ua page addresses to read; a search page brings its own filters |
| `maxItems` | integer | 10 prefill | Rows to return (free plans: 10) |
| `operation` | string | `sale` | `sale` or `rent` |
| `cities` | array | `["kyiv"]` | Regional centres |
| `coverage` | string | `city` | `city` or `region` |
| `propertyTypes` | array | `["flats"]` | Property types |
| `rooms` | array | empty | Room counts |
| `features` | array | empty | Ready-made lun.ua filters |
| `expandBy` | array | all five | Go deeper: districts, microdistricts, streets, complexes, room pages |
| `useSitemaps` | boolean | false | Walk the sitemap |
| `language` | string | `uk` | `uk` or `ru` |
| `maxRunSeconds` | integer | 1800 | Longest run |
| `onlyNew` / `stateKey` / `resetSeen` | boolean / string / boolean | false / empty / false | Monitor mode, its name, and a reset |
| `includeContactDetails` | boolean | false | Business contact data of agencies |

Input for 50 two-room apartments for rent in Lviv:

```json
{
  "recordTypes": ["listings"],
  "operation": "rent",
  "cities": ["lviv"],
  "propertyTypes": ["flats"],
  "rooms": ["2"],
  "maxItems": 50
}
```

### 🧾 LUN.ua listing example: what does a real result look like?

A real listing row (cloud run, 2026-10-29; the description and the photo list are shortened):

```json
{
  "recordType": "listing",
  "listingId": "4730833957",
  "url": "https://rieltor.ua/lvov/flats-sale/view/13134134/",
  "operation": "sale",
  "propertyType": "apartment",
  "price": 235000,
  "currency": "USD",
  "pricePerM2": 3357,
  "rooms": 2,
  "areaBuilt": 70,
  "areaLiving": 35,
  "floor": 18,
  "totalFloors": 25,
  "yearBuilt": 2020,
  "address": "Червоної Калини просп., 56",
  "city": "Львів",
  "district": "Сихівський",
  "housingComplex": "ЖК Avalon Up",
  "latitude": 49.79509353637695,
  "longitude": 24.052188873291016,
  "isPrivateSeller": false,
  "agencyName": "АН Новий Дім",
  "agentVerified": true,
  "publishedAt": "2026-10-15T10:52:44Z",
  "updatedAt": "2026-10-29T07:01:02Z",
  "originSite": "rieltor.ua",
  "scrapedAt": "2026-10-29T16:38:34.431Z"
}
```

`url` is the link to the ad on the site where it was published (rieltor.ua here), because lun.ua has no ad page of its own.

### 🚀 How to scrape LUN.ua in 4 steps

1. Create a free account at [console.apify.com](https://console.apify.com) and open this Actor.
2. Pick what to collect (listings, new-build projects, developers, promotions or floor plans), then the operation (sale or rent), the cities and the property types. Leave everything else on its default to get the apartments of Kyiv.
3. Set **Max Items** and press Start. A 3-listing run finishes in about 2 seconds.
4. Download the dataset as CSV, Excel, JSON or XML, or read it through the Apify API.

### 📈 How does it compare with other LUN.ua scrapers? Read on 2026-11-03

| | This Actor | skipper_lume LUN.ua Scraper | Manual browsing |
|---|---|---|---|
| Record types | Listings, projects, developers, promotions, floor plans | Listings, plus new-build fields (`developers`, `priceFromUAH`) | One page at a time |
| Output columns | 169 | 27 | No export |
| Price history and signed price change | Yes | Change type only | Page by page |
| Seller type and agency data | Yes, no phones unless you switch it on | No such columns published | Yes |
| Only-new monitor mode | Yes | Not stated on its page | None |
| Reach beyond 24 ads per page | District, street and complex pages, sitemaps | Not stated on its page | Not possible |

The other Actor's columns were read on 2026-10-29 from its published dataset schema. It has columns this Actor does not: `market`, `priceUSD` and `priceUAH` (lun.ua prices carry one currency, shown in `price` and `currency`, and this Actor does not convert them).

### 💰 How much does the LUN.ua scraper cost?

Pay per event, no monthly fee. Rates are USD per result on the Free tier.

| Event | Charged for | Per result | Per 1,000 |
|---|---|---|---|
| Listing record | One property ad | $0.022 | $22.00 |
| Project record | One new-build project | $0.033 | $33.00 |
| Developer record | One developer | $0.022 | $22.00 |
| Promotion record | One developer promotion | $0.011 | $11.00 |
| Layout record | One floor plan | $0.011 | $11.00 |

Worked examples: 1,000 listings cost $22.00. The 2,577-ad Kyiv run costs 2,577 x $0.022 = $56.69. All 1,705 developers cost 1,705 x $0.022 = $37.51. A mixed run of 1,000 listings, 100 projects and 50 floor plans costs $22.00 + $3.30 + $0.55 = $25.85. Any repricing of an event is shown on the actor page.

### 💼 LUN.ua scraper use cases

- **Market analysis:** compute the median price per square meter by district, microdistrict or housing complex with `pricePerM2`, `district` and `housingComplex`, and track it over time with scheduled runs.
- **Price-drop alerts:** `previousPrice`, `priceChange` and `priceChangedAt` show which ads got cheaper and when, and the only-new mode returns fresh ads only.

### 🔌 LUN.ua scraper API, MCP and integrations

Run it from any language through the Apify API:

```bash
curl -X POST "https://api.apify.com/v2/acts/RecordsData~lun-ua-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operation":"rent","cities":["lviv"],"propertyTypes":["flats"],"rooms":["2"],"maxItems":50}'
```

Connect it to Make, Zapier, n8n, Google Sheets or Slack with the standard Apify integrations, or let an AI agent call it through the Apify MCP server: `https://mcp.apify.com?tools=RecordsData/lun-ua-scraper`.

### 🤖 LUN.ua scraper for AI agents (MCP)

Add the Actor to any MCP client (Claude, Cursor, VS Code) through the Apify MCP server. The agent sees the input schema as the tool description: a tool that scrapes lun.ua listings, new-build projects, developers, promotions and floor plans in Ukraine, with filters for operation, city, property type, rooms and ready-made lun.ua filters, and a `maxItems` cap.

Example agent prompt:

> Find 20 two-room apartments for rent in Lviv on lun.ua without intermediaries, with coordinates and price, and tell me the median price.

The agent calls the Actor with `{"operation":"rent","cities":["lviv"],"features":["bez-poserednykiv"],"maxItems":20}`, reads `price`, `currency`, `latitude`, `longitude` and `rooms` from the rows and answers from them. Keep `maxItems` small in agent runs.

### ⚖️ Is it legal to scrape LUN.ua?

The Actor reads public pages that lun.ua shows to every visitor, without logging in and without a key, at about 3 requests per second, and it follows the site's `robots.txt` (which allows the pages the Actor reads and disallows query-string addresses, so the Actor never uses them). Private sellers' names and phone numbers are never output. Phone numbers, e-mails, messenger handles and links written inside ad descriptions are removed, and agent site addresses named after a phone number are hidden unless you turn on the contact switch. lun.ua publishes terms of use that restrict copying of its content: check them against your own use before you run large collections, and use the data in line with Ukrainian data protection law.

### 🔗 Limits you should know

- lun.ua serves 24 ads per search page and no second page, so a single page gives 24 rows. **Go deeper** (on by default) follows the site's district, microdistrict, street, housing-complex and room-count links two levels down; **Walk the sitemap** reads every search page the sitemap lists.
- lun.ua search addresses carry the filters in the path, so there are no price or area filters. Filter the dataset afterwards on `price`, `areaBuilt` and `rooms`.
- The same ad is often published on lun.ua and rieltor.ua. `propertyGroupId` and `duplicateOffersCount` mark duplicates inside lun.ua.

### FAQ: LUN.ua scraper questions and answers

**Does the LUN.ua scraper need a proxy or a lun.ua account?**
No. It uses plain requests, a few at a time with a short pause, and needs no login, no API key and no proxy. Cloud runs finished without a single blocked request. You only need an Apify account, and the free plan returns up to 10 rows per run, which is enough to test every record type.

**How do I get more than 24 ads from one search?**
Keep **Go deeper** on. The site shows 24 ads per search page and no second page, so the Actor follows the page's own links to districts, microdistricts, streets, housing complexes and room counts. A default Kyiv apartments search returned 2,577 distinct ads in 4 minutes. Turn on **Walk the sitemap** to reach the most ads.

**Which currency do the ads use?**
The currency of the ad: mostly US dollars for sales, and hryvnia or dollars for rent. `currency` holds the ISO code and `pricePeriod` says `month` or `day` for rentals. Project amounts come in both hryvnia and dollars, and the rate used is in `usdRate`. The Actor does not convert one currency into another.

**Does it return phone numbers?**
Not by default. With **Include business contact data** on, listings posted by agencies get the agency phone numbers and the realtor name, and project rows get the sales phone. Private sellers never get any contact data, and phone numbers written inside ad descriptions are removed in every case.

**Can I get old or expired listings?**
No. lun.ua removes ads that are gone, so the Actor returns the live catalog only, with `publishedAt` and `updatedAt` on every ad. If you need a history, schedule a run every day and keep the datasets, or use the only-new mode and store the rows in your own database.

**What is the difference between a listing and a project row?**
A listing row is one ad for sale or rent, with price, rooms, area, address and seller. A project row is one new-build residential complex, with price ranges, units, construction status, financing terms and developer. Developer, promotion and floor-plan rows come from the same new-build catalog and are charged as their own events.

**How do I get only the new ads every day?**
Turn on **Only new rows** and schedule the Actor. It remembers the rows already returned for the same search in a store of your own account and returns just the new ones. Use the same **State key** for the same search, and **Reset seen rows** to start over.

**Why are some fields empty on a listing?**
Because the ad does not state them. Land has no rooms or floor, and only some ads fill heating, utilities or renovation. Empty columns are left out of the row instead of being filled with null, so the number of columns changes from one row to the next. Check the fill rates above before you rely on a column.

**How do I get help or ask for a missing field?**
Write to contact.punkrecordsdata@gmail.com with the search you ran and the field you need. Bug reports with a run link are the fastest to fix, and a missing column is usually a small change when lun.ua already shows the value on the page.

**🆘 Need Help?** contact.punkrecordsdata@gmail.com

> **⚠️ Disclaimer:** independent tool, not affiliated with lun.ua. It collects only publicly available data.

Last updated: 2026-11-03

# Actor input Schema

## `recordTypes` (type: `array`):

What to return. Listings: one row per sale, rent or daily-rent ad (price and price history, areas, rooms, floor, building, place with coordinates, photos, seller type). Projects: one row per new-build residential complex (price ranges, units, construction status, developer, photos). Developers: one row per developer with its projects. Promotions: one row per active developer offer. Floor plans: one row per apartment layout of a new-build project. Every row counts toward Max Items and types are collected in the order listed here. Projects, developers and floor plans come from the lun.ua sitemaps, filtered by the cities below (developers ignore the city).

## `startUrls` (type: `array`):

Paste lun.ua pages instead of using the filters, for example lun.ua/sale/kyiv/flats-pecherskyi-district or lun.ua/new/kyiv/<project>. A search page brings its own filters, so the filters below are ignored. Leave empty to use the filters.

## `operation` (type: `string`):

Sale, or rent (monthly and daily). Applies to listings.

## `cities` (type: `array`):

Regional centres to search, for example Kyiv or Lviv. A city page also lists the towns around it. Also picks the cities for projects, floor plans and promotions.

## `coverage` (type: `string`):

The city with the towns around it, or the whole region (oblast), which is much larger. Region pages exist only without Rooms and Ready-made filters.

## `propertyTypes` (type: `array`):

Apartments, houses, land, commercial and more. Rent pages exist only for apartments, houses, townhouses and commercial; other types are skipped for rent.

## `language` (type: `string`):

Language of listing and project texts. Developers and floor plans are always Ukrainian.

## `rooms` (type: `array`):

Only apartments and houses with this many rooms, one page per value. Empty means any. Cannot be combined with Ready-made filters.

## `features` (type: `array`):

Filters lun.ua offers as pages, for example without intermediaries (owners), euro renovation or installment plan. Cannot be combined with Rooms.

## `expandBy` (type: `array`):

Follows links to districts, microdistricts, streets, complexes and room pages, two levels down, until the row limit is reached. Remove all to read only the page you asked for.

## `useSitemaps` (type: `boolean`):

After the pages above, also reads every search page in the site sitemap for your operation, cities and property types. Reaches the most ads and takes the longest.

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

Maximum rows in total. Free plans are capped at 10 rows per run; paid plans up to 1,000,000.

## `maxRunSeconds` (type: `integer`):

Stop collecting after this many seconds and return what was gathered, so a very wide search never runs unbounded.

## `includeContactDetails` (type: `boolean`):

Adds agency phones and realtor name to agency listings and the sales phone to project rows. Private sellers never get contact data.

## `onlyNew` (type: `boolean`):

Skip rows this same search already returned in an earlier run; skipped rows are not charged. Max rows then means N new rows.

## `stateKey` (type: `string`):

Label that separates two monitors of identical searches, for example client-a. Empty uses only the filters.

## `resetSeen` (type: `boolean`):

Forget everything this monitor remembered and start again.

## Actor input object example

```json
{
  "recordTypes": [
    "listings"
  ],
  "startUrls": [],
  "operation": "sale",
  "cities": [
    "kyiv"
  ],
  "coverage": "city",
  "propertyTypes": [
    "flats"
  ],
  "language": "uk",
  "rooms": [],
  "features": [],
  "expandBy": [
    "districts",
    "microdistricts",
    "streets",
    "complexes",
    "roomPages"
  ],
  "useSitemaps": false,
  "maxItems": 10,
  "maxRunSeconds": 1800,
  "includeContactDetails": false,
  "onlyNew": false,
  "stateKey": "",
  "resetSeen": false
}
```

# Actor output Schema

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

Key fields per row

## `fullData` (type: `string`):

Complete dataset with all fields

# 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 = {
    "recordTypes": [
        "listings"
    ],
    "startUrls": [],
    "operation": "sale",
    "cities": [
        "kyiv"
    ],
    "coverage": "city",
    "propertyTypes": [
        "flats"
    ],
    "language": "uk",
    "expandBy": [
        "districts",
        "microdistricts",
        "streets",
        "complexes",
        "roomPages"
    ],
    "maxItems": 10,
    "maxRunSeconds": 1800
};

// Run the Actor and wait for it to finish
const run = await client.actor("recordsdata/lun-ua-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 = {
    "recordTypes": ["listings"],
    "startUrls": [],
    "operation": "sale",
    "cities": ["kyiv"],
    "coverage": "city",
    "propertyTypes": ["flats"],
    "language": "uk",
    "expandBy": [
        "districts",
        "microdistricts",
        "streets",
        "complexes",
        "roomPages",
    ],
    "maxItems": 10,
    "maxRunSeconds": 1800,
}

# Run the Actor and wait for it to finish
run = client.actor("recordsdata/lun-ua-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 '{
  "recordTypes": [
    "listings"
  ],
  "startUrls": [],
  "operation": "sale",
  "cities": [
    "kyiv"
  ],
  "coverage": "city",
  "propertyTypes": [
    "flats"
  ],
  "language": "uk",
  "expandBy": [
    "districts",
    "microdistricts",
    "streets",
    "complexes",
    "roomPages"
  ],
  "maxItems": 10,
  "maxRunSeconds": 1800
}' |
apify call recordsdata/lun-ua-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,recordsdata/lun-ua-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/JqqdkhBcCfCkhZX74/builds/UmjXSJHaOIfY8g6pq/openapi.json
