# Kijiji Scraper — Listings, Cars, Rentals & New-Listing Alerts (`yugenox/kijiji-scraper`) Actor

Scrape Kijiji.ca classifieds from any search URL or by keyword, city and category. Prices, photos, locations, attributes, car details (year, make, model, km, VIN) and rental details (beds, baths, utilities). Monitor mode returns only new listings and price drops.

- **URL**: https://apify.com/yugenox/kijiji-scraper.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** E-commerce, Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Kijiji Scraper — Listings, Cars, Rentals & New-Listing Alerts

Scrape **Kijiji.ca**, Canada's largest classifieds site, into clean JSON, CSV or Excel. Paste any Kijiji search URL, or search by keyword, city and category, and get every listing with its price, photos, location, category, posting date, seller type and attributes. Car listings come with **year, make, model, trim, kilometres, transmission, drivetrain and VIN** in their own columns. Rental listings come with **bedrooms, bathrooms, unit type, size, utilities, pets and parking**.

Put it on a schedule with **monitor mode** and each run returns only the **new listings and price drops** since the last run, which makes it an alert feed for deals, inventory or rentals.

No Kijiji account is needed.

### What you can scrape

- **Any Kijiji search URL.** Set up a search on kijiji.ca with a keyword, category, location, price range, filters and sort, then paste the URL. The scraper keeps all of those settings.
- **Keyword searches.** Enter keywords with a city or province ("Toronto", "GTA", "Calgary", "BC") and optionally a category ("Cars & Trucks", "Long Term Rentals", "Furniture"). You can also add a price range, sort order and ad type.
- **Radius searches.** Give a latitude/longitude and a distance in km.
- **Whole categories.** Enter a category and location with no keywords to browse the whole category. For example, every car in Calgary.
- **Single listings.** Paste a listing URL to get that listing's full details.
- **Large searches.** Kijiji shows at most about 4,000 results for one search. When you ask for more, the scraper splits the search into sub-categories, sub-regions and price ranges on its own and removes the duplicates.

### Output fields

| Group | Fields |
|---|---|
| Listing | `id`, `url`, `title`, `description`, `categoryName`, `categoryPath`, `adType` |
| Price | `price` (CAD), `priceType` (FIXED / GIVE\_AWAY / CONTACT / SWAP\_TRADE), `originalPrice`, `priceDropped` |
| Where | `city`, `province`, `locationName`, `latitude`, `longitude`, `address` + `postalCode` (business listings) |
| When | `postedAt`, `refreshedAt` (last bump), `endsAt` |
| Photos | `imageUrl`, `images` (full size), `imageCount` |
| Seller | `sellerType` (private / business), `sellerVerified`, `sellerRating` |
| Placement | `isTopAd`, `isShowcase`, `isHighlighted` |
| Attributes | `attributes` (every Kijiji attribute), `attributeLabels` (human-readable, with details) |
| Cars | `autos.year`, `make`, `model`, `trim`, `mileageKm`, `condition`, `bodyType`, `transmission`, `drivetrain`, `fuelType`, `color`, `doors`, `seats`, `vin`, `stockNumber` |
| Rentals | `realEstate.bedrooms`, `bathrooms`, `unitType`, `sizeSqft`, `furnished`, `petsAllowed`, `parkingSpots`, `agreementType`, `rentedBy`, `availableFrom`, `utilitiesIncluded`, `laundryInUnit`, `airConditioning`, `balcony`, `neighbourhood`, `virtualTour`… |
| With **Full listing details** | full `description`, all `images`, `views`, `status`, `endsAt`, `videoUrl`, `attributeLabels` |
| Monitor mode | `monitorEvent` (new / priceDrop / resurfaced), `previousPrice` |

#### Sample (car listing, full details on)

```json
{
  "id": "1742577667",
  "url": "https://www.kijiji.ca/v-cars-trucks/city-of-toronto/2018-ford-f-150-xlt-4x4-5-0l-v8-backup-camera-clean-carfax/1742577667",
  "title": "2018 Ford F-150 XLT 4x4 - 5.0L V8 - Backup Camera - Clean Carfax",
  "price": 17990,
  "priceType": "FIXED",
  "currency": "CAD",
  "categoryPath": "Cars & Vehicles > Cars & Trucks",
  "city": "Scarborough",
  "province": "ON",
  "address": "2115 Lawrence Avenue East, Scarborough, ON, M1R 2Z8",
  "latitude": 43.745823,
  "longitude": -79.290037,
  "imageUrl": "https://media.kijiji.ca/api/v1/ca-prod-dealer-ads/images/38/388e438f-a043-4ae0-a604-b9e12d112cd4?rule=kijijica-1600-jpg",
  "imageCount": 27,
  "postedAt": "2026-08-26T14:43:27.000Z",
  "refreshedAt": "2026-09-23T13:56:11.000Z",
  "status": "ACTIVE",
  "views": 577,
  "sellerType": "business",
  "autos": {
    "year": 2018, "make": "Ford", "model": "F-150", "trim": "XLT", "mileageKm": 248799,
    "condition": "Used", "bodyType": "Pickup Truck", "transmission": "Automatic",
    "drivetrain": "4 x 4", "fuelType": "Gas", "color": "Black", "vin": "1FTFW1E58JKF46621"
  },
  "realEstate": null,
  "monitorEvent": null
}
```

