Hepsiemlak Scraper - Property Listings, Prices & Contacts avatar

Hepsiemlak Scraper - Property Listings, Prices & Contacts

Pricing

from $1.70 / 1,000 listing records

Go to Apify Store
Hepsiemlak Scraper - Property Listings, Prices & Contacts

Hepsiemlak Scraper - Property Listings, Prices & Contacts

Scrape hepsiemlak.com sale and rental listings by city or district, or paste listing links. Every row carries price, area, rooms, seller and location. Detail enrichment adds specs, description and contact.

Pricing

from $1.70 / 1,000 listing records

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

4

Monthly active users

14 days ago

Last modified

Categories

Share

Hepsiemlak Scraper: Turkey Property Listings

Hepsiemlak Scraper turns hepsiemlak.com into a clean property data feed for Turkey. Get sale (satilik) and rental (kiralik) listings by city or district, or paste listing and catalogue links directly. Every row carries price, area, room plan, seller and location straight from the search page; turn on detail reads for the full spec table, description and contact. Export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • Two ways to find listings. Search by city or district across the country, or paste hepsiemlak.com listing and catalogue links directly.
  • Sale and rental, every property kind. Switch between satilik and kiralik, and narrow to apartments, villas or detached houses.
  • Price and area filters. Bound a search by minimum and maximum price in lira, or minimum and maximum gross area, before a single page is read.
  • Detail reads on demand. Turn on one surcharge per record to add the full spec table, listing number, description and seller contact.
  • Turkish location names, handled. City and district names fold their Turkish letters automatically, so "Şişli" and "Sisli" reach the same search.
  • Built for schedules. Recurring updates return only new and changed listings on repeat runs, and a refused run fails loudly instead of returning an empty dataset.

Use Cases

  • Property investors: compare asking prices, gross area and room plans across Turkish cities and districts to spot value.
  • Real estate agencies: watch competing offices' listings and price changes in the districts you work.
  • Rental market research: track kiralik asking rents by district to follow how the rental market moves.
  • Proptech and listing apps: feed clean listing records with price, area, location and seller into your own product.
  • Market monitoring: schedule recurring runs to catch new listings, price edits and listings going off the market.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
listingId"1000001-1"
urlhepsiemlak.com link to the listing
title"Sample 2+1 apartment near Sample Square"
price / currency4250000 / "TRY"
totalPricedetail-page price line (when Fetch details is on)
grossSqm / netSqm110 / 95
rooms / bedrooms"2+1" / 2
propertyTypes["Apartment"]
city / country"Istanbul" / "TR"
descriptionSnippetone-line summary from the search card
descriptionfull listing description (when Fetch details is on)
sellerName"Sample Realty"
sellerPhoneseller's published contact number (when Fetch details is on)
sellerOfficeUrllink to the seller's agency page
imageUrllisting photo
listingNothe site's own listing number (detail read)
status / lastUpdatedlisting status and last bump date (detail read)
recordType"listing"
sourceType / sourceId"search" / "istanbul" (which location or link found it)
positionslot on the source page
scrapedAt"2026-09-16T00:00:00Z"
changeType / changedFieldsrecurring-updates label and what changed (when Recurring updates is on)

Detail reads also add the floor, building floors, property age, heating, title deed status, furnishing, usage, facade and swap fields to the spec table.

Each listing also carries the site's own search-state attributes when present: county and district, all photos, map coordinates, create, update and start dates, categories, room plan, seller type, owner and firm blocks with their public phones, video link, 360 photo count, price range and the listing flags. Extra fields appear on search rows; none of them add a charge.

How to Use

  1. Pick a mode: search (walk listings by location) or url (paste hepsiemlak.com links).
  2. For search mode, choose Listing type (sale or rent), a property kind, and one or more locations, with optional price and area bounds.
  3. Turn on Fetch details for the full spec table, description and contact, and set Max items to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search apartments for sale in a city:

{
"mode": "search",
"listingType": "sale",
"propertyType": "apartment",
"locations": ["Istanbul"],
"maxItems": 20
}

Rentals in a district, with a price bound and detail reads:

{
"mode": "search",
"listingType": "rent",
"locations": ["Izmir Karsiyaka"],
"maxPrice": 30000,
"fetchDetails": true,
"maxItems": 50
}

Paste listing or catalogue links:

{
"mode": "url",
"urls": [
"https://www.hepsiemlak.com/en/istanbul-satilik/daire/1000001-1",
"https://www.hepsiemlak.com/en/izmir-kiralik"
],
"fetchDetails": true
}

A nationwide sweep bounded by area, no location filter:

