Most people check Jiji or Amazon manually every day waiting for a price to drop. I built a Telegram bot that does it for you automatically and also lets you list and sell items directly from Telegram.
No website. No app. Just Telegram.
GitHub: https://github.com/Carter254g/price-alert-bot
What It Does
The bot has two sides.
For buyers: search for any product, set a target price, and get a Telegram alert the moment the price drops. It pulls real listings from Jiji Kenya and Google Shopping.
For sellers: list a product with a photo and description. Buyers can find it and contact you directly on Telegram.
The Architecture
The project is split into focused modules:
- scraper.py — extracts prices from any product URL using BeautifulSoup
- jiji.py — scrapes Jiji Kenya listings directly from their Nuxt data layer
- search.py — queries Google Shopping via SerpAPI for any product in any country
- telegram.py — sends price alert messages
- bot_handler.py — handles all Telegram commands and conversation flows
- scheduler.py — runs automatic price checks every 6 hours
- listings.py — stores and retrieves local marketplace listings
The Jiji Scraper
Jiji loads listings with JavaScript so a regular request returns empty content. The trick is that Jiji uses Nuxt.js which embeds all the page data in a JSON script tag:
match = re.search(r'id="__NUXT_DATA__"[^>]*>(.*?)</script>', res.text, re.DOTALL)
data = json.loads(match.group(1))
From there it is a matter of walking the data structure to extract titles, prices, locations and URLs. The result is real Jiji listings without needing a headless browser.
The Conversation Flow
python-telegram-bot has a ConversationHandler that manages multi-step flows. The browse flow looks like this:
browse_handler = ConversationHandler(
entry_points=[CommandHandler("browse", browse_start)],
states={
BROWSE_QUERY: [MessageHandler(filters.TEXT, browse_get_query)],
BROWSE_MIN_PRICE: [MessageHandler(filters.TEXT, browse_min_price)],
BROWSE_MAX_PRICE: [MessageHandler(filters.TEXT, browse_max_price)],
},
fallbacks=[CommandHandler("cancel", cancel)],
)
Each state waits for user input before moving to the next step. The user never has to type a command with arguments — the bot guides them through naturally.
Photo Support for Sellers
When a seller lists a product, they can send a photo. Telegram stores photos on their servers and gives back a file_id. That ID gets saved in the JSON config and later used to send the photo back to buyers:
if l.get("photo_id"):
await update.message.reply_photo(photo=l["photo_id"], caption=caption)
No image hosting needed. Telegram handles it all.
Automatic Price Monitoring
The scheduler runs every 6 hours using APScheduler. It checks all monitored URLs, compares current prices to targets, and fires Telegram alerts when a price drops:
scheduler.add_job(check_all, "interval", hours=interval_hours)
Start it once and forget about it.
What I Learned
Nuxt.js apps embed their data in script tags. Once you know where to look, scraping them is straightforward without needing Selenium or Playwright.
Telegram's ConversationHandler is powerful but stateful. You have to manage session data carefully when multiple users are in different states at the same time.
Always send long results as individual messages. Telegram has a 4096 character limit per message and one long block will crash the handler silently.
What Is Next
- WhatsApp integration
- More marketplace sources beyond Jiji
- Price history charts
- Web dashboard to manage listings
Top comments (0)