# Kijiji Scraper: Listings, Cars, Rentals & Prices (`automation_craft/kijiji-scraper`) Actor

Scrape Kijiji by keyword, category and city or postal code, in any sort: prices, places, photos, attributes, seller type. Cars with VIN, km, mileage analysis and history badges; rentals with bedrooms and walk scores. Similar listings, French labels, new listing monitor.

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

## Pricing

from $0.38 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

### Kijiji Scraper: Listings, Cars, Rentals & Prices

**Kijiji Scraper** reads Kijiji (kijiji.ca), Canada's classifieds site, and gives you one row per listing: title, price, category,
place, postal area, map point, posted date, photo links, every attribute (car make, model, year, kilometres and VIN; rental
bedrooms, bathrooms and unit type), the seller type and the view count. Search by keyword, category and Canadian city, postal
code or map point, paste Kijiji search links, or give listing links, in any order Kijiji offers (newest, oldest, price low or
high, relevance, nearest, kilometres). Labels in English or French. No login, no cookies, no browser.

Turn on **listing details** to add the full description, the status and end date, large photos and the seller's public
profile (listing count, member since, and a business's name and website), and for rentals the neighbourhood's walk, transit
and cycle scores. For cars, add Kijiji's **mileage analysis** and price insight, and its **vehicle history** badges; for any
listing, add Kijiji's own **similar listings**. Name a **monitor** and schedule the Actor: each run delivers and bills only
listings it has not delivered before.

This Actor is not affiliated with, endorsed by or sponsored by Kijiji Canada Ltd. or Adevinta. Kijiji is a trademark of its
owner.

#### Who uses it

- **Resellers and flippers** watching a city for underpriced items, newest first, on a schedule.
- **Car dealers and car buyers** reading Cars & Trucks with make, model, year, kilometres, VIN and dealer or private seller.
- **Landlords and rental analysts** reading rents with bedrooms, bathrooms, unit type, furnished and pets.
- **Data teams** who need Canadian classifieds as rows in JSON, CSV or Excel, through the Apify API.

#### Features

| Feature | How | Price |
|---|---|---|
| Search by keyword, category (478, by name, id or path) and place (208 Kijiji locations, postal code or coordinates with a radius) | `keywords`, `categories`, `locations`, `radiusKm` | Listing |
| Pasted Kijiji search links and listing links (or ids) | `searchUrls`, `listingUrls` | Listing (links also Listing detail) |
| Price, seller (private or business), offering or wanted | `minPrice`, `maxPrice`, `sellerType`, `offerType` | included |
| **Cars & Trucks inputs**: make, model, year, kilometres, body type, transmission, fuel, drivetrain, colour, condition | `categories: ["Cars & Trucks"]` and `filters` (`carmake`, `caryear`, `carmileageinkms` ...) | included |
| **Rentals inputs**: bedrooms, bathrooms, unit type, furnished, pets, parking, agreement type | `categories: ["Long Term Rentals"]` and `filters` (`numberbedrooms`, `unittype`, `petsallowed` ...) | included |
| Every filter Kijiji has for a category, checked on Kijiji's own controls on every page | `filters` | included |
| Sort orders Kijiji offers: newest, oldest, price low to high, high to low, relevance, nearest, kilometres low or high | `sortBy` | included |
| Listings in English or French only (detected on the title and description) | `descriptionLanguage` | included |
| Labels in French (Kijiji's own French category, place and attribute names) | `language: "fr"` | included |
| Paid TOP ads, flagged | `includeTopAds` | Listing |
| Full description, status, end date, offer type, large photos, seller profile; rentals: neighbourhood profile and walk, transit, cycle scores | `includeDetails` | Listing detail |
| Private sellers' names, phone numbers, e-mail addresses, streets, postal codes, exact coordinates and full links, off by default (business contact details always come) | `includePrivateSellerDetails` | included |
| **Mileage analysis** (cars): low, average or high km for the car's age, Kijiji's typical km, km per year, price rating, average market price, price against the market | `includeMileageAnalysis` | Mileage analysis |
| **Vehicle history** (cars): Kijiji's badges (No Reported Accidents, One Owner, Low Kilometres, Top Condition) and the CARFAX report link | `includeVehicleHistory` | Vehicle history |
| **Similar listings**: Kijiji's own similar listings of each row, 1 to 50 | `includeSimilarListings`, `similarListingsPerListing` | Similar listing set |
| Derived fields on every row: Kijiji's price rating (cars), repost, motivated seller phrases, the page's median price and an underpriced flag, the text's language; for cars the median price of the same make, model and year among the cars the run has read, with an underpriced flag (and a table of these medians in the summary and the report) | always | included |
| Past Kijiji's 4,040 cap: price band split | `splitLargeSearches` | Listing |
| A monitor: only listings new to it, run after run | `monitorName` | Listing, plus Results page |
| Free rows for every miss (removed, unknown, not applied, not offered), a coverage row per search, a run summary and an HTML run report (key `REPORT`) | always | free |

### Quick start

1. Type a keyword (for example `iphone 13`) and a place (for example `City of Toronto`, `Calgary`, `M5V 2T6` or `Ontario`).
2. Optional: pick a category (`Cars & Trucks`, `Long Term Rentals`, `Cell Phones` or a category id such as `174`), a price range, a seller type, or Kijiji's own filters.
3. Set **Maximum listings** and press **Start**.
4. Download the rows as JSON, CSV or Excel, or read them through the API.

Example input, the Actor's own prefill:

```json
{
    "keywords": ["iphone"],
    "locations": ["City of Toronto"],
    "maxItems": 20
}
```

Cars from dealers in Calgary, 2018 to 2022, under 80,000 km, with details:

```json
{
    "categories": ["Cars & Trucks"],
    "locations": ["Calgary"],
    "sellerType": "business",
    "filters": { "caryear": { "min": 2018, "max": 2022 }, "carmileageinkms": { "max": 80000 } },
    "includeDetails": true,
    "maxItems": 200
}
```

Cars in Toronto, cheapest first, with mileage analysis, vehicle history and 10 similar listings each:

```json
{
    "categories": ["Cars & Trucks"],
    "locations": ["City of Toronto"],
    "sortBy": "price_low",
    "includeMileageAnalysis": true,
    "includeVehicleHistory": true,
    "includeSimilarListings": true,
    "maxItems": 50
}
```

Two bedroom rentals from owners within 5 km of a postal code:

```json
{
    "categories": ["Long Term Rentals"],
    "locations": ["M5V 2T6"],
    "radiusKm": 5,
    "sellerType": "private",
    "filters": { "numberbedrooms": ["2"] }
}
```

### What you get

One row per listing (`type: "listing"`), plus one coverage row per search (`type: "search"`), free status rows for anything
that did not end as a listing (`type: "status"`) and one run summary at the end (`type: "summary"`).

#### Listing fields

| Field | What it holds | Filled (spike, 320 search rows) |
|---|---|---|
| `listingId`, `url`, `title` | Kijiji's id, the listing link, the title | 100% |
| `description` | about 200 characters on search rows; the full text with details on (`descriptionIsFull`) | 100% |
| `price`, `priceCents`, `currency`, `priceType`, `originalPrice`, `priceDropped` | the asking price in CAD (`currency` CAD where a price figure exists), Kijiji's price type (FIXED, CONTACT, GIVE_AWAY, SWAP_TRADE), the price before a drop | price figure 70%, price type 73% (jobs and services mostly show none) |
| `categoryId`, `category`, `categoryPath` | the listing's category in Kijiji's own list | 100% |
| `locationId`, `locationName`, `locationPath`, `postalArea`, `neighbourhood` | Kijiji's place, its path, the first three characters of the postal code, the neighbourhood (rentals) | place 100% |
| `latitude`, `longitude`, `coordinatesRounded` | the map point (two decimals, about 1 km, for private sellers unless `includePrivateSellerDetails` is on) | 97.5% |
| `address`, `nearestIntersection` | the seller's address and nearest intersection (a private seller's only with `includePrivateSellerDetails`) | where Kijiji has one |
| `postedAt`, `sortingDate` | first posted, and the date Kijiji sorts by (a reposted listing moves up) | posted 83%, sorted 100% |
| `imageUrls`, `imageCount` | photo links (200 px on search rows, 640 px with details) | 95% |
| `sellerKind`, `forSaleBy`, `isFromDealer`, `isFromAutosDealer`, `posterId`, `posterRating`, `posterVerified` | private or business by Kijiji's own seller marks (the dealer flag, a business account id, For Sale By, the record's seller type), Kijiji's For Sale By value, the dealer flags (any dealer, a car dealer), the poster's id (the same for all listings of one seller), rating | seller mark 63% to 100% by category |
| `views` | Kijiji's view count when read | 97.5% |
| `vehicleMake`, `vehicleModel`, `vehicleYear`, `vehicleTrim`, `mileageKm`, `vin`, `vehicleCondition`, `bodyType`, `transmission`, `fuelType`, `drivetrain`, `colour` | Cars & Trucks | where the seller gives them |
| `bedrooms`, `bathrooms`, `unitType`, `furnished`, `petsAllowed`, `sizeSqft`, `parkingSpots`, `agreementType`, `availableFrom` | rentals | where the poster gives them |
| `attributes` | every attribute Kijiji holds for the listing, by Kijiji's names | 88% |
| `isTopAd`, `isShowcase`, `isHighlighted`, `adSource` | paid placement flags | 100% |
| `searchKeyword`, `searchCategoryId`, `searchLocation`, `searchLocationId`, `searchRadiusKm`, `searchPriceBand`, `page`, `position` | the search that found the listing | 100% |
| `detailsIncluded`, `monitorNew`, `scrapedAt` | whether the listing's own record was read and merged, whether a monitor delivered it as new, when the row was made | 100% |
| `priceRating`, `priceRatingLabel` | Kijiji's own price badge on a car (GREAT, GOOD, FAIR, POOR: "Great price" ... "Higher price") | cars that carry it |
| `isRepost` | Kijiji sorts the listing more than a day after its first posting (bumped or posted again) | where both dates exist |
| `motivatedSeller`, `motivatedSellerPhrases` | phrases of a seller in a hurry in the title or description ("must sell", "moving", "quick sale", "déménagement" ...) | 100% |
| `descriptionLanguage` | en or fr by the common words of each language in the title and description; null when not clear | where clear |
| `pageMedianPrice`, `underpriced` | the median price figure of the results page the listing came from (5 or more figures), and whether the listing's price is under half of it | search rows |
| `modelMedianPrice`, `modelMedianCarsRead`, `underpricedForModel` | cars: the median price of the same make, model and year among the cars this run delivers from its searches (3 or more: the cars delivered before this row and the row's own round, its own price included; TOP ads not delivered, listings left out by your filters and listing links do not count, and a car of Kijiji's "Other" make or model gets no median; a restarted run starts afresh), how many, and whether the price is under half of it; the summary's table shows the same make and model names as the rows | cars with make, model and year |
| `addOnsIncluded` | the add-ons delivered and billed on this row | 100% |