The dataset has three ready-made table views: **Overview**, **Cars & vehicles** and **Rentals & real estate**.

### Input examples

**Paste a search:**

```json
{ "startUrls": ["https://www.kijiji.ca/b-cars-trucks/calgary/c174l1700199?price=5000__15000"], "maxItems": 500 }
```

**Keywords in a city:**

```json
{ "keywords": ["iphone 15", "ipad"], "location": "Montreal", "sort": "priceAsc", "maxPrice": 800, "maxItemsPerQuery": 200 }
```

**Rentals with full details:**

```json
{ "category": "Long Term Rentals", "location": "Toronto", "maxItems": 300, "includeDetails": true }
```

**Hourly new-listing alert (schedule this):**

```json
{ "keywords": ["dji drone"], "location": "GTA", "monitorMode": "newAndPriceDrops", "monitorStateKey": "gta-drones", "maxItemsPerQuery": 120 }
```

### Monitor mode

On a schedule, turn on **Monitor mode** and give the monitor a name. The first run saves everything it finds as the baseline. After that, each run returns:

- **new**: listings posted since the previous run.
- **priceDrop**: listings seen before whose price went down. The old price is in `previousPrice`. This needs "New listings + price drops".
- **resurfaced**: listings not seen before but posted earlier, such as ads bumped back to the top. These are returned only if you turn the option on.

Listings that haven't changed are skipped and **not charged**. With "Newest first" order, each run stops as soon as it reaches listings the previous run already covered, so frequent schedules stay fast and cheap.

### Use cases

- **Car dealers and flippers.** Track every new vehicle in a region with year, make, model, km and VIN, then spot underpriced cars as they're posted.
- **Rental market analysis.** Get rents by neighbourhood, bedrooms, unit type and utilities for Toronto, Vancouver, Montreal or any city.
- **Resellers and deal hunters.** Get alerts for new listings and price drops on items you buy.
- **Price research.** Build second-hand price benchmarks for any product category across Canada.
- **Lead generation for businesses.** Find which dealers and businesses advertise in a category and area. Business listings include their public address.

### FAQ

**What happens if Kijiji doesn't respond, the run hits its time limit, or something breaks?** The run always finishes as SUCCEEDED with everything collected so far and a status message that says what happened (for example "Partial — 652 listings saved before the run's time limit …"). You are only charged for listings that were actually saved. If the full-details lookup fails for some listings, you still get their search data (and are not charged the detail event for them).

**My input uses different field names.** Common aliases are accepted: `maxResults` / `limit` for `maxItems`, `url` / `urls` for `startUrls`, `keyword` / `query` for `keywords`, `city` for `location`, `fetchDetails` for `includeDetails`, `sortBy` with names like "newest" or "cheapest". Lists may be given as one string (URLs one per line, keywords separated by commas).

**How many listings can I get?** Kijiji shows at most about 4,040 listings for one search. Above that, the scraper splits the search into sub-categories, sub-regions and price bands on its own and removes duplicates. Listings with no price ("Please contact") beyond the first 4,040 can't be reached by price bands.

**Why is the description short?** Search results carry a snippet and the first photo. Turn on **Full listing details** to get the full description, every photo, the view count and the listing status.

**What about private sellers?** For private sellers the scraper never returns names or phone numbers. It also leaves out the street address, postal code and nearest intersection, and rounds map coordinates to about 1 km. Phone numbers and e-mail addresses written into the description are masked. Business and dealer listings keep their public address.

**Which proxy should I use?** Leave the default. The scraper starts on Apify datacenter proxies and switches to Canadian residential proxies on its own when a request needs it.

**Why does postedAt equal refreshedAt for some cars?** Kijiji's car search results only show when a listing was last refreshed. Turn on **Full listing details** to get the original posting date.