{
"mode": "search",
"listingType": "sale",
"minArea": 100,
"maxArea": 200,
"maxItems": 200
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/hepsiemlak-com-scraper").call(run_input={"mode": "search", "locations": ["Istanbul"]})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["title"], listing["price"], listing["currency"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/hepsiemlak-com-scraper').call({ mode: 'search', locations: ['Istanbul'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips listings already collected there, so you don't pay twice.
  • Recurring updates (incrementalMode) is for scheduled runs over the same search or links. Each row is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless Return unchanged rows is on), REAPPEARED or EXPIRED (only after a run that scanned the whole scope, and only with Return gone rows). stateKey names or shares the stored state. ignoreFieldsForChanges lists extra fields (top-level names or dotted paths such as agent.name) to leave out of change detection; they are still returned. Run-describing fields (scrapedAt, sourceType, sourceId, sourceUrl, position) are always excluded. EXPIRED is never produced after a capped run, a Max pages limit, or a pasted link that starts at page=2 or later. The two options cannot be combined on one run. With recurring updates off, output is exactly as before.
  • search mode builds listing paths from Listing type (sale, rent, seasonal-rent), Property kind, Locations and the filters, and walks result pages until Max items.
  • url mode reads each pasted link. Supported shapes: search pages in English or Turkish, city and district catalogues, rent and seasonal-rent catalogues, property-type catalogues, paginated and sorted pages, room-count and owner-listed pages, single listing pages (English or Turkish). Agency directory and developer-firm pages list offices rather than properties, so a pasted one is skipped with a warning naming the link. Filters, sort and property kind in the form are ignored for pasted links.

Filters and sorts (search mode): listing type, property kind, room plan, owner-listed only, price and gross-area bounds, and sort by price or area ascending or descending.

Dataset views

The dataset has three views: Overview (price, area, rooms, location, seller), Details (spec table, description and contact from detail reads) and Changes (change label and changed fields in recurring updates). A run summary is written to the key-value store under OUTPUT.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch walks listing pages for each location; url reads each pasted link.
listingTypestringsalesale reads satilik paths, rent reads kiralik paths, seasonal-rent reads sezonluk-kiralik (holiday let) paths. Search mode only.
propertyTypestringanyNarrow search walks to apartment, villa or detached-house. Pasted links ignore this.
roomCountstring(none)Keep only listings with this room plan, for example 2+1. Search mode only.
ownerOnlybooleanfalseKeep only listings posted by the owner, not by an agency. Search mode only.
sortBystringdefaultprice-asc, price-desc, area-asc or area-desc; default keeps the site order. Search mode only.
locationsarray["Istanbul"]City or district names such as Istanbul, Kadıköy or Izmir Karsiyaka. Each name is resolved through the site's own location lookup (Turkish letters are fine). A name the site does not know stops the run with a message naming it. Districts use the form /en/kadikoy-satilik, not istanbul-kadikoy. Empty means the nationwide listing path.
minPriceinteger(none)Keep only listings at or above this price in lira.
maxPriceinteger(none)Keep only listings at or below this price in lira.
minAreainteger(none)Keep only listings with at least this gross area (m2).
maxAreainteger(none)Keep only listings with at most this gross area (m2).
urlsarrayone example of each supported link shapehepsiemlak.com listing or catalogue links (url mode). Leaving the field untouched in url mode scrapes one example of each shape (search EN/TR, city, rent, seasonal rent, property type, paginated, sorted, room count, owner-listed, detail EN/TR), capped by Max items. Clear the field and paste your own links to scrape only those.
fetchDetailsbooleanfalseRead each listing page for the spec table, description and contact. Adds one detail-enrichment charge per record, at most.
maxItemsinteger20Stop after collecting this many records across all locations and links. 0 means unlimited.
maxPagesinteger0Safety bound on result pages walked per location or link. 0 means no page limit; the run stops at Max items instead.
maxItemsPerSourceinteger(none)Optional extra cap per location or pasted link, on top of Max items. 0 or empty means no per-source cap.
resumeFromRunIdstring(none)Continue one interrupted run by its run or dataset ID. Cannot be combined with recurring updates on one run.
incrementalModebooleanfalseRemember this setup's listings between runs and label every row NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. Cannot be combined with resume on one run.
stateKeystring(none)Name this monitoring setup. Runs with the same key share one baseline; leave empty to derive it from the search setup.
emitUnchangedbooleanfalseAlso return (and bill) UNCHANGED rows. Off by default: unchanged rows are suppressed.
emitExpiredbooleanfalseAlso return (and bill) EXPIRED rows for listings missing from a complete scan. Only on complete scans.
ignoreFieldsForChangesarray[]Incremental mode only. Extra field names (top-level or dotted path) to exclude from UPDATED change detection; still returned.
proxyConfigurationobjectResidential, TurkeyConnection settings. Leave the default unless a run reports that it could not read any results.
mcpConnectorsarray(none)Optional. Send a condensed summary of each scraped item to an app you authorized under Apify Integrations (Notion, Linear, Airtable, Apify). The full record stays in the dataset.
notionParentPageUrlstring(none)Notion connector only: the page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"listingId": "1000001-1",
"url": "https://www.hepsiemlak.com/en/istanbul-satilik/daire/1000001-1",
"title": "Sample 2+1 apartment near Sample Square",
"price": 4250000,
"currency": "TRY",
"grossSqm": 110,
"netSqm": 95,
"rooms": "2+1",
"bedrooms": 2,
"propertyTypes": ["Apartment"],
"city": "Istanbul",
"country": "TR",
"descriptionSnippet": "Bright 2+1 apartment close to the square, ready to move in.",
"sellerName": "Sample Realty",
"sellerOfficeUrl": "https://www.hepsiemlak.com/emlak-ofisi/sample-realty",
"imageUrl": "https://hecdn01.hemlak.com/sample/listing-photo.jpg",
"recordType": "listing",
"sourceType": "search",
"sourceId": "istanbul",
"position": 3,
"scrapedAt": "2026-09-16T00:00:00Z"
}

