# Njuskalo.hr Property Scraper (`logiover/njuskalo-hr-property-scraper`) Actor

Scrape real estate listings from Njuskalo.hr — Croatia's #1 classifieds portal. Extract apartments, houses, land, commercial space and garages (sale or rent) by city or county, with price (EUR), surface area, rooms, parsed Croatian address (city → district → micro-location), image and listing labels

- **URL**: https://apify.com/logiover/njuskalo-hr-property-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Njuskalo.hr Property Scraper

Scrape real estate listings from **[Njuskalo.hr](https://www.njuskalo.hr)** — Croatia's #1 classifieds portal — into a clean, structured Apify dataset.

This actor extracts apartments, houses, land, commercial space, garages and rooms (sale or rent) by location, price (EUR), area and rooms. Each record includes price, surface area, parsed Croatian address (city → municipality → district), advertiser snippet, image and listing labels.

---

### Features

- 🇭🇷 **Croatia-wide coverage** — every Njuskalo SEO city slug is supported (Zagreb, Split, Rijeka, Osijek, Pula, Zadar, Šibenik, Dubrovnik, …).
- 💰 **Native EUR pricing** with auto-computed `pricePerSqm`.
- 🏘️ **Location chain parsing** — city, municipality, district and neighborhood split from the listing's location string.
- 🏷️ **Sponsored / VauVau detection** — premium card flags exposed via `isExclusive` and `labels`.
- 🛡️ **Anti-bot bypass via Playwright** — headless Chromium with fingerprint rotation, residential proxy, cookie-banner handling and session retirement on block detection.
- 🔁 **De-duplication & dynamic pagination** — stops automatically when pages return no new IDs.

---

### Architecture

Njuskalo deploys aggressive bot detection (Cloudflare-grade). Plain HTTP scraping does not work — the actor uses a real **headless Chromium** browser via Crawlee's `PlaywrightCrawler`:

1. **Browser session** with rotated fingerprints (Chrome, Windows/macOS, hr-HR locale) and residential proxy.
2. **Heavy-asset blocking** — images, media and fonts are aborted at the network layer to make pages 3–5× faster.
3. **Cookie banner handling** — Didomi consent button auto-clicked on first navigation.
4. **Listing extraction** — full HTML retrieved once per page, then parsed with `cheerio`. Cards live under `.EntityList--ListItemRegularAd .EntityList-item` (regular) and `.EntityList--VauVau .EntityList-item` (sponsored).
5. **Field parsing** — title, detail URL, price (`strong.price--hrk` — legacy class kept after EUR migration), area & rooms (from `dl/dt/dd` or free-text "Lokacija: …" / "X m²"), date posted (`<time>`), image, location chain.
6. **Block detection** — short responses, captcha/Cloudflare titles or zero `EntityList-item` matches retire the session and trigger a retry with a fresh proxy IP.
7. **Pagination** — dynamic: each successful page enqueues `?page=N+1` until empty or cap.

---

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `locationSlugs` | `string[]` | `["zagreb"]` | Croatian city slugs appended to the category URL. Examples: `zagreb`, `split`, `rijeka`, `osijek`, `zadar`, `pula`, `sibenik`, `dubrovnik`, `karlovac`, `varazdin`, `slavonski-brod`, `velika-gorica`. Empty array = nationwide search. |
| `transaction` | `sale \| rent` | `sale` | Maps to `prodaja` / `iznajmljivanje`. |
| `propertyType` | enum | `apartment` | `apartment` (stan) / `house` (kuća) / `land` (zemljište) / `commercial` (poslovni prostor) / `garage` (garaža) / `room` (soba) / `vacation` (vikendica). |
| `priceMin` / `priceMax` | int (EUR) | `0` | `0` = no bound. |
| `areaMin` / `areaMax` | int (m²) | `0` | `0` = no bound. |
| `roomsMin` / `roomsMax` | int | `0` | `0` = no bound. |
| `maxListings` | int | `200` | Total cap across all tasks. `0` = unlimited. |
| `maxPagesPerTask` | int | `10` | Pagination depth per location (≈ 25 listings per page). |
| `requestDelay` | int (ms) | `2500` | Inter-page delay. **≥ 2000 ms strongly recommended** — Njuskalo throttles aggressively. |
| `maxRetries` | int | `3` | Retries per page on errors / block detection (rotates session). |
| `proxyConfiguration` | proxy | RESIDENTIAL + HR | **Required.** Datacenter IPs are blocked instantly; residential country=HR is mandatory. |

#### Example input

```json
{
  "locationSlugs": ["zagreb", "split"],
  "transaction": "sale",
  "propertyType": "apartment",
  "priceMin": 100000,
  "priceMax": 350000,
  "areaMin": 40,
  "areaMax": 100,
  "roomsMin": 2,
  "roomsMax": 4,
  "maxListings": 500,
  "maxPagesPerTask": 25,
  "requestDelay": 2500,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "HR"
  }
}
````

***

### URL pattern

```
https://www.njuskalo.hr/{prodaja|iznajmljivanje}-{stanova|kuca|zemljista|...}[-{location-slug}]
  ?cijenaMin=<int>
  &cijenaMax=<int>
  &povrsinaMin=<int>
  &povrsinaMax=<int>
  &sobeMin=<int>
  &sobeMax=<int>
  &page=<N>
```

URL filter parameters (`cijenaMin`, etc.) are **best-effort** — the actor also runs the same min/max filters in-memory after parsing each card, so result correctness does not depend on Njuskalo respecting the query string.

***

### Output

One Apify dataset record per listing. Headline fields:

| Field | Description |
|---|---|
| `adId` | Njuskalo numeric listing ID |
| `detailUrl` | Full URL to the listing page |
| `title` | Listing title |
| `shortDescription` | Card-level description snippet |
| `transactionType` | `sale` / `rent` |
| `propertyType` | `apartment` / `house` / … |
| `price` | Price in EUR (number) |
| `priceCurrency` | `EUR` (rare legacy `HRK` listings handled) |
| `pricePerSqm` | Price per m² (parsed or computed) |
| `areaSqm` | Usable surface area (m²) |
| `terrainAreaSqm` | Plot area (houses, land) |
| `rooms` | Number of rooms |
| `floor` / `totalFloors` | When present in the card |
| `buildingType` / `heatingType` / `yearBuilt` | When present in the card |
| `country` | `Hrvatska` |
| `city` / `municipality` / `district` / `microLocation` | Parsed from the listing's "Lokacija" string |
| `fullAddress` | Composed from the four location parts |
| `mainImageUrl` / `imageUrls` / `imageCount` | Cover photo (gallery requires detail-page fetch) |
| `isExclusive` | `true` for sponsored / VauVau cards |
| `labels` | Tier tags (`VauVau`, `Premium`, `Featured`, `Top`, …) |
| `datePosted` | Date string from `<time>` |
| `searchTransaction` `searchPropertyType` `searchLocation` `searchUrl` | Echo of the input search parameters |
| `scrapedAt` | ISO-8601 scrape timestamp |

Two dataset views are pre-configured: **Overview** (compact) and **Full Detail**.

> **Detail-only fields** — `latitude`, `longitude`, full `imageUrls` gallery, `roomsLabel`, `street`, `advertiserId`, `advertiserName`, `advertiserUrl`, feature flags (`hasElevator`, `hasParking`, `hasGarage`, `hasTerrace`, `hasBalcony`, `isFurnished`, `isRegistered`) are populated from Njuskalo's individual listing pages, not the search results. The list-endpoint scraper leaves them as `null` — open a feature request if you need detail-page enrichment.

***

### Important notes

- **Anti-bot is aggressive.** This is the most heavily protected site in this scraper family. Even with residential HR proxies, expect occasional `[BLOCKED]` warnings — the actor handles them by retiring the session and retrying with a new IP. Keep `requestDelay` ≥ 2000 ms and concurrency at 1.
- **Throughput is browser-bound.** Plan for ~6–10 listings per second on a clean session, dropping to ~1–2/s when bot detection fires. A 200-listing run typically takes 1–3 minutes; a 1,000-listing run can take 10–20 minutes.
- **EUR is the standard currency** — Croatia adopted EUR in January 2023. The legacy CSS class `price--hrk` was kept on the price element after migration; the actor treats its content as EUR by default and only flags `HRK` if the symbol explicitly appears.
- **Rooms semantics** — Njuskalo uses integer room counts (1, 2, 3, …) unlike Halooglasi (which uses 0.5 increments). Half-room "garsonjera" listings appear under `rooms: 1` or `rooms: null`.
- **Pagination cap** — Njuskalo paginates indefinitely but new content is rare past page 50. For wide queries, narrow with `priceMin/Max` and `areaMin/Max` to slice the inventory rather than crawling deep.

***

### Common location slugs

**Major cities** — `zagreb`, `split`, `rijeka`, `osijek`, `zadar`, `pula`, `slavonski-brod`, `karlovac`, `varazdin`, `sibenik`, `dubrovnik`, `bjelovar`, `kastav`, `koprivnica`, `vinkovci`, `velika-gorica`, `vukovar`, `samobor`, `sisak`, `crikvenica`, `pozega`, `metkovic`, `cakovec`

**Coastal/Adriatic** — `opatija`, `rovinj`, `porec`, `umag`, `medulin`, `fazana`, `crikvenica`, `novi-vinodolski`, `omis`, `trogir`, `kastela`, `makarska`, `nin`, `biograd-na-moru`, `sukosan`, `vodice`, `primosten`, `cavtat`

**Islands** — `krk`, `cres`, `mali-losinj`, `rab`, `pag`, `brac`, `hvar`, `vis`, `korcula`, `mljet`

To find more, browse a category page on njuskalo.hr and copy the city slug from the URL between `{category-slug}-` and `?`.

***

### Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| `[BLOCKED] suspected anti-bot page` repeated | IP fingerprint flagged | Increase `requestDelay` to 4000+ ms, raise `maxRetries` |
| 0 listings parsed but page loads | Cookie banner re-prompted | Already handled — verify Didomi click selector still `#didomi-notice-agree-button` |
| Only sponsored ("VauVau") cards saved | Regular ad list selector changed | Selector list in `parseEntity` covers known variants — open an issue if the site updates |
| `latitude` / `longitude` always null | List endpoint doesn't expose coordinates | Expected — would require per-ad detail fetch |
| Throughput much lower than expected | Heavy anti-bot triggering | Drop concurrency to 1 (default), increase delay, ensure RESIDENTIAL+HR proxy |

***

### License

Apache-2.0

# Actor input Schema

## `locationSlugs` (type: `array`):

Croatian city slugs appended to the category URL. Each slug becomes its own scraping task. Leave empty for nationwide. Common values: `zagreb`, `split`, `rijeka`, `osijek`, `zadar`, `pula`, `sibenik`, `dubrovnik`, `karlovac`, `varazdin`, `slavonski-brod`, `velika-gorica`, `koprivnica`, `samobor`. Find more by browsing njuskalo.hr/{category} and copying the city suffix from the URL.

## `transaction` (type: `string`):

Sale (`prodaja`) or rent (`iznajmljivanje`).

## `propertyType` (type: `string`):

Njuskalo URL category slug.

## `priceMin` (type: `integer`):

Minimum price in EUR. 0 = no minimum.

## `priceMax` (type: `integer`):

Maximum price in EUR. 0 = no maximum.

## `areaMin` (type: `integer`):

Minimum surface area. 0 = no minimum.

## `areaMax` (type: `integer`):

Maximum surface area. 0 = no maximum.

## `roomsMin` (type: `integer`):

Minimum room count. 0 = no minimum.

## `roomsMax` (type: `integer`):

Maximum room count. 0 = no maximum.

## `maxListings` (type: `integer`):

Total cap across all location tasks (0 = unlimited).

## `maxPagesPerTask` (type: `integer`):

Pagination depth per location. Njuskalo serves ~25 listings per page.

## `requestDelay` (type: `integer`):

Delay between sequential page requests. Njuskalo has aggressive bot detection — keep ≥ 2000ms.

## `maxRetries` (type: `integer`):

Retries per request on errors (rotates browser session/proxy IP).

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

Apify Proxy is REQUIRED. Njuskalo has aggressive anti-bot — RESIDENTIAL with country=HR is mandatory; datacenter IPs get blocked instantly.

## Actor input object example

```json
{
  "locationSlugs": [
    "zagreb"
  ],
  "transaction": "sale",
  "propertyType": "apartment",
  "priceMin": 0,
  "priceMax": 0,
  "areaMin": 0,
  "areaMax": 0,
  "roomsMin": 0,
  "roomsMax": 0,
  "maxListings": 200,
  "maxPagesPerTask": 10,
  "requestDelay": 2500,
  "maxRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "HR"
  }
}
```

# Actor output Schema

## `adId` (type: `string`):

Njuskalo listing numeric ID

## `detailUrl` (type: `string`):

Full URL to the listing page

## `title` (type: `string`):

Listing title

## `shortDescription` (type: `string`):

Card-level description snippet

## `transactionType` (type: `string`):

sale / rent

## `propertyType` (type: `string`):

apartment / house / land / commercial / ...

## `advertType` (type: `string`):

Agency / Private

## `price` (type: `string`):

Total price in EUR

## `priceCurrency` (type: `string`):

Currency (EUR)

## `pricePerSqm` (type: `string`):

Price per square meter

## `areaSqm` (type: `string`):

Usable surface area

## `terrainAreaSqm` (type: `string`):

Plot/terrain area

## `rooms` (type: `string`):

Number of rooms

## `roomsLabel` (type: `string`):

Croatian room label

## `floor` (type: `string`):

Floor number/label

## `totalFloors` (type: `string`):

Total floors in the building

## `buildingType` (type: `string`):

Stara gradnja / Novogradnja

## `heatingType` (type: `string`):

Heating system

## `yearBuilt` (type: `string`):

Construction year

## `country` (type: `string`):

Country (Hrvatska default)

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

City

## `municipality` (type: `string`):

Općina/županija

## `district` (type: `string`):

City district

## `microLocation` (type: `string`):

Neighborhood

## `street` (type: `string`):

Street name

## `fullAddress` (type: `string`):

Composed address string

## `latitude` (type: `string`):

GPS latitude

## `longitude` (type: `string`):

GPS longitude

## `mainImageUrl` (type: `string`):

Cover photo

## `imageUrls` (type: `string`):

All listing images

## `imageCount` (type: `string`):

Total images

## `advertiserId` (type: `string`):

Advertiser ID

## `advertiserName` (type: `string`):

Advertiser display name

## `advertiserUrl` (type: `string`):

Advertiser profile page

## `advertiserType` (type: `string`):

Agency / Private

## `isRegistered` (type: `string`):

Property registered with the cadastre

## `hasElevator` (type: `string`):

Building has elevator

## `hasParking` (type: `string`):

Has parking spot

## `hasGarage` (type: `string`):

Has garage

## `hasTerrace` (type: `string`):

Has terrace

## `hasBalcony` (type: `string`):

Has balcony

## `isFurnished` (type: `string`):

Furnished property

## `isExclusive` (type: `string`):

Sponsored / VauVau listing flag

## `datePosted` (type: `string`):

Most recent post date

## `dateValidFrom` (type: `string`):

Listing valid-from date

## `labels` (type: `string`):

Listing labels/badges

## `searchTransaction` (type: `string`):

Transaction used in search

## `searchPropertyType` (type: `string`):

Property type used in search

## `searchLocation` (type: `string`):

Location slug used in search

## `searchUrl` (type: `string`):

Full search URL used

## `scrapedAt` (type: `string`):

ISO timestamp

# 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 = {
    "locationSlugs": [
        "zagreb"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "HR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/njuskalo-hr-property-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 = {
    "locationSlugs": ["zagreb"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "HR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/njuskalo-hr-property-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "locationSlugs": [
    "zagreb"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "HR"
  }
}' |
apify call logiover/njuskalo-hr-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=logiover/njuskalo-hr-property-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Njuskalo.hr Property Scraper",
        "description": "Scrape real estate listings from Njuskalo.hr — Croatia's #1 classifieds portal. Extract apartments, houses, land, commercial space and garages (sale or rent) by city or county, with price (EUR), surface area, rooms, parsed Croatian address (city → district → micro-location), image and listing labels",
        "version": "0.0",
        "x-build-id": "YXjklaExAvgkNnN16"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/logiover~njuskalo-hr-property-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-logiover-njuskalo-hr-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/logiover~njuskalo-hr-property-scraper/runs": {
            "post": {
                "operationId": "runs-sync-logiover-njuskalo-hr-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/logiover~njuskalo-hr-property-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-logiover-njuskalo-hr-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "proxyConfiguration"
                ],
                "properties": {
                    "locationSlugs": {
                        "title": "Location Slugs",
                        "type": "array",
                        "description": "Croatian city slugs appended to the category URL. Each slug becomes its own scraping task. Leave empty for nationwide. Common values: `zagreb`, `split`, `rijeka`, `osijek`, `zadar`, `pula`, `sibenik`, `dubrovnik`, `karlovac`, `varazdin`, `slavonski-brod`, `velika-gorica`, `koprivnica`, `samobor`. Find more by browsing njuskalo.hr/{category} and copying the city suffix from the URL.",
                        "default": [
                            "zagreb"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "transaction": {
                        "title": "Transaction Type",
                        "enum": [
                            "sale",
                            "rent"
                        ],
                        "type": "string",
                        "description": "Sale (`prodaja`) or rent (`iznajmljivanje`).",
                        "default": "sale"
                    },
                    "propertyType": {
                        "title": "Property Type",
                        "enum": [
                            "apartment",
                            "house",
                            "land",
                            "commercial",
                            "garage",
                            "room",
                            "vacation"
                        ],
                        "type": "string",
                        "description": "Njuskalo URL category slug.",
                        "default": "apartment"
                    },
                    "priceMin": {
                        "title": "Min Price (EUR)",
                        "minimum": 0,
                        "maximum": 100000000,
                        "type": "integer",
                        "description": "Minimum price in EUR. 0 = no minimum.",
                        "default": 0
                    },
                    "priceMax": {
                        "title": "Max Price (EUR)",
                        "minimum": 0,
                        "maximum": 100000000,
                        "type": "integer",
                        "description": "Maximum price in EUR. 0 = no maximum.",
                        "default": 0
                    },
                    "areaMin": {
                        "title": "Min Area (m²)",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Minimum surface area. 0 = no minimum.",
                        "default": 0
                    },
                    "areaMax": {
                        "title": "Max Area (m²)",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Maximum surface area. 0 = no maximum.",
                        "default": 0
                    },
                    "roomsMin": {
                        "title": "Min Rooms",
                        "minimum": 0,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Minimum room count. 0 = no minimum.",
                        "default": 0
                    },
                    "roomsMax": {
                        "title": "Max Rooms",
                        "minimum": 0,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum room count. 0 = no maximum.",
                        "default": 0
                    },
                    "maxListings": {
                        "title": "Max Listings",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Total cap across all location tasks (0 = unlimited).",
                        "default": 200
                    },
                    "maxPagesPerTask": {
                        "title": "Max Pages per Task",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Pagination depth per location. Njuskalo serves ~25 listings per page.",
                        "default": 10
                    },
                    "requestDelay": {
                        "title": "Request Delay (ms)",
                        "minimum": 500,
                        "maximum": 60000,
                        "type": "integer",
                        "description": "Delay between sequential page requests. Njuskalo has aggressive bot detection — keep ≥ 2000ms.",
                        "default": 2500
                    },
                    "maxRetries": {
                        "title": "Max Retries",
                        "minimum": 0,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Retries per request on errors (rotates browser session/proxy IP).",
                        "default": 3
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Apify Proxy is REQUIRED. Njuskalo has aggressive anti-bot — RESIDENTIAL with country=HR is mandatory; datacenter IPs get blocked instantly."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
