# Kijiji & RentFaster Scraper — Canada Rental Listings + Geo Data (`soroush98/kijiji-canada-rentals-scraper`) Actor

Scrape Canadian rental listings from Kijiji and RentFaster.ca in one normalized schema — price, beds, baths, address, coordinates — with cross-source dedup and nearest-amenity (subway/grocery/school) distances. Apartments, condos, houses across Canada.

- **URL**: https://apify.com/soroush98/kijiji-canada-rentals-scraper.md
- **Developed by:** [Soroosh Esmaeilian](https://apify.com/soroush98) (community)
- **Categories:** Real estate, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 listings

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Kijiji & RentFaster Scraper — Canada Rental Listings + Geo Data 🇨🇦🏠

One **normalized, deduplicated** feed of Canadian rental listings from **Kijiji**
and **RentFaster.ca**, with optional **nearest-amenity distances** (transit,
grocery, school, …) attached to every listing.

Most rental scrapers give you one site in that site's own ad-hoc shape. This
Actor gives you **all sources in a single schema**, collapses the same unit
posted to multiple sites into one row, and can tell you *how far each place is
from the subway* — a signal no other rental scraper on Apify ships.

### Why this is different

| | Typical single-site scraper | This Actor |
|---|---|---|
| Sources | One | Kijiji + RentFaster (more coming) |
| Schema | Per-site, ad-hoc | One unified schema across sources |
| Duplicates | You dedupe yourself | Cross-source dedup built in (`also_on`) |
| Location intelligence | Lat/lng only | Nearest-amenity distances, **included free** |

### Input

**Scope**

| Field | Type | Default | Notes |
|---|---|---|---|
| `sources` | array | `["kijiji","rentfaster"]` | Sites to scrape |
| `cities` | array | `[]` (all) | City names, e.g. `["Toronto","Calgary"]` |
| `maxPerCity` | int | `100` | Cap per city, per source |
| `dedupe` | bool | `true` | Merge cross-source duplicates |

**Filters** (all optional — applied cheapest-first)

| Field | Type | Notes |
|---|---|---|
| `minRent` / `maxRent` | int | Monthly rent bounds, e.g. `maxRent: 2500` |
| `minBedrooms` / `maxBedrooms` | int | For exactly 2-bed, set both to `2`. `0` = include bachelor |
| `keywords` | array | Title/description must contain **ALL** (case-insensitive). e.g. `["female"]`, `["parking","balcony"]` |
| `excludeKeywords` | array | Drop if title/description contains **ANY**. e.g. `["no pets"]` |
| `nearAmenities` | array | Keep listings within `maxAmenityDistanceM` of **each** type: `subway, train, bus_stop, grocery, cafe, pharmacy, park, school, university, library, gym, hospital`. Auto-enables enrichment |
| `maxAmenityDistanceM` | int | Default `800` (≈10-min walk) |
| `nearAddress` | string | A specific place to anchor on, e.g. `"200 Bay St, Toronto"`. Geocoded, then listings kept within `nearAddressRadiusM`. **Use this for "near my workplace"** |
| `nearAddressRadiusM` | int | Default `2000` |

**Enrichment & infra**

| Field | Type | Default | Notes |
|---|---|---|---|
| `enrichAmenities` | bool | `false` | Attach `amenity_distances_m` even without a `nearAmenities` filter (fast, free) |
| `enrichRadiusM` | int | `1500` | Amenity search radius |
| `maxEnrich` | int | `200` | Cap on listings enriched per run |
| `proxyConfiguration` | object | Apify Proxy on | **Recommended** — see below |

Examples:

```json
// minimal
{ "sources": ["kijiji", "rentfaster"], "cities": ["Toronto"], "maxPerCity": 50 }

// "2-bed under $2500 in Toronto, near a subway, female-only"
{
  "cities": ["Toronto"], "minBedrooms": 2, "maxBedrooms": 2,
  "maxRent": 2500, "nearAmenities": ["subway"], "maxAmenityDistanceM": 800,
  "keywords": ["female"]
}

// "1-bed within 2 km of my office at 200 Bay St"
{ "cities": ["Toronto"], "maxBedrooms": 1, "nearAddress": "200 Bay St, Toronto", "nearAddressRadiusM": 2000 }
````

#### "Near X" — two different mechanisms

- **Near a *type* of place** (subway, grocery, university…) → `nearAmenities`. Backed by OpenStreetMap; great coverage in Canadian cities.
- **Near a *specific* place** (your office, a named landmark) → `nearAddress`. Geocoded to one point. Amenity categories can't find a specific employer (OSM may not have "Company X"), so use `nearAddress` for that.

#### Description questions (e.g. "female only", "no pets")

The full `description` is always in the output. For **literal** phrases, use `keywords` / `excludeKeywords` (deterministic, server-side). For **nuanced** interpretation, let an LLM read the returned descriptions — e.g. via [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), Claude can run this Actor and reason over the results in chat. Note: keyword matching is literal, so it depends on how the lister phrased it, and gender-restricted *whole-unit* ads may run into provincial human-rights rules (shared/roommate situations are typically exempt) — that's on the data, not the filter.

### Output

Each dataset item (empty fields omitted):

```json
{
  "source": "kijiji",
  "also_on": ["rentfaster"],
  "source_id": "1700123456",
  "url": "https://www.kijiji.ca/v-apartments-condos/...",
  "title": "Bright 2BR near subway",
  "address": "123 King St W, Toronto, ON",
  "city": "Toronto",
  "province": "ON",
  "postal_code": "M5V 1J5",
  "lat": 43.6453,
  "lng": -79.3806,
  "monthly_rent": 2450,
  "bedrooms": 2.0,
  "bathrooms": 1.0,
  "sqft": 720,
  "property_type": "apartment",
  "furnished": false,
  "pet_friendly": true,
  "utilities_included": ["heat", "water"],
  "available_from": "2026-07-01",
  "description": "…",
  "amenity_distances_m": { "subway": 320, "grocery": 150, "park": 410 },
  "scraped_at": "2026-06-27T12:00:00+00:00"
}
```

`bedrooms: 0.5` means bachelor/studio. `also_on` lists other sites the same
unit was found on (only when `dedupe` is enabled).

### Use it from Claude (MCP) 🤖

This Actor is built to be driven by an AI agent, not just a form. Connect
**[Apify's MCP server](https://docs.apify.com/platform/integrations/mcp)** to
Claude (Desktop, Claude Code, or any MCP client) and Claude can run it from a
plain-English request, then reason over the results — no code.

1. Add the hosted MCP server `https://mcp.apify.com` (OAuth), or run
   `@apify/actors-mcp-server` locally with your `APIFY_TOKEN`.
2. In Claude, just ask:
   > *"Run the Canada rentals actor for Toronto — 2-bed under $2500 near a subway — and recommend the best 3."*

Claude maps that straight onto the inputs —
`{cities:["Toronto"], minBedrooms:2, maxBedrooms:2, maxRent:2500, nearAmenities:["subway"]}` —
runs the Actor, reads the dataset, and answers in chat. Because the filters
(`maxRent`, `minBedrooms`, `keywords`, `nearAmenities`, `nearAddress`) are
pushed *into* the Actor, Claude isn't post-filtering a huge blob — it gets a
short, correct set back. The `amenity_distances_m` field is what lets it answer
*"near a subway / grocery / school"* precisely instead of guessing from text.

### Proxy — please read

- **RentFaster.ca** sits behind a Cloudflare managed challenge that fingerprints
  the TLS handshake, so browser-like *headers* alone get `403`. The Actor forges a
  real Chrome TLS/HTTP2 fingerprint (via `curl_cffi`) to clear it; a **residential
  Canadian proxy** is still recommended for a clean IP.
- **Kijiji** rate-limits and blocks datacenter IPs aggressively.

Use **Apify Proxy** (residential group) for production runs. The default input
already enables Apify Proxy.

### Amenity enrichment

Nearest-amenity distances come from a **bundled offline POI index** — ~225k
Canadian POIs (OpenStreetMap, via Geofabrik) shipped inside the Actor and queried
in-process. No external API, no rate limits: enriching hundreds of listings takes
well under a second, and it's **included free** (no per-listing enrichment charge).
The snapshot is refreshed periodically; POIs are static infrastructure so it
doesn't need to be live.

### Legal & fair use

Scrapes only **publicly visible** listing data — no logins, no private data.
You are responsible for your use of the output. Kijiji and RentFaster each have
Terms of Use that restrict automated access; review them and your jurisdiction's
rules, run politely (low concurrency, sensible caps), and don't redistribute in
ways those terms prohibit. This Actor is provided for research and personal use.

### Roadmap

- Facebook Marketplace + rentals.ca sources (best-effort; both are anti-bot).
- Listing-level change tracking (price drops, relistings).

***

Built from the data pipeline behind **EZrelocate**, a Canada-wide rental
recommender (Postgres + PostGIS + pgvector, Claude + Voyage embeddings).

# Actor input Schema

## `sources` (type: `array`):

Which rental sites to scrape.

## `cities` (type: `array`):

City names to cover (e.g. Toronto, Calgary). Leave empty for all supported cities.

## `maxPerCity` (type: `integer`):

Upper bound on listings collected from each city, for each source.

## `maxResults` (type: `integer`):

Hard cap on how many listings the run returns (after filtering + dedup). Raise it for bulk dataset pulls.

## `minRent` (type: `integer`):

Keep only listings at or above this monthly rent.

## `maxRent` (type: `integer`):

Keep only listings at or below this monthly rent. e.g. 2500.

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

Minimum bedroom count. Use 0 to include bachelor/studio (stored as 0.5).

## `maxBedrooms` (type: `integer`):

Maximum bedroom count. For exactly 2-bed, set min and max both to 2.

## `keywords` (type: `array`):

Case-insensitive substring match over title + description. ALL must be present. e.g. \["female"] for women-only, or \["parking","balcony"].

## `excludeKeywords` (type: `array`):

Drop a listing if its title/description contains ANY of these. e.g. \["no pets","students only"].

## `nearAmenities` (type: `array`):

Keep only listings within the distance below of EACH selected amenity type (uses OpenStreetMap). Turns on amenity enrichment automatically.

## `maxAmenityDistanceM` (type: `integer`):

Used with 'Near these amenity types'. 800 m ≈ a 10-minute walk.

## `nearAddress` (type: `string`):

Free-text address or place to anchor on, e.g. 'University of Toronto' or '200 Bay St, Toronto'. Geocoded, then listings are kept within the radius below. Use this for 'near my workplace' (amenity categories can't find a specific employer).

## `nearAddressRadiusM` (type: `integer`):

Used with 'Near a specific address'.

## `dedupe` (type: `boolean`):

Merge the same unit posted to multiple sites into one row (records the extra site in `also_on`).

## `enrichAmenities` (type: `boolean`):

Add `amenity_distances_m` (nearest subway/grocery/school/etc. in metres) from a bundled offline POI index — fast, free, no external API. Off by default. See README.

## `enrichRadiusM` (type: `integer`):

Only used when amenity enrichment is on.

## `maxEnrich` (type: `integer`):

Cap on how many listings are enriched per run. Only used when enrichment is on.

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

Per-source request concurrency. Keep low to stay polite and avoid blocks.

## `minDelayMs` (type: `integer`):

Lower bound of the random delay inserted before each request (politeness).

## `maxDelayMs` (type: `integer`):

Upper bound of the random delay inserted before each request (politeness).

## `userAgent` (type: `string`):

Optional. Set a real contact string in production.

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

Both Kijiji and RentFaster block datacenter IPs (Cloudflare), so this defaults to RESIDENTIAL Canadian IPs, rotated per request. Residential proxy is metered (~$8/GB) and draws from your plan credit. Switch the group to datacenter to run free, but expect intermittent blocks.

## Actor input object example

```json
{
  "sources": [
    "kijiji",
    "rentfaster"
  ],
  "cities": [
    "Toronto",
    "Vancouver",
    "Calgary"
  ],
  "maxPerCity": 100,
  "maxResults": 50,
  "keywords": [],
  "excludeKeywords": [],
  "nearAmenities": [],
  "maxAmenityDistanceM": 800,
  "nearAddressRadiusM": 2000,
  "dedupe": true,
  "enrichAmenities": false,
  "enrichRadiusM": 1500,
  "maxEnrich": 200,
  "maxConcurrency": 3,
  "minDelayMs": 500,
  "maxDelayMs": 1500,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}
```

# 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 = {
    "sources": [
        "kijiji",
        "rentfaster"
    ],
    "cities": [
        "Toronto",
        "Vancouver",
        "Calgary"
    ],
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "CA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("soroush98/kijiji-canada-rentals-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 = {
    "sources": [
        "kijiji",
        "rentfaster",
    ],
    "cities": [
        "Toronto",
        "Vancouver",
        "Calgary",
    ],
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "CA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("soroush98/kijiji-canada-rentals-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 '{
  "sources": [
    "kijiji",
    "rentfaster"
  ],
  "cities": [
    "Toronto",
    "Vancouver",
    "Calgary"
  ],
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}' |
apify call soroush98/kijiji-canada-rentals-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Kijiji & RentFaster Scraper — Canada Rental Listings + Geo Data",
        "description": "Scrape Canadian rental listings from Kijiji and RentFaster.ca in one normalized schema — price, beds, baths, address, coordinates — with cross-source dedup and nearest-amenity (subway/grocery/school) distances. Apartments, condos, houses across Canada.",
        "version": "0.1",
        "x-build-id": "vh73nBUNkbgXHqBNi"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/soroush98~kijiji-canada-rentals-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-soroush98-kijiji-canada-rentals-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/soroush98~kijiji-canada-rentals-scraper/runs": {
            "post": {
                "operationId": "runs-sync-soroush98-kijiji-canada-rentals-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/soroush98~kijiji-canada-rentals-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-soroush98-kijiji-canada-rentals-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "sources"
                ],
                "properties": {
                    "sources": {
                        "title": "Sources",
                        "type": "array",
                        "description": "Which rental sites to scrape.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "kijiji",
                                "rentfaster"
                            ],
                            "enumTitles": [
                                "Kijiji",
                                "RentFaster.ca"
                            ]
                        },
                        "default": [
                            "kijiji",
                            "rentfaster"
                        ]
                    },
                    "cities": {
                        "title": "Cities",
                        "type": "array",
                        "description": "City names to cover (e.g. Toronto, Calgary). Leave empty for all supported cities.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxPerCity": {
                        "title": "Max listings per city (per source)",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Upper bound on listings collected from each city, for each source.",
                        "default": 100
                    },
                    "maxResults": {
                        "title": "Max results (total)",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Hard cap on how many listings the run returns (after filtering + dedup). Raise it for bulk dataset pulls.",
                        "default": 50
                    },
                    "minRent": {
                        "title": "Min rent ($/month)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Keep only listings at or above this monthly rent."
                    },
                    "maxRent": {
                        "title": "Max rent ($/month)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Keep only listings at or below this monthly rent. e.g. 2500."
                    },
                    "minBedrooms": {
                        "title": "Min bedrooms",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Minimum bedroom count. Use 0 to include bachelor/studio (stored as 0.5)."
                    },
                    "maxBedrooms": {
                        "title": "Max bedrooms",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum bedroom count. For exactly 2-bed, set min and max both to 2."
                    },
                    "keywords": {
                        "title": "Description must contain ALL of these",
                        "type": "array",
                        "description": "Case-insensitive substring match over title + description. ALL must be present. e.g. [\"female\"] for women-only, or [\"parking\",\"balcony\"].",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "excludeKeywords": {
                        "title": "Description must contain NONE of these",
                        "type": "array",
                        "description": "Drop a listing if its title/description contains ANY of these. e.g. [\"no pets\",\"students only\"].",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "nearAmenities": {
                        "title": "Near these amenity types",
                        "type": "array",
                        "description": "Keep only listings within the distance below of EACH selected amenity type (uses OpenStreetMap). Turns on amenity enrichment automatically.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "subway",
                                "train",
                                "bus_stop",
                                "grocery",
                                "cafe",
                                "pharmacy",
                                "park",
                                "school",
                                "university",
                                "library",
                                "gym",
                                "hospital"
                            ]
                        },
                        "default": []
                    },
                    "maxAmenityDistanceM": {
                        "title": "Max distance to amenity (m)",
                        "minimum": 100,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Used with 'Near these amenity types'. 800 m ≈ a 10-minute walk.",
                        "default": 800
                    },
                    "nearAddress": {
                        "title": "Near a specific address / place",
                        "type": "string",
                        "description": "Free-text address or place to anchor on, e.g. 'University of Toronto' or '200 Bay St, Toronto'. Geocoded, then listings are kept within the radius below. Use this for 'near my workplace' (amenity categories can't find a specific employer)."
                    },
                    "nearAddressRadiusM": {
                        "title": "Radius around that address (m)",
                        "minimum": 100,
                        "maximum": 20000,
                        "type": "integer",
                        "description": "Used with 'Near a specific address'.",
                        "default": 2000
                    },
                    "dedupe": {
                        "title": "Collapse cross-source duplicates",
                        "type": "boolean",
                        "description": "Merge the same unit posted to multiple sites into one row (records the extra site in `also_on`).",
                        "default": true
                    },
                    "enrichAmenities": {
                        "title": "Attach nearest-amenity distances",
                        "type": "boolean",
                        "description": "Add `amenity_distances_m` (nearest subway/grocery/school/etc. in metres) from a bundled offline POI index — fast, free, no external API. Off by default. See README.",
                        "default": false
                    },
                    "enrichRadiusM": {
                        "title": "Amenity search radius (m)",
                        "minimum": 250,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Only used when amenity enrichment is on.",
                        "default": 1500
                    },
                    "maxEnrich": {
                        "title": "Max listings to enrich",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Cap on how many listings are enriched per run. Only used when enrichment is on.",
                        "default": 200
                    },
                    "maxConcurrency": {
                        "title": "Max concurrent requests",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Per-source request concurrency. Keep low to stay polite and avoid blocks.",
                        "default": 3
                    },
                    "minDelayMs": {
                        "title": "Min per-request delay (ms)",
                        "type": "integer",
                        "description": "Lower bound of the random delay inserted before each request (politeness).",
                        "default": 500
                    },
                    "maxDelayMs": {
                        "title": "Max per-request delay (ms)",
                        "type": "integer",
                        "description": "Upper bound of the random delay inserted before each request (politeness).",
                        "default": 1500
                    },
                    "userAgent": {
                        "title": "User-Agent override",
                        "type": "string",
                        "description": "Optional. Set a real contact string in production."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy",
                        "type": "object",
                        "description": "Both Kijiji and RentFaster block datacenter IPs (Cloudflare), so this defaults to RESIDENTIAL Canadian IPs, rotated per request. Residential proxy is metered (~$8/GB) and draws from your plan credit. Switch the group to datacenter to run free, but expect intermittent blocks.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ],
                            "apifyProxyCountry": "CA"
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