Send results into your apps (MCP connectors)

Optionally send a condensed summary of each scraped item to an app you authorized under Apify Integrations (Notion, Linear, Airtable, Apify) with mcpConnectors. For Notion, notionParentPageUrl names the page under which item pages are created, and maxNotifyListings caps how many items are written to each connector per run. The full record always stays in the dataset.

Plan Requirement

hepsiemlak.com sits behind an anti-bot challenge: plain and datacenter connections get an HTTP 403 "Just a moment..." page, so this actor needs a paid Apify plan with residential proxy access. The default (residential exits in Turkey) is the lane to use, and the actor takes a fresh exit when one is refused, then falls back to a page-rendering backup connection only when needed. Individual exits can still be refused, so a run may retry before pages load. A rate of failed runs is normal on this site; schedule with retries.

What you will see in the log:

  • On a plan without residential access: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." If the backup serves pages you also see "Served over the backup connection (the default connection was unavailable)."
  • If the proxy is refused for the account, the run fails with "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required."
  • If residential is unavailable and the backup cannot load pages: "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested hepsiemlak pages."
  • If nothing loaded for another reason: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

A refused run always fails loudly, never as an empty dataset.

FAQ

How much does it cost?

You pay for the actor start, one listing-record charge per row returned, and one detail-enrichment charge per enriched row when Fetch details is on. Rows that are suppressed (unchanged), dropped or failed are not charged. A pasted listing link is read from its own listing page, so it always carries that detail-enrichment charge, even with Fetch details off. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.

This actor collects only publicly available listing data. You are responsible for how you use it: follow hepsiemlak.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Seller names and phone numbers shown on a listing are published by the lister as the contact channel; they are normal marketplace fields, not discovered personal data.

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Recurring updates. Each run then returns only new and updated listings, and unchanged ones are not billed.

Why did my run fail instead of returning an empty dataset?

If the site refuses every request, the run stops with a clear message so "no listings for this search" is never confused with "nothing could be read". Run it again in a few minutes. If only some locations or links could be read, you still get what was found.

Can I use Resume and Recurring updates together?

No. Pick one per run: Resume from run ID continues a single interrupted crawl, while Recurring updates tracks a setup across scheduled runs. Clear one field to use the other.

🔗 More scrapers you might like

Pair this actor with these related scrapers from the same team:

🏠 PropertyGuru SG Scraper
Scrape PropertyGuru.com.sg sale and rental listings with 30+ structured fields, including...
🏠 Cian RU
Collect property listings from Cian.ru by search filters or direct URLs. Returns...
🏠 ImmobilienScout24.de Scraper
Extract property listings from immobilienscout24.de, Germany's #1 real estate platform...
🧩 Suumo.jp Scraper
Scrape Suumo, Japan's largest property portal: rental rooms with rent, management fees...
🏠 Otodom.pl Scraper
Scrape Otodom.pl properties for sale and rent, including apartments, houses, plots...
🏠 RealestateCo NZ
Search and extract all real estate properties for sale, rent, and sold across New Zealand...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.