# 99acres Scraper (`datascrapers/99acres-scraper`) Actor

Scrape property listings from 99acres.com using search queries or start URLs. Extract prices, amenities, seller/agent details, and optional listing-page extras.

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

## Pricing

from $1.20 / 1,000 dataset items

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**99acres Scraper** creates a structured dataset of property listings collected from 99acres.com. Each listing item is one buy or rent card and can include price in Indian rupees, area, BHK, locality, city, amenities, and the seller on the card. Agent extraction also writes separate dealer, owner, and builder rows. Query with a location such as Delhi or a 99acres search or listing URL, and set category, segment, property type, BHK, and price bounds. Control the listing limit with maxItems. Retrieve records through the Apify Dataset API or export them as JSON, CSV, Excel, XML, or another supported format.

[![99acres Scraper — input to structured data](https://raw.githubusercontent.com/faizanalii/apify-actor-assets/main/99acres-scraper/99acres-scraper-value-demo.gif)](https://apify.com/datascrapers/99acres-scraper)

### Dataset at a glance

| Property | Value |
|---|---|
| Source | 99acres.com |
| Record unit | One property listing, or one agent row when agent extraction is on |
| Input methods | Location search query or a 99acres search or listing URL |
| Main identifiers | `listingId` on listings; `agentId` on agent rows |
| Delivery | Apify Dataset and API |
| Export formats | JSON, CSV, Excel, XML, and other Apify dataset exports |
| Update model | Fresh records per Actor run |
| Pricing | Pay per event: `dataset-item` and optional `listing-details` and `agent-details` at $0.001 each |

### Coverage and available records

The Actor collects public 99acres buy and rent inventory for residential or commercial searches.

- `searchQueries` takes a location such as Delhi, Whitefield Bangalore, or Bandra Mumbai. The first city or locality match is used.
- `startUrls` accepts a search URL or a listing page whose path contains `-spid-` or `-npxid-`.
- At least one query or start URL is required. The Actor raises an error when both are empty.
- `category` is buy or rent. A value of sale is treated as buy. Filters apply to query searches and to start URLs that do not already encode a category.
- `segment` is residential or commercial.
- Property types cover apartment, builder floor, house, villa, plot, studio, farmhouse, serviced apartment, office, shop, and warehouse. An empty list does not restrict type.
- BHK accepts 1 through 5, where 5 means 5 or more. Furnishing accepts furnished, semi-furnished, and unfurnished.
- `postedBy` restricts results to owner, dealer, or builder. `possession` accepts ready to move or under construction.
- `minPrice` and `maxPrice` are Indian rupees.
- `maxItems` caps listing rows. 0 means no listing cap. Agent rows do not count toward this cap.
- `extractListingDetails` opens listing pages for description extras, photos, reviews, and page amenities. `listing-details` is charged only when those extras are attached. Search-card fields are always returned. In the stored sample, `detailsFetched` is true while `description` is still null, so a detail fetch does not guarantee a description.
- `extractAgentDetails` writes one dataset row per unique dealer, owner, or builder from listing posters and featured-dealer widgets. Each of those rows is charged as `agent-details`. Seller fields on the listing card are still included.
- The stored sample is a Delhi residential buy search. It includes builder-floor listings and project cards. It does not demonstrate every property type or city.

The Actor does not keep historical snapshots. Pagination follows the search until the result set ends or `maxItems` listing rows are saved.

### Data dictionary

#### Listing records

Types and examples come from stored listing rows. Nullable is Yes when any stored listing omitted the key or set it to null.

| Field | Type | Nullable | Description | Example |
|---|---|---:|---|---|
| `recordType` | string | No | Record kind. listing for a property row; agent for a dealer, owner, or builder row. | listing |
| `listingType` | string | No | Source listing kind. Observed value on property rows: property. | property |
| `listingId` | string | No | 99acres listing id, such as H93752656. Best key for a property row. | E4506387 |
| `url` | string | No | Absolute listing URL. Null on some agent rows. | https://www.99acres.com/4-bhk-bedroom-independent-builder-floor-for-s... |
| `title` | string | No | Listing title from the search card. | 4 BHK Builder Floor in Jasola, Delhi |
| `subtitle` | string | Yes | Subtitle. Null in the stored listing sample. | 1, 2, 3, 4 BHK Builder Floor in Chattarpur, South Delhi |
| `propertyType` | string | No | Display type, such as Independent/Builder Floor or Project. | Independent/Builder Floor |
| `category` | string | No | buy or rent, from the Actor input and search. | buy |
| `segment` | string | No | residential or commercial. | residential |
| `preference` | string | No | Source preference code. Observed sale value: S. | S |
| `price` | integer | No | Price in Indian rupees as an integer. Project rows can use the lower bound. | 49500000 |
| `priceMax` | integer | No | Upper price in INR when the source sends a range. Otherwise the same as price. | 49500000 |
| `priceDisplay` | string | No | Formatted price text from the source, such as 13 Cr. | 4.95 Cr |
| `pricePerSqft` | number | Yes | Price per square foot as a number. Null when the source omits it. | 152307.0 |
| `bedrooms` | integer | Yes | Bedroom count. Null on project cards that do not state a single BHK. | 4 |
| `bathrooms` | integer | Yes | Bathroom count. Null when omitted. | 3 |
| `balconies` | integer | Yes | Balcony count. Null when omitted. | 3 |
| `areaValue` | number | Yes | Area number. The stored sample uses square feet in areaDisplay. | 325.0 |
| `areaUnit` | string | Yes | Area unit code. Null in the stored sample; use areaDisplay for the labeled area. | sq.yards |
| `areaDisplay` | string | Yes | Formatted area, such as 5200 sqft. | 2925 sqft |
| `carpetArea` | number | Yes | Carpet area number. Null when omitted. | 5200.0 |
| `builtUpArea` | null | Yes | Built-up area number. Null in the stored sample. | null |
| `floor` | string | Yes | Floor label. The stored builder-floor row uses B. | 1 |
| `totalFloors` | integer | Yes | Total floors as an integer. Null when omitted. | 4 |
| `furnishing` | string | Yes | Furnishing text, such as Semifurnished. | Semifurnished |
| `address` | string | No | Address or locality line. | Jasola, Delhi |
| `locality` | string | No | Locality text. | Jasola, Delhi |
| `city` | string | No | City or district label, such as South Delhi. | South Delhi |
| `projectName` | string | Yes | Project name. Null when the card is not a named project. | Jasola Vihar PKT 1 & 2 |
| `builderName` | string | Yes | Builder name. Null when omitted. | Ambe Estate |
| `latitude` | number | No | Latitude in decimal degrees. | 28.5475733 |
| `longitude` | number | No | Longitude in decimal degrees. | 77.2951057 |
| `postedDate` | string | Yes | Source posted time, ISO-8601. | 2026-08-22T10:33:31+00:00 |
| `updatedAt` | string | Yes | Source updated time, ISO-8601. | 2026-08-03T12:04:39+00:00 |
| `possessionStatus` | string | Yes | Possession text. Null in the stored sample. | Ready To Move |
| `isVerified` | boolean | Yes | True when the card is marked verified. | false |
| `isPremium` | boolean | No | True when the card is marked premium. | false |
| `description` | string | Yes | Description text. Null in the stored sample even on a row with detailsFetched true. | Buy a home of your own in Ambe Homes which offers 1,2 BHK Independent... |
| `imageUrl` | string | No | Primary image URL. | https://imagecdn.99acres.com/media1/17843/14/356874146T-1755231182605... |
| `imageUrls` | array | No | Image URL list. | https://imagecdn.99acres.com/media1/17843/14/356874146T-1755231182605.jpg, https://imagecdn.99acres.com/media1/17843/14/356874146M-1755231183052.jpg, https://imagecdn.99acres.com/media1/17843/14/356874232M-1755228976177.jpg (+4) |
| `tags` | array | No | Tag strings from the card. | FEATURED, READY TO MOVE, RESALE |
| `amenities` | array | No | Amenity strings from the card or detail page. | 21, 48, 50 (+20) |
| `seller` | object | No | Seller object from the card. See the seller table. | object |
| `postedBy` | string | No | Who posted the listing, such as Dealer or Builder. | Dealer |
| `sourceQuery` | string | No | Search query that produced the row, such as Delhi. | Delhi |
| `sourceUrl` | string | No | Search or start URL that produced the row. | https://www.99acres.com/search/property/buy/delhi?city=1075722\&prefer... |
| `detailsFetched` | boolean | No | True when the Actor attached listing-page extras on this row. | true |
| `agentDetailsFetched` | boolean | No | True when agent extraction ran for the search that produced this listing. | true |
| `scrapedAt` | string | No | UTC timestamp written by the Actor, ISO-8601. | 2026-09-08T16:14:08.143185+00:00 |

#### Seller object

`seller` is present on stored listing rows.

| Field | Type | Nullable | Description | Example |
|---|---|---:|---|---|
| `name` | string | No | Seller or firm name on the card. | krish chugh |
| `firmName` | string | No | Firm name. | Krishna Associates And Builders |
| `postedBy` | string | No | Poster role, such as Dealer. | Dealer |
| `photoUrl` | string | Yes | Seller photo URL. | https://imagecdn.99acres.com/media1/12454/7/249087249O-1600331996585.... |
| `reraRegistered` | boolean | Yes | True when the card marks the seller as RERA registered. | false |

#### Agent records

These rows are written only when `extractAgentDetails` is true. The example is a stored builder row from the Delhi search. Several contact fields are null in that sample.

| Field | Type | Nullable | Description | Example |
|---|---|---:|---|---|
| `recordType` | string | No | Always agent on these rows. | agent |
| `agentId` | string | No | Deduplication key. Falls back to firm or name when the source has no id. The stored sample uses the firm name. | Krishna Associates And Builders |
| `name` | string | No | Agent, dealer, owner, or builder name. | krish chugh |
| `firmName` | string | No | Firm name. May equal name. | Krishna Associates And Builders |
| `postedBy` | string | No | Role label, such as Builder. | Dealer |
| `url` | null | Yes | Profile URL. Null when the source has none. | null |
| `imageUrl` | string | Yes | Photo URL. Null when omitted. | https://imagecdn.99acres.com/media1/12454/7/249087249O-1600331996585.... |
| `phonePartial` | null | Yes | Phone text exposed by the source. Null in the stored sample. | null |
| `reraRegistered` | boolean | Yes | RERA flag. Null when the source does not send a boolean. | false |
| `city` | string | No | City label carried from the listing or widget. | South Delhi |
| `totalListings` | null | Yes | Listing count. Null when omitted. | null |
| `source` | string | No | Where the agent was found. Observed value: listing. | listing |
| `sourceQuery` | string | No | Search query that produced the agent. | Delhi |
| `scrapedAt` | string | No | UTC timestamp written by the Actor, ISO-8601. | 2026-09-08T16:14:12.324805+00:00 |

Deduplicate listing rows on `listingId`. Deduplicate agent rows on `agentId`. When the source has no agent id, the Actor uses the firm or name, so two different people with the same firm label can collapse to one row.

### Example dataset record

Listing row from `searchQueries: ["Delhi"]`, category buy, segment residential, with listing details and agent extraction enabled. The search URL is the `sourceUrl` on the record.

```json
{
  "recordType": "listing",
  "listingType": "property",
  "listingId": "H93752656",
  "url": "https://www.99acres.com/4-bhk-bedroom-independent-builder-floor-for-sale-in-green-park-extension-delhi-south-5200-sqft-spid-H93752656",
  "title": "4 BHK Triplex Builder Floor in Green Park Extension, Delhi",
  "subtitle": null,
  "propertyType": "Independent/Builder Floor",
  "category": "buy",
  "segment": "residential",
  "preference": "S",
  "price": 130000000,
  "priceMax": 130000000,
  "priceDisplay": "13 Cr",
  "pricePerSqft": 25000.0,
  "bedrooms": 4,
  "bathrooms": 5,
  "balconies": 4,
  "areaValue": 5200.0,
  "areaUnit": null,
  "areaDisplay": "5200 sqft",
  "carpetArea": 5200.0,
  "builtUpArea": null,
  "floor": "B",
  "totalFloors": 4,
  "furnishing": "Semifurnished",
  "address": "Green Park Extension, Delhi",
  "locality": "Green Park Extension, Delhi",
  "city": "South Delhi",
  "projectName": null,
  "builderName": null,
  "latitude": 28.561444444444444,
  "longitude": 77.20130833333333,
  "postedDate": "2026-08-22T10:33:31+00:00",
  "updatedAt": "2026-08-24T09:38:36+00:00",
  "possessionStatus": null,
  "isVerified": true,
  "isPremium": false,
  "description": null,
  "imageUrl": "https://imagecdn.99acres.com/media1/41208/1/824161101T-1787395135113.jpg",
  "imageUrls": [
    "https://imagecdn.99acres.com/media1/41208/1/824161101T-1787395135113.jpg",
    "https://imagecdn.99acres.com/media1/41208/1/824161101M-1787395135336.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160449M-1787395138849.jpg",
    "https://imagecdn.99acres.com/media1/41207/19/824159927M-1787395126088.jpg",
    "https://imagecdn.99acres.com/media1/41207/19/824159961M-1787395125049.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160011M-1787395128310.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160025M-1787395129719.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160441M-1787395136995.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160483M-1787395136835.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160541M-1787395135724.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160577M-1787395130576.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160751M-1787395125998.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160437M-1787395132541.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160439M-1787395133961.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160545M-1787395140534.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160657M-1787395130939.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160075M-1787395134449.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160091M-1787395130756.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160119M-1787395136042.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160169M-1787395126236.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160219M-1787395118370.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160239M-1787395121365.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160397M-1787395129335.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160043M-1787395133042.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160099M-1787395132515.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160109M-1787395131312.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160203M-1787395126552.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160253M-1787395123185.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160329M-1787395128943.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160347M-1787395130677.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160379M-1787395130449.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160693M-1787395122385.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160187M-1787395133308.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160299M-1787395125793.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160313M-1787395132957.jpg",
    "https://imagecdn.99acres.com/media1/41208/0/824160601M-1787395138188.jpg",
    "https://imagecdn.99acres.com/media1/41208/1/824161009M-1787395137514.jpg",
    "https://imagecdn.99acres.com/media1/41208/1/824161073M-1787395133539.jpg"
  ],
  "tags": [
    "FEATURED",
    "READY TO MOVE",
    "RESALE",
    "Verified"
  ],
  "amenities": [
    "21",
    "50",
    "51",
    "52",
    "5",
    "10",
    "2",
    "17",
    "9",
    "19",
    "36",
    "44",
    "46",
    "45",
    "29",
    "3",
    "12",
    "103"
  ],
  "seller": {
    "name": "GLOBAL PROPERTY",
    "firmName": "GLOBAL PROPERTY",
    "postedBy": "Dealer",
    "photoUrl": "https://imagecdn.99acres.com/media1/21051/9/421029512O-1683101489785.jpg",
    "reraRegistered": false
  },
  "postedBy": "Dealer",
  "sourceQuery": "Delhi",
  "sourceUrl": "https://www.99acres.com/search/property/buy/delhi?city=1075722&preference=S&res_com=R",
  "detailsFetched": true,
  "agentDetailsFetched": true,
  "scrapedAt": "2026-09-08T16:14:08.142635+00:00"
}
```

Agent row from the same run:

```json
{
  "recordType": "agent",
  "agentId": "Ambe Estate",
  "name": "Ambe Estate",
  "firmName": "Ambe Estate",
  "postedBy": "Builder",
  "url": null,
  "imageUrl": null,
  "phonePartial": null,
  "reraRegistered": null,
  "city": "South Delhi",
  "totalListings": null,
  "source": "listing",
  "sourceQuery": "Delhi",
  "scrapedAt": "2026-09-08T16:15:19.493664+00:00"
}
```

### Query and input reference

| Input | Type | Required | Default | Accepted values | Description |
|---|---|---:|---|---|---|
| `searchQueries` | array of strings | No | — | Location text | Primary input. At least one query or start URL is required at run time. |
| `startUrls` | array | No | — | 99acres search or listing URLs | Search URL or a listing page with `-spid-` or `-npxid-`. |
| `category` | string | No | buy | buy, rent | Sale is accepted and treated as buy. |
| `segment` | string | No | residential | residential, commercial | Homes or commercial inventory. |
| `propertyTypes` | array of strings | No | — | apartment, builder_floor, house, villa, plot, studio, farmhouse, serviced_apartment, office, shop, warehouse | Empty means all types. |
| `bedrooms` | array of strings | No | — | 1, 2, 3, 4, 5 | 5 means 5 or more BHK. |
| `furnishTypes` | array of strings | No | — | furnished, semi_furnished, unfurnished | Furnishing filter. |
| `postedBy` | string | No | empty | empty, owner, dealer, builder | Poster restriction. Empty means anyone. |
| `possession` | string | No | empty | empty, ready_to_move, under_construction | Possession filter. |
| `minPrice` | integer | No | — | 0 or greater, INR | Minimum price in rupees. |
| `maxPrice` | integer | No | — | 0 or greater, INR | Maximum price in rupees. |
| `extractListingDetails` | boolean | No | false | true, false | Open listing pages. Charges `listing-details` only when extras are attached. |
| `extractAgentDetails` | boolean | No | false | true, false | Write unique agent rows charged as `agent-details`. |
| `maxConcurrency` | integer | No | 5 | 1 to 10 | Parallel listing-detail workers. |
| `maxItems` | integer | No | 0 | 0 or greater | Maximum listing rows. Agent rows are not counted. 0 means no cap. |
| `proxyConfiguration` | object | No | Apify residential | Apify proxy input | Connection used for 99acres requests. Residential is the input default. |

Minimal request:

```json
{
  "searchQueries": ["Delhi"],
  "category": "buy",
  "maxItems": 20
}
```

Request with details, agents, and a price bound:

```json
{
  "searchQueries": ["Whitefield Bangalore"],
  "category": "buy",
  "segment": "residential",
  "propertyTypes": ["apartment"],
  "bedrooms": ["2", "3"],
  "minPrice": 5000000,
  "maxPrice": 20000000,
  "extractListingDetails": true,
  "extractAgentDetails": true,
  "maxItems": 100,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Retrieve the data through the API

This is the Apify Actor API. 99acres does not provide this endpoint.

1. Start `datascrapers/99acres-scraper` with a JSON input.
2. Wait until the run finishes, or poll the run status.
3. Read items from the run's default dataset. Listing rows and agent rows share that dataset. Split them on `recordType`.
4. Page the dataset with offset and limit, or export it from the run page.

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("datascrapers/99acres-scraper").call(run_input={
    "searchQueries": ["Delhi"],
    "category": "buy",
    "maxItems": 20,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
listings = [item for item in items if item.get("recordType") == "listing"]
print(listings)
```

Other languages are listed on the Actor's API tab in Apify Console. Do not put a real token in a URL or in source control.

### Export and pipeline examples

| Destination | Recommended method | Typical use |
|---|---|---|
| PostgreSQL or Supabase | Dataset API or a webhook consumer | Store `listingId` for listings and `agentId` for agents |
| Google Sheets | Apify integration | Share a locality price extract |
| Amazon S3 or other cloud storage | Scheduled dataset export or an integration | Archive each run's JSON or CSV |
| A custom application | Dataset items endpoint | Split `recordType` and page a large search |

### Data quality and record handling

Listing fields come from the 99acres search card. When `extractListingDetails` is on and extras are attached, those extras are merged onto the same listing and `detailsFetched` is true. `description` can still be null after that merge. `category` and `segment` reflect the Actor input used for the search.

Within one run, search discovery skips a property id already seen. The id is taken from `PROP_ID`, then `SPID`, then `projectUnitId`, then the heading. The recommended external key is `listingId`. Agent rows are deduplicated by `agentId`, then by name plus firm. The stored agent sample uses the firm name as `agentId` because no separate id was present.

`dataset-item` is charged for every saved listing. `listing-details` is charged when `detailsFetched` is true. `agent-details` is charged for each saved agent row, and those rows do not use `dataset-item`. A listing that is not saved is not billed.

Prices are integers in INR plus a separate display string. Do not parse `priceDisplay` when `price` is present. Area unit is not always filled; `areaDisplay` carries the labeled area in the stored sample. Dates `postedDate`, `updatedAt`, and `scrapedAt` are ISO-8601. `scrapedAt` is the Actor clock in UTC. The other two are source times.

Project cards in the stored sample have null bedrooms and a price range in `price` and `priceMax`. Builder-floor cards have a single price and a BHK count.

### Pricing and cost examples

The Actor uses pay per event. Every saved listing charges one `dataset-item` event at **$0.001**. A listing with attached detail extras also charges one `listing-details` event at **$0.001**. Each saved agent row charges one `agent-details` event at **$0.001** and does not charge `dataset-item`. The same prices apply on every plan tier. There is no separate Actor-start event in this Actor.

Platform usage, including compute and residential proxy traffic, is billed to the run account in addition to these events. Estimates below are event charges only. Agent-row counts depend on how many unique posters the search returns.

| Records | Events | Estimated event cost |
|---:|---|---:|
| 1,000 listings, no extras | 1,000 × `dataset-item` | $1.00 |
| 1,000 listings with detail extras | 1,000 × `dataset-item` and 1,000 × `listing-details` | $2.00 |
| 10,000 listings, no extras | 10,000 × `dataset-item` | $10.00 |
| 10,000 listings with detail extras | 10,000 × `dataset-item` and 10,000 × `listing-details` | $20.00 |

Add $0.001 for each agent row. `maxItems` caps listing rows, not agent rows.

### Limitations and responsible data use

The Actor reads publicly available 99acres pages and the fields those pages expose. It does not return a historical archive. Each run reflects the site at the time of the request. Save datasets yourself if you need a time series.

Values can be missing when 99acres omits them, when a filter matches nothing, or when a listing page adds no extras. Phone values on agent rows are only the text the source exposes, and the stored sample leaves `phonePartial` null. Site markup and availability can change.

You are responsible for using the dataset in line with 99acres terms, privacy rules, and any contract that applies to your project. This page does not provide a legal conclusion about a particular use.

### Dataset questions

#### What does one dataset item represent?

Either one property listing (`recordType` listing) or one dealer, owner, or builder (`recordType` agent). Agent rows appear only when `extractAgentDetails` is true.

#### Which field should I use as a unique identifier?

Use `listingId` for listings. Use `agentId` for agent rows. `agentId` may be a firm name when the source has no id.

#### Are fields nullable or conditional?

Yes. Project cards omit a single BHK. `description`, `areaUnit`, `builderName`, and several agent contact fields are null in the stored sample. Detail extras and agent rows depend on the two extraction switches.

#### Can I retrieve the records as CSV or JSON?

Yes. Download JSON, CSV, Excel, XML, or another format from the Apify Console export menu, or read JSON through the Dataset API. Split listing and agent rows with `recordType` before a CSV load if you need one table per entity.

#### How do I paginate large datasets?

The Actor pages through the 99acres search until `maxItems` listings are saved or the search ends. After the run, page the Apify dataset with offset and limit.

#### Does the Actor return historical data?

No. A record is the listing state observed during that run.

#### What counts as a billable result?

Each saved listing is one `dataset-item` event at $0.001. Each listing with attached detail extras is an additional `listing-details` event at $0.001. Each saved agent row is one `agent-details` event at $0.001. Platform usage is charged separately.

### Related datasets from Data Scrapers

- [Property Finder Scraper](https://apify.com/datascrapers/propertyfinder-scraper) — listing records from Property Finder for another market.
- [Bayut Property Scraper](https://apify.com/datascrapers/bayut-scraper) — Bayut price, area, and location records.
- [Dubizzle UAE Scraper](https://apify.com/datascrapers/dubizzle-scraper) — Dubizzle UAE property and classifieds records.
- [Idealista Scraper](https://apify.com/datascrapers/idealista-scraper) — Idealista listing records for cross-market schema comparison.
- [Rightmove Scraper](https://apify.com/datascrapers/rightmove-scraper) — UK sale and rent listing records.
- [Realtor.com Scraper](https://apify.com/datascrapers/realtor-scraper) — US listing records with price and property fields.

### Data Scrapers support

Need an additional field, record type, or export workflow? Contact Data Scrapers at stardustspotlight@gmail.com. Include a sample source URL, required fields, expected record volume, and preferred delivery format.

# Actor input Schema

## `searchQueries` (type: `array`):

Locations to search on 99acres.com (e.g. "Delhi", "Whitefield Bangalore", "Bandra Mumbai"). Primary input for AI agents — no URL required. The first city or locality match is used.

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

99acres search or listing URLs (e.g. "https://www.99acres.com/search/property/buy/delhi?city=1075722\&preference=S\&res_com=R" or a ...-spid- / ...-npxid- listing page). Optional — filters still apply to query-based searches.

## `category` (type: `string`):

Buy or rent inventory. Applies to search queries and start URLs that do not already encode a category.

## `segment` (type: `string`):

Residential homes or commercial inventory.

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

Restrict results to these property types (e.g. apartment, villa, plot). Leave empty for all types.

## `bedrooms` (type: `array`):

Bedroom configuration to include (e.g. 2, 3). Leave empty for all.

## `furnishTypes` (type: `array`):

Furnishing filter (furnished, semi-furnished, unfurnished).

## `postedBy` (type: `string`):

Restrict to owners, dealers, or builders.

## `possession` (type: `string`):

Ready-to-move inventory, under construction, or no restriction.

## `minPrice` (type: `integer`):

Keep listings at or above this price in Indian rupees (e.g. 5000000 for ₹50 L).

## `maxPrice` (type: `integer`):

Keep listings at or below this price in Indian rupees (e.g. 20000000 for ₹2 Cr).

## `extractListingDetails` (type: `boolean`):

Open each listing in parallel for description extras, photos, reviews, and page amenities. Charged as listing-details only when extras are actually attached. Search-card fields are always returned.

## `extractAgentDetails` (type: `boolean`):

Emit unique dealer / owner / builder records from listing posters and featured-dealer widgets. Each agent is a separate dataset row charged as agent-details. Listing seller fields on the card are always included.

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

Parallel listing-detail workers (1–10). Higher is faster; each request uses a rotated residential proxy.

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

Maximum number of listing records to scrape (0 = unlimited). Agent rows do not count toward this cap.

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

Proxy settings for anti-bot protection. Apify Residential is recommended for 99acres.com.

## Actor input object example

```json
{
  "searchQueries": [
    "Delhi"
  ],
  "startUrls": [
    {
      "url": "https://www.99acres.com/search/property/buy/delhi?city=1075722&preference=S&res_com=R"
    }
  ],
  "category": "buy",
  "segment": "residential",
  "extractListingDetails": false,
  "extractAgentDetails": false,
  "maxConcurrency": 5,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset of scraped 99acres listings and optional agent records

## `runStats` (type: `string`):

Aggregate scrape statistics including listing, details, and agent counts

# 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 = {
    "searchQueries": [
        "Delhi"
    ],
    "startUrls": [
        {
            "url": "https://www.99acres.com/search/property/buy/delhi?city=1075722&preference=S&res_com=R"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascrapers/99acres-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 = {
    "searchQueries": ["Delhi"],
    "startUrls": [{ "url": "https://www.99acres.com/search/property/buy/delhi?city=1075722&preference=S&res_com=R" }],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("datascrapers/99acres-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 '{
  "searchQueries": [
    "Delhi"
  ],
  "startUrls": [
    {
      "url": "https://www.99acres.com/search/property/buy/delhi?city=1075722&preference=S&res_com=R"
    }
  ],
  "maxItems": 10
}' |
apify call datascrapers/99acres-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datascrapers/99acres-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/Ip0sp18HhnCiW8QHz/builds/LANIA2IU3to8D7YxK/openapi.json
