Kijiji Scraper & API - New Listings to Discord, Telegram
Pricing
$1.50 / 1,000 listings
Kijiji Scraper & API - New Listings to Discord, Telegram
Kijiji new listings to Discord, Telegram, Slack or any webhook: a Kijiji bot for saved searches that sends only ads not seen before. Also scrapes public Kijiji search listings with price, location, date, category, condition and images. No login.
Pricing
$1.50 / 1,000 listings
Rating
0.0
(0)
Developer
Luke Hunter
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Kijiji Scraper - Listings, Prices & New-Ad Alerts
For resellers, dealers, market analysts and agencies who need Kijiji listings data in bulk. Scrape public Kijiji search results (Canada) and return one flat row per ad - title, asking price, location, date, category, condition and image - or schedule it in new-ad alert mode to catch fresh listings for a saved search as they appear.
Pay per delivered listing: $0.0015 per listing — 1,000 listings = $1.50.
Collect public Kijiji search-result listings without login, cookies, proxies, CAPTCHA solving, or seller-profile crawling. The Actor checks robots.txt for every search-page path before fetching it and stops a search honestly when a later page is disallowed, blocked, challenged, or unavailable. Earlier delivered pages remain in the dataset.
Quick start (1 minute)
- Open the Input tab and enter one or more search terms, e.g.
bike(or paste public Kijiji search-page URLs intostartUrls). - Click Start.
- Export the dataset to CSV, Excel or JSON, or read it through the API.
{"searchTerms": ["bike"],"maxPagesPerSearch": 1,"maxItems": 20}
That prefilled example returns up to 20 listings and costs at most $0.03.
You can also provide public search-page startUrls. maxPagesPerSearch is 1-10 (default 2); maxItems is a hard run-wide cap (default 100, maximum 5000). Turn on onlyNewSinceLastRun for scheduled new-ad alerts; stateStoreName isolates remembered listing IDs.
Example output
This row is based on the committed capture fixture; unavailable fields remain null.
{"id": "1742515731","url": "https://www.kijiji.ca/v-mountain-bike/st-catharines/2026-trek-marlin-xs-27-5-wheels/1742515731","title": "2026 Trek Marlin – XS – 27.5” Wheels","price": 750,"currency": null,"priceType": "FIXED","location": "St. Catharines","date": "2026-08-25T02:22:46.000Z","category": "647","condition": "usedlikenew","imageUrl": "https://media.kijiji.ca/api/v1/ca-prod-fsbo-ads/images/5b/5b29fbaf-cd45-44a7-9cb7-3050d0c0b78d?rule=kijijica-200-jpg","isBusinessSeller": false}
Rows are flat and always include id, url, title, price, currency, priceType, location, date, category, condition, imageUrl, and isBusinessSeller. Fields absent from the captured search page are returned as null; the Actor never guesses missing currency, condition, category, price type, or seller type.
Use cases
- Reseller and dealer sourcing: run saved searches for the used bikes or other stock you buy, then sort by
price,locationanddateto spot under-priced ads worth contacting first. - Market and price analysis: collect current asking prices for a product keyword, then track median asking price, ad volume and condition mix per category in a spreadsheet or database. These are asking prices, not sold prices.
- New-ad monitoring for agencies and teams: schedule the same search with
onlyNewSinceLastRun: trueand receive only listing IDs not previously delivered for that watch - feed them to Slack, email or a CRM via an Apify webhook. - Availability snapshots: save bounded search-page snapshots for category, location or product-availability analysis without crawling individual seller profiles.
Get Kijiji alerts in Discord, Telegram, Slack, Teams, Google Chat, your phone (ntfy/Pushover) or any app (webhook)
Want a Kijiji Discord alert, a Kijiji Telegram bot, or new listings pushed to Slack, Teams, Google Chat or your phone instead of checking a dataset? Add one or more destinations in the Actor's Notifications (optional) section and each run sends the listings it delivered. It is a monitor that notifies you: it only reads public Kijiji search pages and never contacts sellers, buys anything or logs in anywhere, and the messages go only to the places you set up.
| Channel | Fill in | What you get |
|---|---|---|
| Discord | discordWebhookUrl | One card per listing, 10 per message |
| Telegram | telegramBotToken + telegramChatId | Up to 10 listings per message, one line each |
| Slack | slackWebhookUrl | Block Kit message, up to 10 listings per message |
| Mattermost, Rocket.Chat | slackCompatibleWebhookUrl | Slack-style incoming webhook: a Markdown list (these apps do not render Slack Block Kit) |
| Microsoft Teams | teamsWebhookUrl | Adaptive Card from a Teams Workflows webhook, up to 10 listings per card |
| Google Chat | googleChatWebhookUrl | Card in a space, up to 10 listings per message |
| ntfy (phone push, no account) | ntfyTopic (optional ntfyServer, ntfyToken) | A push per listing, up to 10, then one "...and N more" |
| Pushover (phone push) | pushoverUserKey + pushoverAppToken | A push per listing, up to 10, then one "...and N more" |
| Any app: Zapier, Make, n8n, Pipedream, IFTTT, Home Assistant | webhookUrl | One JSON POST per run with the delivered rows |
Fill in as many as you like; each channel works on its own and a failing one never stops the others.
Setup, channel by channel
- Discord (1 minute): Server Settings → Integrations → Webhooks → New Webhook → pick the channel → Copy Webhook URL.
- Telegram (2 minutes): chat with @BotFather, send
/newbot, paste the token intotelegramBotToken. Add the bot to the chat or channel (administrator for a channel; for a chat with yourself press Start on the bot).telegramChatIdis a numeric id (123456789, or-1001234567890for a group or channel) or a public@channelusername. - Slack: at api.slack.com/apps create an app (From scratch) → Incoming Webhooks → switch it on → Add New Webhook to Workspace → pick the channel → copy the
https://hooks.slack.com/services/...URL. - Mattermost or Rocket.Chat: create an incoming webhook in the app and paste its public
https://URL intoslackCompatibleWebhookUrl. Localhost, private IP addresses and.local/.internalnames are rejected. - Microsoft Teams: in the channel open ... → Workflows → Post to a channel when a webhook request is received → finish the wizard and copy the URL (a host ending in
.logic.azure.comor.powerplatform.com). The old "Office 365 connector" webhooks are retired and not supported. - Google Chat: in the space open Apps & integrations → Webhooks → Add webhook, name it and copy the
https://chat.googleapis.com/v1/spaces/...URL (needs a Google Workspace account that allows webhooks). - ntfy (free, no account): install the ntfy app (or open ntfy.sh), subscribe to a topic with a long random name, and put the same name in
ntfyTopic. Anyone who knows the topic can read it, so make it unguessable. Own server or a protected topic: setntfyServer(publichttps://address) andntfyToken. - Pushover: copy your user key from pushover.net into
pushoverUserKey, create an application at pushover.net/apps/build and put its API token inpushoverAppToken. Pushover itself is a separate paid app after its trial: check their pricing. - Any app (webhook): paste the catch-hook URL from Zapier, Make, n8n, Pipedream, IFTTT or Home Assistant into
webhookUrl. It must be a publichttps://address.
The recipe: a Kijiji new-listing alert in five steps
- Set your search in
searchTerms(for examplebike) or paste a Kijiji search URL intostartUrls. - Turn on
onlyNewSinceLastRun, so only listings not delivered before are sent. - Add your destination(s) from the table above.
- Run it once. The first run is the baseline and sends what is currently listed (up to
maxNotifications). - Create a Schedule (for example every few hours). From then on you only hear about listings it has not delivered before for that search.
{"searchTerms": ["bike"],"onlyNewSinceLastRun": true,"maxItems": 100,"ntfyTopic": "your-long-random-topic-name","maxNotifications": 25}
The generic webhook (webhookUrl)
Each run sends one POST per 100 delivered rows (so usually one) with this body, followed by whatever your tool does with it:
{"source": "apify","actor": "kijiji-scraper","runId": "HG7ML7M8z78YcAPEB","count": 2,"total": 2,"part": 1,"parts": 1,"items": [ { "...": "the full dataset rows" } ]}
count is the number of rows in this POST, total the number in the run, and part / parts number the POSTs when a run delivers more than 100 rows. maxNotifications does not cap the webhook. Your endpoint should answer with a 2xx status; redirects are not followed and a failure is reported in the run status, never retried in a loop.
What to expect
- What a message contains: title, price, location, condition, whether the seller is a business or private (never a name), the listed date and a thumbnail, plus the link and the search term it matched.
- Only delivered listings are sent. A run that finds nothing new sends nothing, so there is no "no new listings" spam. Rows the run could not deliver (for example because your spending limit was reached) are not sent.
maxNotifications(default 25, max 100) caps how many listings go to chat and phone channels per run (the webhook is not capped). The rest are still in the dataset and the status message says so. ntfy and Pushover send at most 10 individual pushes, then one "...and N more" summary.- Cost: notifications are free. You pay only for delivered listings at the usual price, exactly as without alerts. There is no extra charge for any channel.
- Failures never fail the run. A deleted webhook or an unreachable service leaves the run successful and the dataset complete, and the status message says what happened, for example
Notified: Discord 12, Slack 12, ntfy 10 (+summary). Teams failed (HTTP 404) - check the webhook URL.The logs show the channel name and HTTP status only, never a URL or token. - Your URLs, tokens and ntfy topic are stored as secret inputs. Anyone holding a webhook URL can post to that channel, so treat it like a password.
- The dataset is unchanged. The output rows are identical whether or not you set a destination; the run's status message just gains a short note such as
Notified: Discord 12, ntfy 10 (+summary). - It is a monitor that notifies you. It never contacts sellers, buys anything or logs in to Kijiji, and the messages go only to the destinations you set up.
Pricing
Pricing: $0.0015 per delivered listing. Event: listing. Rows skipped by robots rules, blocks, duplicate alert history, or failures are not charged.
Notifications to Discord, Telegram, Slack, Teams, Google Chat, ntfy, Pushover and webhooks are free: you pay only for delivered listings, never for messages sent.
Fixture coverage
search-p1: 46 rows; search-p2: 46 rows. The parser uses only the page structures captured in test/fixtures/.
Limitations and responsible use
This Actor reads only public search-result data represented by the captured page fixtures. It does not log in, use proxies, rotate user agents, accept cookies to bypass access controls, solve CAPTCHAs, or crawl seller profiles/phone numbers. Search-page layout changes can require a parser update. Block/challenge responses are reported, not bypassed.
Use it from your code, Make, Zapier or n8n
Built for automated pipelines: small runs, stable field names, one row per item, and you pay only for rows actually delivered.
One API call that runs the Actor and returns the data (replace $APIFY_TOKEN with your token from Apify Console → Settings → Integrations):
curl -s -X POST "https://api.apify.com/v2/acts/lukehunter~kijiji-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"searchTerms": ["bike"], "maxPagesPerSearch": 1, "maxItems": 20}'
JavaScript (npm i apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('lukehunter~kijiji-scraper').call({"searchTerms": ["bike"],"maxPagesPerSearch": 1,"maxItems": 20});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python (pip install apify-client):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('lukehunter~kijiji-scraper').call(run_input={"searchTerms": ["bike"], "maxPagesPerSearch": 1, "maxItems": 20})items = client.dataset(run['defaultDatasetId']).list_items().items
Schedules, webhooks and no-code tools: save your input as a Task, add a Schedule (e.g. hourly or daily), and attach a webhook or one of the Integrations tab's connectors (Make, Zapier, n8n, Google Sheets, Slack) to push each run's results into your own system.
Only new items each run: set "onlyNewSinceLastRun": true on a scheduled Task and every run after the first delivers, and charges for, only items it hasn't delivered before for that same input. That makes it a ready-made change feed.
Reliability: an automated test runs this Actor's parser against the live site every day, and failures are fixed fast.
Feedback: an honest rating on the Store page, good or bad, helps others decide if this Actor fits their needs. Missing a field or found a problem? Open an issue on the Actor page.
FAQ
How much does it cost?
$0.0015 per delivered listing, so 100 listings cost $0.15 and 1,000 cost $1.50. There is no charge for starting a run, and rows skipped because of robots rules, blocks, duplicate alert history or failures are not charged. maxItems is a hard cap on the cost of any run.
How do I schedule it and get new-ad alerts?
Set onlyNewSinceLastRun: true, then click Schedule on the run page (or create a schedule under Schedules in the Apify Console). The first successful run is a baseline: it delivers and remembers its listings, and you are charged normally for it. Later runs deliver only listing IDs not seen before for that same search, and a run with nothing new succeeds with an empty dataset. Add a webhook for ACTOR.RUN.SUCCEEDED under the schedule's Integrations to forward new ads to Slack, email, Zapier or Make. Use stateStoreName only to isolate or reset a watch's memory.
What export formats and integrations are available?
Every run writes a standard Apify dataset, which you can download as JSON, CSV, Excel, XML or HTML, read through the Apify API and client libraries, or send to other tools with webhooks and integrations.
What is not collected?
No seller profiles, names, phone numbers or contact details, no login-only data, and no individual ad detail pages (full description and all photos) - only the fields on public search-result cards. Fields missing from a card are returned as null and never guessed (for example, currency is null whenever the search page does not state one). Listings are returned as published, including Kijiji's own category ID and condition codes.
Do I need proxies or an account?
No. The Actor needs no login, cookies, proxies or CAPTCHA solving. If a page is blocked, challenged or disallowed by robots.txt, it reports that honestly and stops that search instead of trying to get around it.
Can I get Kijiji alerts by email?
Not natively. There are two routes. (1) Set webhookUrl to a Zapier, Make or n8n catch hook and add an email or Gmail step: the webhook delivers the listings as JSON, so the email can list them. (2) Apify's own run integrations and run notifications can email you when a run finishes, but they only send a link to the run or dataset, not the listings themselves. For instant alerts without building anything, Telegram, ntfy or Pushover reach your phone directly.
Can I get Kijiji alerts in WhatsApp?
Not natively, and we do not use unofficial WhatsApp APIs, which risk getting your number banned. The official route is the WhatsApp Business Platform (Cloud API) with its own business account, message templates and pricing: point webhookUrl at a Zapier, Make or n8n flow that calls it. For free phone alerts use Telegram or ntfy instead.
More from this publisher
- Vinted Scraper — Vinted catalog listings and alerts.
- Vinted Cross-Country Prices — compare Vinted item prices across countries.
- Marktplaats Scraper — Marktplaats classifieds listings and alerts.
- Blocket Scraper — Blocket classifieds listings and alerts.