#### With listing details (`includeDetails`)

| Field | What it holds |
|---|---|
| `description` (full), `descriptionIsFull: true` | the whole text (up to about 10,000 characters seen), HTML turned into text |
| `status`, `endDate`, `offerType` | ACTIVE, when the listing ends, OFFER or WANTED |
| `sellerType`, `sellerListingsCount`, `sellerMemberSince`, `sellerProfileType` | Kijiji's seller type, how many listings the seller has, since when |
| `sellerName`, `sellerWebsite`, `sellerProfileUrl` | the seller's name, website and Kijiji page: a business profile's always; a person's profile (a private seller's, or a person's behind a dealer listing) only with `includePrivateSellerDetails`; the website also from the listing's record (a business listing's always, any listing's with the switch on) |
| `dealerMsrp` | a car dealer's list price, where Kijiji has one |
| `neighbourhoodSummary`, `neighbourhoodTransportation`, `walkScore`, `transitScore`, `cycleScore` (each with its description) | a rental's neighbourhood as Kijiji profiles it, scores 0 to 10 |
| `imageUrls` | 640 px photo links |

Details are read with Kijiji's own listing query in a way that adds no view to the seller's ad. When a seller's profile
cannot be read, the row still carries the listing's own record and is billed its Listing detail; the seller fields stay
empty, apart from the website the listing's record carries (a business's, or with `includePrivateSellerDetails` on any
seller's).

