# BuyRentKenya Property Scraper — Kenya Real Estate (`nomad-agent/buyrentkenya-scraper`) Actor

Extract property listings from BuyRentKenya.com — Kenya's largest real-estate portal. Search houses, flats, land and commercial property for sale or rent by location. Clean JSON: title, price (KES), area, beds/baths, agent, images, posting date. Server-rendered pages, no login, no browser.

- **URL**: https://apify.com/nomad-agent/buyrentkenya-scraper.md
- **Developed by:** [Nomad.Dev](https://apify.com/nomad-agent) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.40 / 1,000 listing 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

## BuyRentKenya Property Scraper — Kenya Real Estate

Extract property listings from [BuyRentKenya.com](https://www.buyrentkenya.com) — Kenya's largest real-estate portal. Search houses, flats & apartments, land and commercial property **for sale or rent** by location, and get clean structured JSON. Server-rendered pages — no login, no browser, no proxies needed.

### What BuyRentKenya data does this scraper extract?

One flat JSON record per listing:

| Field | Meaning |
|---|---|
| `id` | BuyRentKenya listing id |
| `title` | Listing title as posted |
| `price` | Numeric price in KES |
| `currency` | `KES` |
| `location` | Combined `area, city, county` string |
| `county` / `city` / `area` | Location parts |
| `bedrooms` / `bathrooms` | Room counts (bathrooms need `fetchDetails`) |
| `areaSqm` | Plot / floor surface where provided |
| `propertyType` | e.g. `Townhouses for sale`, `Other Apartments for rent` |
| `listingType` | `sale` or `rent` |
| `agency` | Listing agency / seller name |
| `sellerType` | `agency` / `individual` where provided |
| `daysOnMarket` | Days since posting |
| `postedAt` | Posting date (exact with `fetchDetails`, else derived) |
| `imagesCount` | Photo count (needs `fetchDetails`) |
| `description` | Full listing description (needs `fetchDetails`) |
| `url` | Direct link to the listing |
| `isNew` | `true` on every record when `onlyNewSinceLastRun` is on (search mode only — see below) |

### Input

| Name | Type | Default | Description |
|---|---|---|---|
| `searchType` | string (`buy`\|`rent`) | `buy` | Search listings for sale or for rent. |
| `propertyType` | string | `all` | Category to search: `houses`, `flats-apartments`, `land`, `commercial`, `bedsitters`, or `all`. |
| `location` | string | `nairobi` | Location path slug (`nairobi`, `mombasa`, `nairobi/westlands`, …). Empty = all of Kenya. |
| `minPrice` | integer | `0` | Drop listings priced below this (KES). `0` = no minimum. Client-side filter. |
| `maxPrice` | integer | `0` | Drop listings priced above this (KES). `0` = no maximum. Client-side filter. |
| `minBedrooms` | integer | `0` | Drop listings with fewer bedrooms than this. Free from the search-page card; no `fetchDetails` needed. Search mode only. |
| `minBathrooms` | integer | `0` | Drop listings with fewer bathrooms than this. Bathrooms are detail-page-only, so this **auto-enables `fetchDetails`** if it's off. Search mode only. |
| `maxPages` | integer | `3` | Search-result pages to crawl per category (25 listings/page). Hard cap `10` (robots.txt). |
| `maxItems` | integer | `100` | Hard cap on total listings returned. `0` = no cap. Max `1000`. Billed at $0.004/listing — see Pricing. |
| `fetchDetails` | boolean | `false` | Visit each listing's detail page for bathrooms, image count, full description and exact publish date. One extra request per listing. |
| `onlyNewSinceLastRun` | boolean | `false` | Only output listings not seen in a previous run with this flag on. Seen listings aren't billed. Search mode only (no-op with `listingUrls` — see Delta mode below). |
| `listingUrls` | array of strings | `[]` | Scrape these specific `https://www.buyrentkenya.com/listings/...` URLs instead of running a search (detail mode). |
| `concurrency` | integer | `4` | *(Advanced)* Parallel workers for detail-page fetches. Max `8`. |

### How to scrape BuyRentKenya with this Actor

1. Pick **buy** or **rent** and a **property type** (or `all`).
2. Set **location** to a URL path slug: `nairobi`, `mombasa`, `kiambu`, `nairobi/westlands`, `nairobi/kilimani`… Leave empty for all of Kenya.
3. Optionally set a KES **price range**, **minBedrooms** / **minBathrooms**, **maxPages** (25 listings/page, max 10 pages per the site's robots.txt) and **fetchDetails** for bathrooms, photos, description and exact posting date.
4. Turn on **onlyNewSinceLastRun** for a recurring schedule that only pays for genuinely new listings each time.
5. Run and export JSON, CSV or Excel — or call it over the API:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("nomad-agent/buyrentkenya-scraper").call(run_input={
    "searchType": "rent",
    "propertyType": "flats-apartments",
    "location": "nairobi/westlands",
    "maxPrice": 150000,
    "fetchDetails": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], "|", item["price"], item["currency"], item["url"])
````

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/nomad-agent~buyrentkenya-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchType": "buy", "propertyType": "houses", "location": "nairobi", "maxPages": 3}'
```

**Detail mode:** pass `listingUrls` (full `https://www.buyrentkenya.com/listings/...` URLs) to scrape specific listings instead of searching.

**Delta mode (`onlyNewSinceLastRun`):** turn this on to only get listings this Actor hasn't returned before. It keeps a small per-Actor id cache (up to ~50k listing ids, oldest evicted first) in a named key-value store; each run adds newly-delivered ids and skips (doesn't push, doesn't bill) anything already in the cache. Set `isNew: true` on every record it does return. It only applies to search mode — if you pass `listingUrls` you're asking for those exact listings by name, so the flag is a no-op there (every URL you list is always scraped and returned; the Actor logs an info line noting the no-op).

**Bedroom/bathroom filters:** `minBedrooms` and `minBathrooms` are applied as a final pass after search + optional `fetchDetails` enrichment, and — like `minPrice`/`maxPrice` — a listing with an unknown value for the filtered field is dropped once a minimum is set. `minBathrooms` needs detail-page data, so setting it above `0` silently (and loudly, via a log line) turns `fetchDetails` on for you even if you left it unchecked; without that auto-enable, `bathrooms` would always be `null` and the filter would drop every listing. Like the price filters, both bed/bath filters only apply to search mode, not to explicit `listingUrls`.

### Output example

```json
{
  "id": "4007805",
  "title": "5 Bed Townhouse with En Suite in Lavington",
  "price": 75000000,
  "currency": "KES",
  "location": "Lavington, Nairobi",
  "county": "Nairobi",
  "city": "Lavington",
  "area": "Lavington",
  "bedrooms": 5,
  "bathrooms": 6,
  "propertyType": "Townhouses for sale",
  "listingType": "sale",
  "agency": "SRG Properties",
  "daysOnMarket": 20,
  "postedAt": "2026-06-11",
  "imagesCount": 20,
  "url": "https://www.buyrentkenya.com/listings/5-bedroom-townhouse-for-sale-lavington-4007805",
  "source": "buyrentkenya",
  "searchType": "buy",
  "isNew": true
}
```

`isNew` is only present when `onlyNewSinceLastRun` is on; older integrations that don't expect the field can safely ignore it.

### Integrations

Export results as JSON, CSV, Excel (XLSX), HTML or RSS straight from the Apify Console, or wire the dataset into [Make](https://www.apify.com/integrations/make), [Zapier](https://www.apify.com/integrations/zapier), [n8n](https://www.apify.com/integrations/n8n) and other Apify integrations. For code, use `run-sync-get-dataset-items` (shown above) for a single synchronous call, the `apify-client` SDKs, or the [Apify MCP server](https://mcp.apify.com) to drive this Actor from an LLM/agent tool loop.

### Pricing

Pay per event: **$0.05 per Actor start** and **$0.004 per listing returned**.
100 listings ≈ $0.45 (the default `maxItems`). No subscription — pay only for what you fetch. Listings skipped by `onlyNewSinceLastRun` because they were already delivered in a previous run are never pushed, so they're never billed either.

### Use cases

- Kenya property market research: price levels by county, city and area
- Track new sale/rent inventory in specific neighbourhoods (Westlands, Kilimani, Karen…)
- Feed valuation models and rental-yield dashboards with fresh KES prices
- Monitor agency activity and days-on-market trends
- Aggregate listings into your own real-estate app or newsletter

### FAQ

**Does it need a browser or proxies?**
No. BuyRentKenya server-renders its pages; the Actor parses plain HTML plus embedded structured data.

**Why is pagination capped at 10 pages?**
The site's robots.txt only permits `?page=2`–`?page=10`. The Actor respects that; narrow by location/category to cover more inventory.

**Why filter price (and bedrooms/bathrooms) client-side?**
Filter query params (`price=`, `bedrooms=`, …) are disallowed by the site's robots.txt, so the Actor fetches the plain category pages it may crawl and filters `minPrice`/`maxPrice`/`minBedrooms`/`minBathrooms` in-Actor, after the page is fetched.

**Why does setting `minBathrooms` turn on `fetchDetails` for me?**
Bathroom counts only exist on a listing's detail page — the search-page card never has them. Silently applying `minBathrooms` without `fetchDetails` would see every listing's `bathrooms` as unknown and drop everything, which is a worse failure mode than a slower, slightly pricier run that actually honors the filter you asked for. The Actor logs an info line whenever it does this auto-enable.

**Does `maxItems`, together with `onlyNewSinceLastRun`, ever lose listings?**
No. A listing is only added to the "seen" id cache once it is actually pushed to the dataset. If a run hits its `maxItems` cap before delivering every new listing found, the undelivered ones stay untouched in the cache and are picked up (and billed) on the next run instead of being silently dropped.

**Is it legal to scrape BuyRentKenya?**
The Actor reads the same public, unauthenticated pages any visitor sees and follows the site's robots.txt. Review the site's terms for your use case.

# Actor input Schema

## `searchType` (type: `string`):

Search listings for sale ('buy') or for rent ('rent').

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

Which category to search. 'all' crawls every category available for the chosen searchType (bedsitters exist for rent only, land for sale only).

## `location` (type: `string`):

Location path slug as used on buyrentkenya.com URLs — e.g. 'nairobi', 'mombasa', 'kiambu', or a nested area like 'nairobi/westlands'. Leave empty for all of Kenya.

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

Drop listings priced below this (Kenyan shillings). 0 = no minimum. Filtering happens client-side; listings without a public price are dropped when a bound is set.

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

Drop listings priced above this (Kenyan shillings). 0 = no maximum.

## `minBedrooms` (type: `integer`):

Drop listings with fewer bedrooms than this. Bedroom count comes free from the search-page listing card (no detail fetch needed), or from the detail page when 'Fetch listing details' is on. 0 = no minimum. Listings with an unknown bedroom count are dropped when this is set, same as the price filters. Only applies to search mode — not to explicit 'Listing URLs'.

## `minBathrooms` (type: `integer`):

Drop listings with fewer bathrooms than this. Bathroom count is only available from a listing's detail page, so setting this above 0 automatically enables 'Fetch listing details' even if you left it off (one extra request per listing — see Pricing). Listings with an unknown bathroom count are dropped when this is set. 0 = no minimum. Only applies to search mode — not to explicit 'Listing URLs'.

## `maxPages` (type: `integer`):

Search-result pages to crawl per category (25 listings/page). Hard cap 10 — the site's robots.txt only allows pagination up to page 10.

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

Hard cap on total listings returned. 0 = no cap. Each listing returned is billed at $0.004 (see Pricing tab), so the default of 100 keeps a zero-config run cheap (~$0.45 incl. actor-start) — raise it, or set 0 for unlimited, once you know the volume you need.

## `fetchDetails` (type: `boolean`):

Visit each listing's detail page to add bathrooms, image count, full description and exact publish date. Slower (one extra request per listing). Automatically enabled when 'Min bathrooms' is set above 0.

## `onlyNewSinceLastRun` (type: `boolean`):

Only output listings not seen in previous runs with this flag. Seen listings aren't billed, so this saves you money on repeat runs. Uses an id cache scoped to this Actor (keyed by listing id, up to ~50k remembered ids). Only applies to search mode — a no-op when you pass explicit 'Listing URLs', since those are listings you asked for by name.

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

Optional: scrape these specific listing detail URLs (https://www.buyrentkenya.com/listings/...) instead of running a search.

## `concurrency` (type: `integer`):

Parallel workers for detail-page fetches.

## Actor input object example

```json
{
  "searchType": "buy",
  "propertyType": "all",
  "location": "nairobi",
  "minPrice": 0,
  "maxPrice": 0,
  "minBedrooms": 0,
  "minBathrooms": 0,
  "maxPages": 3,
  "maxItems": 100,
  "fetchDetails": false,
  "onlyNewSinceLastRun": false,
  "concurrency": 4
}
```

# Actor output Schema

## `dataset` (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 = {
    "location": "nairobi"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nomad-agent/buyrentkenya-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 = { "location": "nairobi" }

# Run the Actor and wait for it to finish
run = client.actor("nomad-agent/buyrentkenya-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 '{
  "location": "nairobi"
}' |
apify call nomad-agent/buyrentkenya-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "BuyRentKenya Property Scraper — Kenya Real Estate",
        "description": "Extract property listings from BuyRentKenya.com — Kenya's largest real-estate portal. Search houses, flats, land and commercial property for sale or rent by location. Clean JSON: title, price (KES), area, beds/baths, agent, images, posting date. Server-rendered pages, no login, no browser.",
        "version": "0.1",
        "x-build-id": "HbBYHi8UxcryLjvnD"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/nomad-agent~buyrentkenya-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-nomad-agent-buyrentkenya-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/nomad-agent~buyrentkenya-scraper/runs": {
            "post": {
                "operationId": "runs-sync-nomad-agent-buyrentkenya-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/nomad-agent~buyrentkenya-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-nomad-agent-buyrentkenya-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",
                "properties": {
                    "searchType": {
                        "title": "Buy or rent",
                        "enum": [
                            "buy",
                            "rent"
                        ],
                        "type": "string",
                        "description": "Search listings for sale ('buy') or for rent ('rent').",
                        "default": "buy"
                    },
                    "propertyType": {
                        "title": "Property type",
                        "enum": [
                            "all",
                            "houses",
                            "flats-apartments",
                            "land",
                            "commercial",
                            "bedsitters"
                        ],
                        "type": "string",
                        "description": "Which category to search. 'all' crawls every category available for the chosen searchType (bedsitters exist for rent only, land for sale only).",
                        "default": "all"
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "Location path slug as used on buyrentkenya.com URLs — e.g. 'nairobi', 'mombasa', 'kiambu', or a nested area like 'nairobi/westlands'. Leave empty for all of Kenya."
                    },
                    "minPrice": {
                        "title": "Min price (KES)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop listings priced below this (Kenyan shillings). 0 = no minimum. Filtering happens client-side; listings without a public price are dropped when a bound is set.",
                        "default": 0
                    },
                    "maxPrice": {
                        "title": "Max price (KES)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop listings priced above this (Kenyan shillings). 0 = no maximum.",
                        "default": 0
                    },
                    "minBedrooms": {
                        "title": "Min bedrooms",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop listings with fewer bedrooms than this. Bedroom count comes free from the search-page listing card (no detail fetch needed), or from the detail page when 'Fetch listing details' is on. 0 = no minimum. Listings with an unknown bedroom count are dropped when this is set, same as the price filters. Only applies to search mode — not to explicit 'Listing URLs'.",
                        "default": 0
                    },
                    "minBathrooms": {
                        "title": "Min bathrooms",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop listings with fewer bathrooms than this. Bathroom count is only available from a listing's detail page, so setting this above 0 automatically enables 'Fetch listing details' even if you left it off (one extra request per listing — see Pricing). Listings with an unknown bathroom count are dropped when this is set. 0 = no minimum. Only applies to search mode — not to explicit 'Listing URLs'.",
                        "default": 0
                    },
                    "maxPages": {
                        "title": "Max pages per category",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Search-result pages to crawl per category (25 listings/page). Hard cap 10 — the site's robots.txt only allows pagination up to page 10.",
                        "default": 3
                    },
                    "maxItems": {
                        "title": "Max items (total)",
                        "minimum": 0,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Hard cap on total listings returned. 0 = no cap. Each listing returned is billed at $0.004 (see Pricing tab), so the default of 100 keeps a zero-config run cheap (~$0.45 incl. actor-start) — raise it, or set 0 for unlimited, once you know the volume you need.",
                        "default": 100
                    },
                    "fetchDetails": {
                        "title": "Fetch listing details",
                        "type": "boolean",
                        "description": "Visit each listing's detail page to add bathrooms, image count, full description and exact publish date. Slower (one extra request per listing). Automatically enabled when 'Min bathrooms' is set above 0.",
                        "default": false
                    },
                    "onlyNewSinceLastRun": {
                        "title": "Only new since last run",
                        "type": "boolean",
                        "description": "Only output listings not seen in previous runs with this flag. Seen listings aren't billed, so this saves you money on repeat runs. Uses an id cache scoped to this Actor (keyed by listing id, up to ~50k remembered ids). Only applies to search mode — a no-op when you pass explicit 'Listing URLs', since those are listings you asked for by name.",
                        "default": false
                    },
                    "listingUrls": {
                        "title": "Listing URLs (detail mode)",
                        "type": "array",
                        "description": "Optional: scrape these specific listing detail URLs (https://www.buyrentkenya.com/listings/...) instead of running a search.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "concurrency": {
                        "title": "Detail-fetch concurrency",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Parallel workers for detail-page fetches.",
                        "default": 4
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
