IT.
← All work

Classifieds Aggregator

bazito

A board for people relocating: it reads hundreds of open Telegram channels in over a dozen countries, parses price, period and currency with rules, strips personal contacts, and shows it all on one board with a median for every selection.

380+
Telegram channels read
19+
countries on the board
5
sections: housing, transport, goods, jobs, services

The problem

Relocation classifieds are scattered across hundreds of Telegram channels and chats, one per city and topic. In a typical rental chat only one message in five to ten is a listing; the rest is questions and thank-yous. One agent posts the same flat to ten chats, and currency alone turns up in 81 spellings across the corpus.

What I did

I architected it as a pipeline on a small VPS. Open channels are read over plain HTTP with no Telegram account, chats over MTProto. Every post is deduplicated by its normalised text, passed through a cheap prefilter, parsed by rules into strict JSON, sanity-checked, merged with the same object from other channels and stripped of contacts. The board is a static PWA on Vercel reading from Supabase. A model annotates verticals in batches, and the live loop runs without a key to any external model.

Engineering decisions

  1. 01

    Money stays with the rules

    Price, period and currency are parsed deterministically, because that is exactly where a model's mistake is visible to the reader. Every fix to those rules runs against the whole corpus first: a candidate sample plus a random control of about 8,000 posts that must not change at all. The parking fix changed 62 of 3,409 candidates, every one of them parking read as rent, and nothing in the control.

  2. 02

    One flat, one card

    A post blasted across ten chats is normalised and hashed before parsing, so ten copies cost one parse. The same flat described differently in different channels is merged by a fingerprint of region, district, bedrooms, price and area. Once the fingerprint learned regions, cards mixing two countries dropped to zero and the largest merged group went from 973 posts to 239.

  3. 03

    A model where meaning matters, checked twice

    A service almost never calls itself a service, so rules alone caught only about a fifth of jobs and services. Verticals are annotated by Claude Code subagents in batches of 200 posts. Two independent annotations of the same 286 posts agreed on 98.6%, and annotating everything the candidate net rejected put its real recall at 78%.

  4. 04

    Contacts never reach the board

    Phone numbers, handles and links to personal profiles are stripped in the pipeline before the board. The button on a card leads to the source channel instead, so the author gets the reply where they posted. The analytics counter does not load until the visitor answers the cookie question.

Screens

Outcome

Live at bazito.app in Russian and English: housing, transport, goods, jobs and services from hundreds of channels in over a dozen countries, a median for every selection and every district, rent guides computed from live listings, and three pieces in the Writing section on how it is built.

Built with

  • Python
  • httpx
  • BeautifulSoup
  • Telethon (MTProto)
  • SQLite
  • Supabase
  • Vercel (static PWA)
  • Claude Code subagents