#### Add-ons (each off by default, each its own event, charged only when Kijiji had the data)

| Add-on | Fields | Billed |
|---|---|---|
| `includeMileageAnalysis` (Cars & Trucks) | `mileageUsage` (LOW, AVERAGE, HIGH) and `mileageUsageLabel` ("Low km" ...), `mileageTypicalKm` (Kijiji's low, average and high km for the car's age), `kmPerYear` (Kijiji's rule: the km divided by the age from 1 January of the model year), `marketAveragePrice` (the average market price Kijiji shows, provided to Kijiji by CARFAX Canada), `priceVsMarketPercent`, `priceRating` | a Mileage analysis per car Kijiji has an analysis or a market price for (28 of 30 cars in our probe) |
| `includeVehicleHistory` (Cars & Trucks) | `vehicleHistoryBadges` (accidentFree, lowKilometer, oneOwner, topCondition), `vehicleHistoryBadgeLabels` ("No Reported Accidents" ...), `vehicleHistoryReportUrl` (the CARFAX report link Kijiji shows; the CARFAX site is not read) | a Vehicle history per car with at least one badge (few cars carry one: 3 of 36 in our probes) |
| `includeSimilarListings`, `similarListingsPerListing` (any category) | `similarListings` (each: `listingId`, `title`, `price`, `priceType`, `categoryId`, `category`, `locationId`, `locationName`, `imageUrl`, `url`) and `similarListingsCount` | a Similar listing set per row with at least one |

Rows outside Cars & Trucks carry the car fields empty and are not billed for them. Similar listings come from other sellers
whose kind is not known: unless `includePrivateSellerDetails` is on, their titles get the private seller masks and their
links are by id alone.

#### Coverage row (one per search)

`listingsOnKijiji` (Kijiji's total), `reachableBySearch` and `beyondSearchCap` (Kijiji serves at most 4,040 listings of one
search), `pagesRead`, `listingsSeen`, `listingsDelivered`, `alreadyDelivered`, `knownToMonitor`, `filteredOut`, `topAdsSkipped`,
`externalAdsSkipped` (job ads Kijiji shows from another site), `removedOrGone`, `detailsFailed`, `priceBands`,
`listingsWithoutPriceNotInBands` (a split search's listings with no price figure), `morePagesOffered`,
`newListingsMayLieBeyond` (a monitor), `complete` and `stoppedBy`.

#### Free status rows

A place or category Kijiji does not know or several share (with the candidates), a filter Kijiji does not offer for the
category (with the filters it offers), a search Kijiji did not apply as sent, a removed listing (`removed`, Kijiji keeps its
record with status DELETED), an unknown listing id (`not_found`), a page that could not be read, and the reason a run stopped.

### How much does it cost to scrape Kijiji?

You pay per listing row delivered, plus a small start fee per run. Platform usage is included.

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Listing (per 1,000) | $0.53 | $0.49 | $0.44 | $0.38 |
| Listing detail (per 1,000: with details on, and for every listing link) | $0.35 | $0.33 | $0.31 | $0.30 |
| Mileage analysis (per 1,000 cars, only with `includeMileageAnalysis`) | $0.35 | $0.30 | $0.25 | $0.20 |
| Vehicle history (per 1,000 cars with a badge, only with `includeVehicleHistory`) | $1.50 | $1.40 | $1.30 | $1.20 |
| Similar listing set (per 1,000 rows, only with `includeSimilarListings`) | $0.40 | $0.35 | $0.30 | $0.25 |
| Results page (per 1,000 pages of up to 40 listings, monitor runs only) | $0.15 | $0.15 | $0.15 | $0.15 |
| Actor start (per run) | $0.007 | $0.007 | $0.007 | $0.007 |

Platinum and Diamond plans pay the Gold price. The Store pricing card shows these same prices per 1,000 events: "$0.38 /
1,000" on the Listing row means one listing costs $0.00038. The Actor start event is charged once per run and has no plan
discount.

- **1,000 listings** cost $0.53 on Free and $0.38 on Gold, plus $0.007 for the run; with details, $0.88 on Free and $0.68 on Gold.
  A listing link is always read with its details, so 1,000 listing links cost the with details price.
- **A monitor run** also pays $0.00015 per results page it reads (its window), whatever the page held: a monitor over 3
  searches with 2 pages each pays $0.0009 a run for its pages, plus its new listings and the start fee. Runs without a
  monitor never pay it.
- **What is never billed:** listings left out by your filters, a listing found twice in one run, listings a monitor already
  delivered, removed listings, unknown ids, places or categories Kijiji does not know, searches Kijiji did not apply as sent,
  coverage, status and summary rows.
- **Limits:** set **Maximum listings** and, in the run options, a maximum charge for the run: the Actor stops delivering
  before it would pass either. A run may also send at most 30 requests that deliver nothing billable (searches with no
  match, pages whose listings your filters leave out, removed listings, place and link lookups), plus 2 for every listing
  and every listing detail it delivers, and spend at most 55 seconds on them, plus 5 seconds for every listing and 4 for
  every listing detail it delivers (a request Kijiji answers slowly or not at all spends its time); a long list of searches
  that mostly find nothing stops early with a free row that says so, so split such a list over several runs.

### Input

| Setting | What it does |
|---|---|
| `keywords` | search words; each one is searched in every category and place given |
| `locations` | Kijiji locations by name (City of Toronto, Toronto, Calgary, Montreal, Ontario, ON, Canada), id or path; a postal code (M5V 2T6 or M5V); coordinates (43.6532, -79.3832). Without places a search covers all of Canada |
| `categories` | Kijiji categories by id (174), name (Cars & Trucks) or path, from Kijiji's own list of 478 |
| `radiusKm` | km around a postal code or coordinates (10 when left empty) |
| `searchUrls` | plain links of Kijiji results pages, read the way Kijiji reads them |
| `listingUrls` | listing links or ids, each read with its details and billed as a Listing and a Listing detail |
| `minPrice`, `maxPrice` | price range in whole dollars |
| `sellerType` | any, private or business |
| `offerType` | offering (default) or wanted |
| `filters` | any of Kijiji's own filters for the category, by Kijiji's names: `{"carmake": ["toyota"], "caryear": {"min": 2018}}` |
| `sortBy` | newest (default), oldest, price_low, price_high, relevance (keyword searches), nearest, mileage_low, mileage_high (cars) |
| `descriptionLanguage` | any (default), en or fr: keep only listings written in that language |
| `language` | en (default) or fr: Kijiji's labels in French |
| `includeTopAds` | also deliver Kijiji's paid TOP ads (off by default) |
| `includeDetails` | add the full record and the seller's profile (Listing detail event) |
| `includePrivateSellerDetails` | also deliver private sellers' names, phone numbers, e-mail addresses, streets, postal codes, exact coordinates and full links (off by default; see Privacy) |
| `includeMileageAnalysis` | cars: Kijiji's mileage analysis and price insight (Mileage analysis event) |
| `includeVehicleHistory` | cars: Kijiji's vehicle history badges and report link (Vehicle history event) |
| `includeSimilarListings`, `similarListingsPerListing` | Kijiji's similar listings of each row, 1 to 50, 10 when left empty (Similar listing set event) |
| `splitLargeSearches` | read a search past 4,040 listings band by band of price |
| `maxItems` | the most listing rows a run delivers (100 when left empty) |
| `maxPagesPerSearch` | results pages of 40 per search (1 to 101, 10 when left empty) |
| `monitorName` | a monitor that delivers only listings new to it, run after run |

#### How searches are read

- **In the order you ask.** Every search is read in the order `sortBy` names, newest first by default (Kijiji's sorting date:
  a reposted listing moves up), page after page. Kijiji's own selected order is checked on every page; an order Kijiji does
  not offer for a search (relevance without keywords, kilometres outside cars) is a free row listing the orders it offers. A
  monitor reads newest first.
- **Checked on every page.** Kijiji applies the keyword, category, place, radius and every filter itself; the Actor checks on
  every page that Kijiji applied exactly what was sent, and checks the price and seller filters again on each row. A search
  Kijiji did not apply as sent delivers nothing and gets a free row saying what Kijiji applied.
- **The 4,040 cap.** Kijiji serves at most 101 pages of 40 listings for one search, whatever its total. The coverage row says
  how many listings Kijiji holds and how many lay beyond the cap. With `splitLargeSearches` a larger search is read band by
  band of price, each band small enough to be read whole; listings without a price figure are counted on the coverage row.
- **Places.** A Kijiji location is searched over Kijiji's own area for it. A postal code is placed with Kijiji's geocoder and
  searched within the radius; a postal code Kijiji's geocoder does not know is a free row.

#### The monitor

Name a monitor (`monitorName`) and schedule the Actor. The monitor remembers every listing it delivered in a store this
Actor keeps for this listing, so each run delivers and bills only listings it never delivered before; listings it already
delivered are skipped for free. Each run reads the newest `maxPagesPerSearch` pages of each search and pays a Results page for
each, so keep the pages small for a frequent schedule (1 or 2) and raise them if the coverage row says
`newListingsMayLieBeyond`. The same monitor name
with other searches or filters reads nothing (a free row says so).

### Privacy

Private sellers' personal data sits behind one switch, `includePrivateSellerDetails`, off by default. Off, a private
seller's row (and a row whose seller kind is not known) carries no person's name, Kijiji page or website (a business
profile's still come), no street address or nearest intersection, coordinates rounded to two decimals (about 1 km) and a
link by id alone, and phone numbers, e-mail addresses, street addresses with a house number, full postal codes and names
written into its title, description and attribute values (and into similar listing titles) are masked with a wide rule that
catches the usual writings, not every possible one; those texts come in plain characters. On, all of it comes as Kijiji
shows it to a visitor who is not logged in. A business's (Kijiji's dealer flag, a business account, For Sale By "dealer")
texts, address, coordinates, link, name and website are delivered either way; a business account that marks its listing "by
owner" counts as private, as on Kijiji's own For Sale By filter. Kijiji's own seller phone field is never delivered: logged
out it is cut short (`416710xxxx`) and the full number needs a reCAPTCHA check. Photos are links to Kijiji's image host and
belong to the people who posted them. You are responsible for a lawful use of personal data.

### What this Actor does NOT do

- No seller phone field (Kijiji shows the full number only after a reCAPTCHA check; numbers sellers write into their
  texts come with `includePrivateSellerDetails` on, and always for a business), no messages, offers or posting: those need a
  Kijiji login or a click Kijiji counts.
- No dealer reviews from Google (another site than Kijiji; owner decision) and no CARFAX report contents (another site: the
  report link is given, the report is not read).
- No page past the 101st of a search (Kijiji serves none); use `splitLargeSearches` and the price filters.
- No eBay cross listings filter: none was seen on Kijiji (3,844 rows of this Actor's test runs came from Kijiji itself).
- Status messages are in English in both label languages.
- No job ads Kijiji shows from another site (they link off Kijiji; counted on the coverage row).
- No Kijiji Autos (closed in 2025) and no Kijiji outside Canada.
- Filters in a pasted search link are not read: paste the plain first page link and use the filter settings.

### FAQ

#### Does Kijiji have an API?

Kijiji offers no public API for its listings. This Actor reads the same public listing data any visitor sees, with no login,
and gives it to you as rows you can read through the Apify API (examples below).

#### How do I scrape Kijiji listings without coding?

Type a keyword and a place, press Start, and download the rows as CSV or Excel. The Actor reads Kijiji's own search for you,
newest first, and needs no login.

#### How do I get new Kijiji listings automatically?

Name a monitor and schedule the Actor (every hour, for example). Each run delivers only listings the monitor has not
delivered before, newest first, and bills only those.

#### Can I scrape Kijiji cars with VIN and mileage?

Yes. Search the Cars & Trucks category (id 174): rows carry make, model, year, kilometres and the VIN where the seller gives
it, and `sellerType` picks dealers or private sellers. Kijiji's own car filters (make, year, kilometres, body type,
transmission) go in `filters`, and `sortBy` reads by price or kilometres. Add `includeMileageAnalysis` for Kijiji's low,
average or high mileage rating and its average market price, and `includeVehicleHistory` for its history badges.

#### Is it legal to scrape Kijiji?

This Actor reads only public listings without logging in and never passes Kijiji's reCAPTCHA check for a phone number.
Private sellers' names, contacts and addresses are masked unless you turn on `includePrivateSellerDetails`. Kijiji's terms restrict
automated collection and reuse; you are responsible for a lawful use of the data you collect, personal data included.

#### Why does this Actor run with limited permissions?

It needs nothing beyond its own storage: it reads Kijiji's public listings and writes to its own dataset. Limited permissions
keep it from touching anything else in your account. A monitor is a named store the Actor creates for itself.

### API

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~kijiji-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["iphone"], "locations": ["City of Toronto"], "maxItems": 20}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/kijiji-scraper').call({ keywords: ['iphone'], locations: ['City of Toronto'], maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((x) => x.type === 'listing'));
```

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("automation_craft/kijiji-scraper").call(run_input={"keywords": ["iphone"], "locations": ["City of Toronto"], "maxItems": 20})
rows = [x for x in client.dataset(run["defaultDatasetId"]).iterate_items() if x["type"] == "listing"]
```

### Changelog

See the Changelog tab. 0.1: first release.

### More data tools by Automation Craft

- [Airbnb Scraper: Prices, Calendar, Reviews](https://apify.com/automation_craft/airbnb-scraper)
- [Amazon Product Scraper - Search, Best Sellers](https://apify.com/automation_craft/amazon-data-scraper)
- [Trustpilot Reviews Scraper: Coverage Per Company](https://apify.com/automation_craft/trustpilot-reviews-scraper)
- [US New Business Registrations Scraper - LLC Leads](https://apify.com/automation_craft/us-new-business-registrations-scraper)
- [Google Trends Scraper - Compare and Trending Now](https://apify.com/automation_craft/google-trends-scraper)
- [LinkedIn Jobs Scraper - No Login, Real Dates](https://apify.com/automation_craft/linkedin-jobs-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/kijiji-scraper/changelog.md

# Actor input Schema

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

Search words as you would type them on Kijiji, for example iphone 13, sectional sofa or honda civic. Up to 100 characters each.

## `locations` (type: `array`):

Kijiji locations by name from Kijiji's own list (City of Toronto, Toronto, Toronto (GTA), Calgary, Montreal, Ontario, ON, Canada), by location id (1700273) or by path (Ontario > Toronto (GTA)); a Canadian postal code (M5V 2T6 or its first three characters M5V); or coordinates (43.6532, -79.3832). A postal code or coordinates are searched around that point with the radius below. A name several Kijiji locations share, or a place Kijiji does not know, is answered with a free row, and its searches are not read.

## `categories` (type: `array`):

Kijiji categories by id (174), by name (Cars & Trucks, Long Term Rentals, Cell Phones) or by full path (Buy & Sell > Phones > Cell Phones), from Kijiji's own list of 478 categories. A name several categories share (Other) is answered with a free row that lists their ids and paths. Leave empty to search every category.

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

How far around a postal code or coordinates to search (1 to 1000 km; 10 when left empty). A Kijiji location is searched over its own area, so this setting needs a postal code or coordinates among the places.

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

Links of Kijiji results pages, such as https://www.kijiji.ca/b-cars-trucks/calgary/c174l1700199 or https://www.kijiji.ca/b-buy-sell/city-of-toronto/iphone-13/k0c10l1700273. Each link is read the way Kijiji reads it and searched newest first with the filters below. Paste the plain link of the first page: a link with filters in its query string or a page number is refused with a free row (use the settings below for filters). Through the API an item may also be {"url": "..."}.

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

Kijiji listing links (https://www.kijiji.ca/v-<category>/<place>/<title>/<listing id>) or listing ids. Each one is read with its details and its seller's public profile and delivered as given, so each link is billed as a Listing and a Listing detail whatever "Include listing details" says; the search filters below do not apply to links. A removed listing or an unknown id is a free row. Through the API an item may also be {"url": "..."}.

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

Lowest asking price in whole dollars. Listings without a price figure (contact, free, swap) do not pass a price filter.

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

Highest asking price in whole dollars.

## `sellerType` (type: `string`):

Private sellers or businesses and dealers only, by Kijiji's own seller marks. Where the category has Kijiji's own For Sale By or For Rent By filter, Kijiji applies it; on every row the marks decide (Kijiji's dealer flag, a business account id, the For Sale By value, the record's seller type). A business that marks its listing by owner counts as private, as on Kijiji. A row that carries no seller mark does not pass this filter. Default: any seller.

## `offerType` (type: `string`):

Kijiji's searches show offers unless asked for wanted ads. Default: offering.

## `filters` (type: `object`):

Any filter of Kijiji's own filter list for a category, by Kijiji's own names and values: a list of values, or a range as {"min": n, "max": n}. Examples: cars {"carmake": \["toyota", "honda"], "caryear": {"min": 2018, "max": 2022}, "carmileageinkms": {"max": 80000}, "cartransmission": \["2"]}; rentals {"numberbedrooms": \["2"], "unittype": \["apartment"], "petsallowed": \["1"]}. A filter the category does not have, or a value Kijiji does not use there, is answered with a free row that lists what Kijiji offers. Price, seller and offer type have their own settings.

## `sortBy` (type: `string`):

The order Kijiji reads each search in, from the orders Kijiji itself offers (checked on every page: a search Kijiji does not sort as asked delivers nothing and gets a free row listing the orders it offers there; relevance needs keywords, kilometres need Cars & Trucks). Default: newest first. A monitor reads newest first only.

## `descriptionLanguage` (type: `string`):

Keep only listings whose title and description are written in English or in French, by the common words of each language (a listing whose language is not clear does not pass). Listings left out are free. Every row carries descriptionLanguage. Default: any.

## `includeTopAds` (type: `boolean`):

Also deliver the paid TOP ads Kijiji places at the head of each results page (flagged isTopAd, delivered once each). Off by default: TOP ads are not in newest first order and repeat across searches.

## `language` (type: `string`):

The language of Kijiji's own labels in the rows: category and place names and paths, car and rental values (Automatique, Propriétaire) and badge texts, as Kijiji shows them in French. Titles and descriptions stay as the seller wrote them; status messages stay in English. Default: English.

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

Read each delivered listing's own record and its seller's public profile: the full description (search rows carry about 200 characters), the status and end date, the offer type, every attribute, large photos, and for the seller the number of listings, member since and, for a business, its name and website. Reads add no view to the seller's ad. Billed as a Listing detail event per row. Off by default.

## `includePrivateSellerDetails` (type: `boolean`):

Off by default (also when left out or empty). Off, a private seller's row, and a row whose seller kind Kijiji does not show, carries no person's name or Kijiji page (a business profile's name, page and website still come), no street address or nearest intersection, coordinates rounded to about 1 km (coordinatesRounded true) and a listing link by id alone, and phone numbers, e-mail addresses, street addresses with a house number, full postal codes and names written into titles, descriptions, attribute values (and the fields taken from them) and similar listing titles are masked with a wide rule that catches the usual writings, not every possible one. On, a private seller's row carries them as Kijiji shows them to a visitor who is not logged in: sellerName, sellerProfileUrl and sellerWebsite (with details on), address, nearestIntersection, exact latitude and longitude (coordinatesRounded false), Kijiji's full listing url, and the title, description, attributes and the fields taken from them (such as vehicleTrim and vehicleHistoryReportUrl) and similar listing titles and links as written, phone numbers and e-mail addresses included. Business and dealer sellers' contact details are delivered either way. Kijiji's own seller phone field is never delivered (it needs a reCAPTCHA check). You are responsible for a lawful use of personal data (GDPR and Canada's PIPEDA included).

## `includeMileageAnalysis` (type: `boolean`):

For Cars & Trucks listings, add Kijiji's own mileage analysis (low, average or high kilometres for the car's age, Kijiji's typical kilometres and the kilometres per year by Kijiji's rule) and its price insight (Kijiji's price rating and the average market price it shows, with the difference in percent). Billed as a Mileage analysis event per car Kijiji has one for; other rows carry the fields empty and are not billed. Off by default.

## `includeVehicleHistory` (type: `boolean`):

For Cars & Trucks listings, add Kijiji's vehicle history badges (such as No Reported Accidents, One Owner, Low Kilometres) and the CARFAX report link Kijiji shows (the CARFAX site itself is not read). Billed as a Vehicle history event per car that has at least one badge; others are not billed. Off by default.

## `includeSimilarListings` (type: `boolean`):

Add Kijiji's own similar listings of each delivered listing (id, title, price, category, place, photo, link). Billed as one Similar listings event per row that gets at least one. Off by default.

## `similarListingsPerListing` (type: `integer`):

How many similar listings each row carries (1 to 50; 10 when left empty). Needs Add similar listings.

## `splitLargeSearches` (type: `boolean`):

Kijiji serves at most 4,040 listings (101 pages) of one search. With this on, a search that holds more is read band by band of price, each band small enough to be read whole; listings without a price figure are counted on the coverage row. Off by default. Not with a monitor.

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

The most listing rows this run delivers (and bills), over all searches. 100 when left empty.

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

How many results pages of 40 listings each search reads at most (1 to 101; Kijiji serves no page past the 101st). 10 when left empty. With splitLargeSearches it applies to each price band.

## `monitorName` (type: `string`):

Name a monitor to run on a schedule: it remembers every listing it delivered (in a store this Actor keeps for this listing) and every later run delivers and bills only listings it has not delivered before. Each run reads the newest pages of each search (Pages per search). The same name with other searches or filters reads nothing. Up to 60 letters, digits, spaces and . \_ , - : # ( ).

## Actor input object example

```json
{
  "keywords": [
    "iphone"
  ],
  "locations": [
    "City of Toronto"
  ],
  "includePrivateSellerDetails": false,
  "maxItems": 20
}
```

# Actor output Schema

## `items` (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 = {
    "keywords": [
        "iphone"
    ],
    "locations": [
        "City of Toronto"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/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 = {
    "keywords": ["iphone"],
    "locations": ["City of Toronto"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/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 '{
  "keywords": [
    "iphone"
  ],
  "locations": [
    "City of Toronto"
  ],
  "maxItems": 20
}' |
apify call automation_craft/kijiji-scraper --silent --output-dataset

```

## MCP server setup

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