**Is it legal to scrape Kijiji?** This Actor only collects publicly available data: the listings, prices, photos, locations and listing details that anyone can see on kijiji.ca without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it. Listing text is written by the people who posted it, so a description can mention a name, and business listings keep the address and contact details the business published; that can count as personal data. You must follow privacy laws such as GDPR, PIPEDA and CCPA, as well as Kijiji's terms. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. Everything comes from pages kijiji.ca shows to any visitor without logging in. It never uses a login or a Kijiji account, never touches private or restricted accounts, never reaches password-protected areas, and never returns a seller's name, phone number or e-mail as a field. For private sellers it also leaves out the street address and postal code and masks phone numbers and e-mail addresses written into the description.

**Can I scrape in French?** Yes. Paste French Kijiji URLs as they are. Titles and descriptions come back as the seller wrote them, and category names come back in English.

# Actor input Schema

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

Paste any Kijiji search URL — with its keyword, category, location, filters and sort exactly as you set them on kijiji.ca (e.g. https://www.kijiji.ca/b-cars-trucks/calgary/c174l1700199?price=5000\_\_15000). Listing URLs (https://www.kijiji.ca/v-…/1739736810) return that one listing with full details.

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

Or search by keyword. Each keyword runs its own search, using the location, category and filters below.

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

City, region or province for keyword searches: "Toronto", "GTA", "Montreal", "Greater Vancouver Area", "Calgary", "ON", "BC"… or a Kijiji location id. Empty = all of Canada.

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

Kijiji category for keyword searches: "Cars & Trucks", "Long Term Rentals", "Furniture", "Bikes", "Electronics"… or a Kijiji category id. Empty = all categories. Setting only a location and/or category (no keywords) browses that whole category.

## `sort` (type: `string`):

Order of results for keyword searches. URLs keep their own sort.

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

Keyword searches only.

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

Keyword searches only.

## `adType` (type: `string`):

Offering (for sale / for rent) or Wanted ads. Keyword searches only.

## `latitude` (type: `string`):

Search around a point instead of a named location, e.g. 43.6532. Use with Longitude and Radius.

## `longitude` (type: `string`):

e.g. -79.3832

## `radiusKm` (type: `integer`):

Distance around the point, in km.

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

Maximum number of listings saved across the whole run. Leave empty for no total limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for each URL / keyword. Kijiji itself shows at most 4,040 listings for one search; above that the scraper automatically splits the search into sub-categories, sub-regions and price ranges to go further. In monitor mode this is how deep each search is checked.

## `postedWithinHours` (type: `integer`):

Skip older listings. With "Newest first" order the scan stops as soon as it reaches older listings, so this is also fast and cheap.

## `includeDetails` (type: `boolean`):

Open every listing for its full description, all photos, view count, status, end date and labelled attributes (search results carry a short description and the first photo).

## `skipTopAds` (type: `boolean`):

Leave out the paid "Top Ad" listings Kijiji pins above the results (they are often older and repeat on every page). Organic results only.

## `monitorMode` (type: `string`):

For scheduled runs: remember what earlier runs saw and save only what changed. "New listings" returns listings posted since the previous run; "New + price drops" also returns listings whose price went down (with previousPrice). The first run saves everything as the baseline. Unchanged listings are skipped and not charged.

## `monitorStateKey` (type: `string`):

Name for this monitor's memory, e.g. "calgary-trucks". Use a different name for each separate alert. Empty = derived from the searches.

## `monitorIncludeResurfaced` (type: `boolean`):

Also return listings not seen before but posted before the previous run (bumped back to the top, or older ads appearing for the first time). They carry monitorEvent "resurfaced".

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

How many pages are fetched at the same time.

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

Apify Proxy is required. Datacenter proxy is used first (cheapest) and blocked IPs automatically fall back to Canadian residential proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.kijiji.ca/b-gta-greater-toronto-area/drone/k0l1700272"
  ],
  "sort": "dateDesc",
  "adType": "OFFER",
  "maxItems": 50,
  "maxItemsPerQuery": 100,
  "includeDetails": false,
  "skipTopAds": false,
  "monitorMode": "off",
  "monitorIncludeResurfaced": false,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every row this run saved, as JSON.

## `resultsCsv` (type: `string`):

The same rows as CSV, ready for a spreadsheet.

## `resultsTable` (type: `string`):

The same rows narrowed to the key columns (the "overview" view).

# 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 = {
    "startUrls": [
        "https://www.kijiji.ca/b-gta-greater-toronto-area/drone/k0l1700272"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/kijiji-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 = {
    "startUrls": ["https://www.kijiji.ca/b-gta-greater-toronto-area/drone/k0l1700272"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/kijiji-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 '{
  "startUrls": [
    "https://www.kijiji.ca/b-gta-greater-toronto-area/drone/k0l1700272"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/kijiji-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/kijiji-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/pPpvWxpeikF4aBtGl/builds/07VlRZwr3ks6OuOnW/openapi.json
