# Kijiji Scraper – Listings, Prices, Cars, Canada (`loudtzu/kijiji-listings-scraper`) Actor

Scrape Kijiji.ca search results by keyword, province or any search URL: title, price, category, city, province, postal prefix, photos, car specs and other attributes. No seller IDs or contact info. $0.39 per 1,000 listings, no start fee.

- **URL**: https://apify.com/loudtzu/kijiji-listings-scraper.md
- **Developed by:** [Travis M](https://apify.com/loudtzu) (community)
- **Categories:** Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.39 / 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, prices and car specs across Canada ($0.39 per 1,000 listings)

Get **Kijiji.ca search results** as clean data. Search by keyword (all of Canada or chosen provinces) or paste any Kijiji search URL with your category, city and filters already set. Each listing comes back as one row: title, price, category, city, province, postal prefix, photos, posting date and the listing's attributes (condition, and for cars: make, model, year, mileage, transmission and so on).

The Actor reads the same public search pages anyone sees in a browser. It uses no login and no proxies, and it **never outputs seller IDs, names, ratings, phone numbers or emails**.

### Why this one

| | This Actor | Other Kijiji Actors on the Store |
|---|---|---|
| Keyword × province searches built for you | ✅ 11 provinces/regions, IDs checked | Varies |
| Price as a number (CAD), price rating for cars, price-drop and top-ad flags | ✅ | Varies |
| Province + postal prefix (FSA) on every row | ✅ derived from the listing location | Varies |
| Privacy | No seller ID, name, rating or contact details. Street addresses are reduced to the postal prefix and coordinates rounded to ~1 km. In text, postal codes are cut to the FSA, and street addresses, emails, phone numbers and names after "call/text/contact/ask for" are masked | Varies |
| Honest blocking | Clear "Blocked by Kijiji" status, keeps the listings collected so far | Varies |

| Price per listing (USD) | Free | Bronze | Silver | Gold | Platinum | Diamond | Start fee |
|---|---|---|---|---|---|---|---|
| **This Actor** | **0.00039** | **0.00039** | **0.00039** | **0.00039** | **0.00039** | **0.00039** | **none** |
| fayoussef | 0.0009 | 0.0009 | 0.00089 | 0.00088 | 0.00088 | 0.00088 | $0.00005 |
| memo23 | 0.00095 | 0.00095 | 0.00095 | 0.00095 | 0.00095 | 0.00095 | $0.005 |
| automation-lab | 0.00345 | 0.003 | 0.00234 | 0.0018 | 0.0012 | 0.00084 | $0.005 |
| haketa | 0.004 | 0.0035 | 0.003 | 0.0025 | 0.0025 | 0.0025 | $0.00005 |
| ivanvs | 0.0035 | 0.0035 | 0.0035 | 0.0035 | 0.0035 | 0.0035 | none |
| calm_builder (58 users) | 0.0006 | 0.0005 | 0.00045 | 0.0004 | 0.0004 | 0.0004 | $0.001 per GB of memory |
| service-paradis (72 users) | 0.002 | 0.0018 | 0.0016 | 0.0014 | 0.0014 | 0.0014 | none |
| smartspidering (134 users) | no Actor fee | | | | | | you pay only platform usage (compute + proxy) |

Prices are taken from each Actor's Store listing on Oct 24, 2026 (Free → Diamond tiers; calm_builder also sells optional detail/report add-ons). Rivals may open listing pages for full descriptions; this one reads search results only (see limits).

### Privacy-safe by design

- Left out by default: seller IDs, names, ratings, phone numbers and emails; listing URLs use the short form without the address slug.
- Location is reduced to city, province and postal prefix (FSA), with coordinates rounded to about 1 km.
- In titles, descriptions and attributes, emails, phone numbers, street addresses and names after cues like "call" or "ask for" are masked.
- There is no opt-in input to collect seller details.
- How you use the data is your responsibility under the privacy laws that apply to you (e.g. PIPEDA, GDPR, CCPA). These defaults reduce privacy risk; they are not legal advice or a guarantee of legal compliance.

### Input

| Field | Default | Notes |
|---|---|---|
| `keywords` | | e.g. `["mountain bike", "iphone 15"]` |
| `provinces` | all of Canada | AB, BC, MB, NB, NL, NS, ON, PE, QC, SK, TERR |
| `searchUrls` | | Any `https://www.kijiji.ca/b-…` results URL (category, city, radius and filters set on kijiji.ca) |
| `minPrice` / `maxPrice` | | CAD. Listings without a price are dropped when set |
| `excludeTopAds` | false | Skip paid placements |
| `maxPagesPerSearch` | 10 | ~40 listings per page |
| `maxItems` | 100 | Up to 50,000 in total |

```json
{ "keywords": ["mountain bike"], "provinces": ["NS", "NB"], "maxPrice": 1500, "maxItems": 300 }
```

### Output (one row per listing)

| Field | Example |
|---|---|
| `listingId`, `listingType`, `url` | `1741576997`, `AutosListing`, `https://www.kijiji.ca/v-a/a/1741576997` |
| `title`, `description` | Description is Kijiji's search snippet (~200 chars). Emails, phones, street addresses and names after contact cues masked; postal codes cut to FSA |
| `price`, `originalPrice`, `currency`, `priceType`, `priceRating` | `18599`, `null`, `CAD`, `FIXED`, `FAIR` |
| `categoryId` | `174` |
| `city`, `province`, `postalPrefix`, `latitude`, `longitude` | `Dartmouth`, `NS`, `B2W`, `44.67`, `-63.54` |
| `sellerType` | `private`, `dealer` or `business` (type only, no identity) |
| `postedAt`, `sortedAt` | ISO dates |
| `isTopAd`, `isShowcase`, `priceDrop` | flags |
| `imageUrls`, `imageCount` | Thumbnail URLs |
| `attributes` | `{"carmake": "ram", "condition": "usedgood", …}` (Kijiji's own codes) |

### Use cases

- Used-car and resale price tracking by province
- Market research on demand and supply for a product category
- Deal alerts: run on a schedule with a `maxPrice`

### Honest limits

- sellerType is often empty outside cars.
- **Search-results data only.** The full description and the full photo set are on each listing page, which this version doesn't open. `description` is Kijiji's snippet.
- **No proxy.** Kijiji may block or rate-limit datacenter IPs. The Actor waits 2–3 seconds between pages and retries 429/5xx 3 times (2/4/8 s). If it's blocked, it stops with a clear status and you're charged only for listings saved.
- Kijiji repeats "Top Ads" across pages; duplicates are removed. A search ends when a page brings no new listings.
- `attributes` uses Kijiji's internal codes (e.g. `usedgood`) as-is.
- `province` comes from the listing address or postal prefix; `postedAt` is missing on some listings (`sortedAt` is always present).
- Masking is pattern-based (English and French cues). Unusual formats such as a name with no cue word or an address without a street suffix can slip through.
- New Actor with no reviews yet.

# Actor input Schema

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

Search terms, e.g. 'mountain bike'. Each is searched across Canada, or in each province you pick below.

## `provinces` (type: `array`):

Used with keywords. Empty = all of Canada.

## `searchUrls` (type: `array`):

Any Kijiji search-results URL (https://www.kijiji.ca/b-...), with your category, city and filters already set on kijiji.ca.

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

Drop listings below this price (and listings without a price).

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

Drop listings above this price (and listings without a price).

## `excludeTopAds` (type: `boolean`):

Skip paid 'Top Ad' placements.

## `maxPagesPerSearch` (type: `integer`):

About 40 listings per page.

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

Total listings for this run. You pay per listing saved.

## Actor input object example

```json
{
  "keywords": [
    "mountain bike"
  ],
  "excludeTopAds": false,
  "maxPagesPerSearch": 10,
  "maxItems": 100
}
```

# Actor output Schema

## `listings` (type: `string`):

All listings, 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 = {
    "keywords": [
        "mountain bike"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("loudtzu/kijiji-listings-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 = { "keywords": ["mountain bike"] }

# Run the Actor and wait for it to finish
run = client.actor("loudtzu/kijiji-listings-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 '{
  "keywords": [
    "mountain bike"
  ]
}' |
apify call loudtzu/kijiji-listings-scraper --silent --output-dataset

```

## MCP server setup

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