# Emlakjet Scraper \[Only $1/1K💰] | Turkey Real Estate | Agents (`ahmed_jasarevic/emlakjet-scraper`) Actor

Scrape emlakjet.com Turkish property listings - price in TRY, rooms, m2, floor, city/district/mahalle, coordinates, photos - plus the agent/office directory with phone and WhatsApp. For Turkey real-estate market research and lead generation.

- **URL**: https://apify.com/ahmed_jasarevic/emlakjet-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 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/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

## Emlakjet Scraper

Emlakjet scraper for Turkey's property marketplace: extract satilik (for sale) and kiralik (for rent) listings across all 81 provinces with price in TRY, rooms, m2, floor, city/district/mahalle, coordinates, photos - plus the emlak agent/office directory with phone and WhatsApp contacts.

### Main Use Cases

- Turkey real-estate market research - asking prices, price per m2 and supply by province and district
- Investment screening and yield analysis - compare satilik and kiralik asking prices in the same district
- Buyer-agent and brokerage lead generation from the emlak office and consultant directories
- Rental and daily-rental market tracking across coastal and city districts
- Feeding a valuation or proptech product with live Turkish listing data

### How It Works

![How the Emlakjet Scraper works: search URLs to Turkish sale and rent listings with prices, square metres and agent contacts.](https://api.apify.com/v2/key-value-stores/oeuA0kLOyhbRM4fzt/records/how-it-works-emlakjet.webp)

emlakjet.com is a Next.js (App Router) site. Its search and listing pages are server-rendered, so the actor is a lightweight Cheerio (HTTP) crawler - no browser. It reads two structured sources straight out of the served HTML:

1. The embedded schema.org `RealEstateListing` JSON-LD on search pages, used to discover listing links and emit summaries.
2. The React Server Component (RSC) flight payload (`self.__next_f`), where it brace-matches the application-state objects for full listing details (including the agent block) and for the office/consultant directories.

The agent phone number is recovered from the agent's public WhatsApp deeplink when the raw contact field is masked in the payload. Search pages paginate automatically (30 listings per page) until `maxListings` is reached.

### Scrape Emlakjet Listings And Agent Contacts (Satilik / Kiralik)

Pass one or more Emlakjet search URLs - for example `https://www.emlakjet.com/satilik-konut/istanbul` or `https://www.emlakjet.com/kiralik-konut/ankara` - and the actor walks the result pages, opening each listing for the full record: price in TRY, rooms (e.g. `3+1`), gross and net m2, floor, city/district/mahalle, coordinates, image gallery and the advertising agent or office with its phone/WhatsApp. Add `https://www.emlakjet.com/emlak-ofisleri` or `https://www.emlakjet.com/danismanlar` to also pull the office and consultant directories with their active-listing counts.

### Input

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `searchUrls` | string\[] | No | `["https://www.emlakjet.com/satilik-konut/istanbul"]` | Emlakjet search/category URLs whose result pages should be crawled. Listing links are discovered from the embedded schema.org data. |
| `listingUrls` | string\[] | No | - | Direct listing detail URLs (`https://www.emlakjet.com/ilan/...`); each is scraped for full details. |
| `officeUrls` | string\[] | No | - | `https://www.emlakjet.com/emlak-ofisleri` or `/danismanlar`, or an individual office/consultant profile URL. |
| `maxListings` | integer | No | `100` | Maximum listing detail pages (or directory rows) to collect for paying users. |
| `maxSearchPages` | integer | No | `0` | Pages per search query. `0` = automatic (enough pages to fill `maxListings`); a positive value hard-caps pagination. |
| `scrapeDetails` | boolean | No | `true` | Open each listing for full details (agent, phone/WhatsApp, rooms, m2, floor, coordinates). Off = summary-only from search pages. |
| `maxConcurrency` | integer | No | `10` | Parallel requests. |
| `maxRequestsPerCrawl` | integer | No | `500` | Hard cap on total HTTP requests. |
| `proxy` | object | No | off | Apify Proxy picker; enable if a cloud IP is ever challenged. |

### Output

Rows are written to the default dataset and distinguished by `recordType`.

**Listings** (`recordType: "listing"`):

| Field | Description |
|---|---|
| `listingId`, `title`, `url`, `slug` | Identity and link |
| `transactionType` | `sale` / `rent` |
| `propertyType` | `residential` / `land` / `commercial` |
| `price`, `currency`, `pricePerSqm`, `previousPrice` | Price in TRY |
| `rooms` | e.g. `4+1` |
| `grossArea`, `netArea` | m2 (brut / net) |
| `floor`, `totalFloors`, `bathrooms`, `buildingAge` | Building details |
| `city`, `cityId`, `district`, `districtId`, `mahalle`, `mahalleId` | il / ilce / mahalle |
| `locationAddress`, `latitude`, `longitude` | Location |
| `images`, `mainImage`, `imageCount` | Photo gallery |
| `listingDate`, `updatedDate` | ISO timestamps |
| `agent` | `{ id, memberId, name, companyName, type, membershipLevel, isVerified, licenseNo, yearsActive, officeUrl, consultantUrl, hasPhone, phone, whatsappUrl }` |
| `quickInfos`, `properties` | Full attribute map (heating, parking, deed status, ...) |

**Directory rows:** `officeDirectory`, `consultantDirectory`, `office`, `consultant` - with `activeListingCount`, `last3MonthListingCount`, `membershipYears`, `phone`, `languages`, `location` and (for consultants) `reviewCount`, `avatar`.

### Example Input

```json
{
  "searchUrls": [
    "https://www.emlakjet.com/satilik-konut/istanbul",
    "https://www.emlakjet.com/kiralik-konut/ankara"
  ],
  "officeUrls": ["https://www.emlakjet.com/emlak-ofisleri"],
  "maxListings": 300,
  "scrapeDetails": true
}
```

### Example Output

```json
{
  "recordType": "listing",
  "listingId": "19727527",
  "title": "Han Emlak'tan Ethemefendi'de 3+1 Ultra Luks Yeni Bina",
  "url": "https://www.emlakjet.com/ilan/...-19727527",
  "transactionType": "sale",
  "propertyType": "residential",
  "price": 22450000,
  "currency": "TRY",
  "pricePerSqm": 160357,
  "rooms": "3+1",
  "grossArea": 140,
  "netArea": 125,
  "floor": "3. Kat",
  "city": "Istanbul",
  "district": "Kadikoy",
  "mahalle": "Erenkoy Mahallesi",
  "latitude": 40.9765,
  "longitude": 29.0553,
  "listingDate": "2026-08-14T00:00:00.000Z",
  "agent": {
    "name": "Han Emlak",
    "companyName": "Han Gayrimenkul",
    "type": "office",
    "isVerified": true,
    "hasPhone": true,
    "phone": "+90 555 000 0000",
    "officeUrl": "https://www.emlakjet.com/emlak-ofisleri/han-emlak"
  },
  "scrapedAt": "2026-10-15T15:25:00.000Z"
}
```

### Integrations & Automation

- **Apify API / JS / Python clients** - load listings into a valuation model, BI tool or proptech backend.
- **Webhooks** - trigger downstream processing when a run finishes.
- **Zapier, Make, Google Sheets** - export a district price table or a broker lead list.
- **Scheduling** - run daily to track new listings and asking-price movement for a district set.

### Related Actors

- [Emlakjet Scraper - Turkey Property Listings (Emlak)](https://apify.com/vladignatyev/emlakjet-scraper) - established Emlakjet listing scraper.
- [Emlakjet Scraper](https://apify.com/olivine_lemur/emlakjet-scraper) - category-driven Emlakjet scraper.
- [Sotheby's Realty Scraper](https://apify.com/ahmed_jasarevic/sothebysrealty-scraper) - luxury real-estate listings to pair with Turkish market data.

### FAQ

#### Why use this actor instead of the official API?

Emlakjet does not publish a public listings API - its internal API requires an auth token the frontend holds (unauthenticated calls return 401). This actor reads the server-rendered HTML and the embedded structured data that the public pages already serve, so no key is required.

#### What are alternatives to this actor?

Commercial third-party APIs exist that wrap Emlakjet into JSON endpoints (for example ReefAPI and similar providers) and add price history, nearby places and demographics - those require a subscription. For a self-serve scrape of listings and the agent directory, this actor is the direct route.

#### Which provinces and districts are covered?

All 81 Turkish provinces are reachable through their Emlakjet search URLs (`/satilik-konut/istanbul`, `/kiralik-konut/ankara`, district pages, and so on). Coverage is limited only by the URLs you supply and `maxListings`.

#### How do I compare sale and rental prices for the same area?

Run the actor once with a `satilik-konut` search URL and once with `kiralik-konut` for the same district, then join the two datasets on district and rooms. Note that rental prices are monthly while sale prices are total, and that some fields (owner phone) may be masked on the source page.

### For AI Agents & LLM Apps

Purpose: return Emlakjet property listings and/or the agent/office directory as structured rows, for a set of Emlakjet search or profile URLs.

Minimal working input:

```json
{ "searchUrls": ["https://www.emlakjet.com/satilik-konut/istanbul"] }
```

Variant input (directory mode):

```json
{ "officeUrls": ["https://www.emlakjet.com/emlak-ofisleri"] }
```

Output fields - listings: `recordType`, `listingId`, `title`, `url`, `slug`, `transactionType`, `propertyType`, `price`, `currency`, `pricePerSqm`, `previousPrice`, `rooms`, `grossArea`, `netArea`, `floor`, `totalFloors`, `bathrooms`, `buildingAge`, `city`, `district`, `mahalle`, `locationAddress`, `latitude`, `longitude`, `images`, `mainImage`, `imageCount`, `listingDate`, `updatedDate`, `agent`, `quickInfos`, `properties`, `scrapedAt`. Directory: `recordType`, `activeListingCount`, `last3MonthListingCount`, `membershipYears`, `phone`, `languages`, `location`, `reviewCount`, `avatar`.

Behaviors an agent should know:

- `recordType` distinguishes `listing`, `listingSummary`, `office`, `consultant`, `officeDirectory` and `consultantDirectory` rows in one dataset - filter on it.
- `maxSearchPages` defaults to `0` (auto): the actor crawls exactly enough pages to fill `maxListings`, so a request for 100 listings is not silently capped.
- `scrapeDetails` defaults to `true` and adds one request per listing; turning it off returns only the summary data embedded in search pages (no agent/phone/coordinates).
- `maxListings` defaults to 100; free users get a capped preview (10 rows).
- Pagination uses `?sayfa=N` (30 listings per page) and stops as soon as the listing budget is filled.

Billing: pay-per-event - about $1 per 1,000 result rows, plus a per-listing detail charge (about $3 per 1,000) when `scrapeDetails` is on, and the one-time actor-start event; lower on paid Apify plans.

### Legal & Compliance Disclaimer

This actor is independent and is not affiliated with, endorsed by, or sponsored by Emlakjet. It reads only publicly available listing, search and agent-directory pages; it does not log in or access account-only data. Agent names and phone numbers are business contact details the platform publishes on its listings. Turkish data-protection law (KVKK) and, for non-Turkish data subjects, the GDPR may govern your use of the personal data in rows that include an agent's name or phone number - you are responsible for your own compliance with Emlakjet's terms of service and with applicable law. Data is provided for market research and lawful outreach, and should not be used to send unsolicited commercial messages in violation of applicable rules.

### SEO Keywords

emlakjet scraper, turkey real estate data, turkish property listings, emlakjet api, satilik konut, kiralik konut, turkey property price data, istanbul apartment prices, price per square meter turkey, emlak ofisleri directory, turkish rental market data, turkey housing market scraper, emlak ilan data, sahibinden alternative, real estate investor data turkey, property agent leads turkey, turkey citizenship investment property, emlakjet listings json

# Actor input Schema

## `searchUrls` (type: `array`):

Emlakjet search or category URLs whose result pages should be crawled, e.g. https://www.emlakjet.com/satilik-konut/istanbul or https://www.emlakjet.com/kiralik-konut/ankara. Listing links are discovered from the embedded schema.org data on each page.

## `listingUrls` (type: `array`):

Direct links to listing detail pages, e.g. https://www.emlakjet.com/ilan/.... Each is scraped for full details.

## `officeUrls` (type: `array`):

Emlakjet agent directory pages. Use https://www.emlakjet.com/emlak-ofisleri (office directory with active-listing counts) or https://www.emlakjet.com/danismanlar (consultant directory). Individual office/consultant profile URLs (e.g. https://www.emlakjet.com/emlak-ofisleri/<slug>) are also supported.

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

Maximum number of listing detail pages (or directory rows) to collect for paying users.

## `maxSearchPages` (type: `integer`):

Maximum pages of each search result query to crawl (30 listings per page). 0 = automatic: crawl enough pages to reach maxListings. Set a positive number to hard-cap pagination.

## `scrapeDetails` (type: `boolean`):

If enabled (recommended), each listing link is opened to collect full details (agent, phone/WhatsApp, rooms, m², floor, coordinates). If disabled, only the summary data embedded in the search pages is returned (cheaper, but no agent/phone).

## `maxConcurrency` (type: `integer`):

Maximum number of parallel requests.

## `maxRequestsPerCrawl` (type: `integer`):

Hard safety cap on the total number of HTTP requests the crawler may make.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "searchUrls": [
    "https://www.emlakjet.com/satilik-konut/istanbul"
  ],
  "listingUrls": [],
  "officeUrls": [],
  "maxListings": 100,
  "maxSearchPages": 0,
  "scrapeDetails": true,
  "maxConcurrency": 10,
  "maxRequestsPerCrawl": 500,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchUrls": [
        "https://www.emlakjet.com/satilik-konut/istanbul"
    ],
    "listingUrls": [],
    "officeUrls": [],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/emlakjet-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 = {
    "searchUrls": ["https://www.emlakjet.com/satilik-konut/istanbul"],
    "listingUrls": [],
    "officeUrls": [],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/emlakjet-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 '{
  "searchUrls": [
    "https://www.emlakjet.com/satilik-konut/istanbul"
  ],
  "listingUrls": [],
  "officeUrls": [],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/emlakjet-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/emlakjet-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/9xmLHMLPsaX1ukO7C/builds/jI62mRH8yyw1eFhvH/openapi.json
