DEV Community

Ibrahim Awab
Ibrahim Awab

Posted on Edited on AI-assisted

pricecheck: my friend didn't know what to offer for a used monitor, so now he gets three numbers

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I Built

A friend of mine in Islamabad needs a monitor. He told me what he wanted like this:

"I want a 27 inch monitor… has to be obviously a reputable brand, I don't know much about monitors tho… like 27 inch IPS, budget maybe around 35k."

Then he said the part that actually turned into a project:

"Don't know how to bargain too. If I had some frame of reference, like someone put a monitor at 55k and I can bring it down to 35k, that would be easy for me. So that's an issue, that I don't know how much I can haggle, plus I don't know much about monitors."

My friend's problem: he doesn't know how much he can haggle

In Pakistan, used electronics mostly change hands on OLX. Every listing is an asking price, and every buyer is expected to bargain. If you don't know what similar monitors usually go for, you either overpay or you insult the seller with a lowball and lose the deal. My friend's problem wasn't "which monitor is best". It was "what number do I say out loud".

So I built pricecheck. You paste an OLX link (or browse a category with filters), and it tells you:

  • what similar listings usually ask, as a range, not one number
  • a verdict: good deal, fair, overpriced, suspiciously cheap, or hard to judge
  • three numbers to use when you bargain: open your offer at, a fair deal is, most you should pay
  • the similar listings it compared against, what it read from the listing, what to check in person, and what Pakistani shops charge for the same model new

It runs on my own PC with open models. Gemma 4 E4B reads the listings locally through Ollama on a GTX 1660 Super. TabPFN predicts the price range. Plain Python decides the advice.

Who would pay for it: anyone buying used electronics on OLX who doesn't bargain for a living, like my friend. It's also useful to people who resell: the same range tells a seller whether they're asking more than similar listings.

Demo

Live site (browse 500+ priced monitors, no setup): https://pricecheck-gamma.vercel.app

What the recording shows, step by step:

1. My friend's filters. 27", IPS, Islamabad, budget 35,000, plus "include ones I could bargain down to it". One listing matches: an ASUS PB278Q (27", 1440p, IPS) asking Rs 40,000, which pricecheck marks overpriced, 24% above usual.

Browsing with my friend's filters: 27 inch, IPS, Islamabad, 35k budget

2. The bargaining panel. Half of similar listings ask between Rs 26,583 and Rs 39,679, so it says: open at Rs 24,500, a fair deal is Rs 26,500 to 32,000, and don't go above Rs 39,500. Below that: what Gemma read from the listing, what to check in person, and the similar listings it compared against.

The bargaining panel for the ASUS PB278Q

3. A listing that is not in my data. A Dell SE2717HX (27", IPS, 75 Hz) went up on OLX today for Rs 20,500. I paste the link on the local page and it checks it on the spot: fetches the listing, Gemma reads it, TabPFN prices it against 510 others, code writes the advice.

Pasting a brand-new OLX link and checking it live

Verdict: good deal, 29% below usual. Similar listings ask Rs 24,078 to 34,490. Open at Rs 19,000, and don't pay more than the asking price.

Live result for the Dell SE2717HX

4. The Sentry trace of a live check of that same listing (in How I Built It below).

That Dell is exactly what my friend described, inside his budget, with room to spare. It's in Lahore, not Islamabad, which is the kind of thing he still has to decide himself.

Code

GitHub logo miawab / pricecheck

Is this OLX price fair? Gemma reads listings, TabPFN prices them, all on your own PC.

pricecheck

Is this OLX price fair? Paste an OLX link or browse a category, and see what similar listings usually ask, whether this one is a good deal, and what to offer when you bargain.

Everything runs on your own computer with open models:

  • Gemma (Google's open-weight model, run locally with Ollama) reads each messy listing ("27 inch ips lush condition 10/10 box available") into clean columns.
  • TabPFN (Prior Labs' tabular model, also local) learns from all the other listings what a similar item usually costs, and gives a price range.
  • Plain code turns that range into advice: open at, fair deal, most you should pay. The models supply facts; code decides.

Nothing runs in the background. Data only changes when you run the update yourself.

What you need

  • A Windows, Mac or Linux PC. An NVIDIA GPU with 6 GB+ makes Gemma fast (a few seconds per listing)…

The live site is static, so anyone can browse the priced listings. To check brand-new links like in the demo, run it locally: the README walks through installing Ollama, pulling Gemma, getting a free TabPFN key, and python -m pricecheck.doctor tells you what's missing.

How I Built It

How a check works: OLX listing, Gemma reads it, TabPFN prices it, plain code decides the advice

1. Collect. pricecheck reads OLX's public monitor category: one page every 2 seconds, nothing behind a login. Phone numbers are stripped from titles and descriptions before anything is saved (933 of them had one), and seller names are never stored. On Oct 14 that gave 1,180 listings.

2. Gemma reads each listing, once. OLX listings look like "27 inch ips lush condition 10/10 box available urgent sale". Gemma 4 E4B turns that into columns: brand, model, size, panel, resolution, refresh rate, condition, whether it has a fault, whether the box is included. It runs locally through Ollama, so there's no API bill per listing, and each listing is only read once. 643 listings have been read so far.

3. TabPFN prices each listing from the others. TabPFN is Prior Labs' foundation model for tables: you give it rows with known prices and it predicts prices for new rows, with no training loop on my side. I ask it for the 25th, 50th and 75th percentile, so every listing gets a "usual range", not a single guess. When pricing the whole dataset I use 5 folds, so a listing's own price is never in the rows used to price it.

4. Plain code turns the range into advice. This is the bit I was most careful about. The models supply facts; code decides what to tell a person who is about to spend their money:

def advice(price, q25, q50, q75):
    """Turn a price range into what to do. Code decides; the model only supplied the range."""
    gap = price / q50 - 1
    if q75 / q25 > 2.2:
        verdict, say = "unsure", "Similar listings vary too much in price to judge this one. ..."
    elif price < q25 * 0.6:
        verdict, say = "too_cheap", "Far below similar listings. Check carefully in person: ..."
    elif price <= q25:
        verdict, say = "good_deal", "Cheaper than most similar listings. ..."
    elif price <= q75:
        verdict, say = "fair", "In the usual range. There's some room to bargain."
    else:
        verdict, say = "overpriced", "Above the usual range. Bargain hard or ..."
    target_low, target_high = min(price, q25), min(price, q50)
    return {
        "open_at": round500(min(price, q25) * 0.92),
        "fair_from": round500(target_low),
        "fair_to": round500(target_high),
        "max_pay": round500(min(price, q75)),  # never more than they ask, never above the usual range
        ...
    }
Enter fullscreen mode Exit fullscreen mode

Two rules matter most. It will never tell you to pay more than the seller asked. And if similar listings are spread too wide to judge, it says "hard to judge" instead of inventing confidence.

5. SerpApi checks what shops charge. For listings with a clear model name, pricecheck searches Google Shopping through SerpApi for Pakistani shops selling the same model new (OLX and Facebook results excluded). It only shows one number when the shops roughly agree; otherwise it shows the range and links. Found for 45 listings so far, 19 where shops agree, using 35 searches.

6. Sentry traces every check as an agent run. Each live check is an invoke_agent span, with a chat gemma span for the read and tool spans for fetch_olx_listing, tabpfn_price_range, bargain_advice and serpapi_new_price. Here is the trace of a live check of the Dell from the demo:

Sentry trace of one live check

The whole check took 19.04 s: OLX fetch 1.06 s, Gemma 5.18 s, TabPFN 10.88 s, the advice itself 6.56 ms, SerpApi 1.84 s. That breakdown is how I know where time actually goes. Without it I would have guessed Gemma was the slow part. It isn't any more; TabPFN is.

7. Any OLX category. Monitors is one "recipe", a small TOML file listing where to collect from and which fields matter. python -m pricecheck.new_recipe phones "<OLX link>" lets Gemma draft a new recipe from real listings, which you then read and fix by hand. Nothing runs on a schedule; prices only update when you run the update yourself.

Results

I wanted to know if TabPFN was actually earning its place, so I compared it with simpler ways to price the same listings. python -m pricecheck.evaluate monitors prices all 510 single-monitor listings, each one without seeing its own price:

Method Typical error Within 15% of asking price
Same-specs median (what a person would do by hand) 28.6% 26.3%
Gradient boosting 22.4% 35.3%
TabPFN 19.2% 39.6%

Typical pricing error: same-specs median 28.6%, gradient boosting 22.4%, TabPFN 19.2%

TabPFN's "usual range" contained the real asking price 51% of the time. A 25th-75th percentile range should hold about half of prices, so 51% means the ranges are honest: not too narrow to look confident, not too wide to be useless. On an earlier test with only 27" monitors, TabPFN's typical error was 22% against 35% for the simple rule.

19% typical error sounds large until you remember what it's predicting: asking prices, which are already noisy. Sellers price the same model very differently, and some never expect to get what they ask. The goal isn't to guess the exact number. It's to give someone a frame of reference, which is the phrase my friend used.

Why Does Open Innovation Matter?

For a price checker, the economics decide whether it can exist at all. A check has to cost close to nothing, because nobody pays much to be told what to offer for a 20,000-rupee monitor.

  • No bill per listing. Gemma read 643 listings on my own 6 GB GPU, and each update only reads the new ones. TabPFN runs on my CPU. The only outside calls are SerpApi for shop prices (35 searches so far, inside the free tier) and Sentry for traces (free tier). Re-reading the whole category costs electricity, not tokens.
  • I could change how the model behaves. Gemma 4's thinking mode was making each listing take about 20 seconds. Because I run it myself, I turned it off and forced its answer into a fixed JSON schema, which brought it down to 5-7 seconds and gave me the "has a fault" field that fixed the broken-monitor mistake.
  • Swapping models is one setting. On a weaker PC, PRICECHECK_MODEL=gemma4:e2b-it-qat switches to the smaller Gemma. Nothing else changes.
  • No listing goes to a model provider. The only things that leave my PC are the shop-price searches and the Sentry traces. The listings are public, but I still strip phone numbers before saving anything.

I didn't benchmark a closed API against this, so I can't claim it would be less accurate. The win is that running it costs me nothing per check and I control every step, which is what makes it something a person could actually sell.

My First User

My friend tried it before I wrote any of this. His reaction:

"W, this is nice. Does this take into account how old a model is? Good though, very helpful."

His question is a good one, and the honest answer is: partly. pricecheck uses how long a listing has been up, its condition, and its specs (refresh rate, resolution, panel type), and those track a model's generation fairly well. But it does not know a model's release year. A Dell P2719H from 2018 and a P2725H from 2024 are both "27-inch 1080p IPS Dell" to it, and they shouldn't be priced the same. That's the first thing I'd add next.

I also asked him straight out whether he would pay for it. His answer:

"lol if i had the money yeah. but yeah def a lot of ppl would"

Fair point: a student hunting for a 35k monitor has little to spare. My guess is that the paying users are people with more at stake per purchase, like resellers checking what to ask for their stock, but I haven't tested that yet.

He hasn't contacted a seller or bought anything yet, so I can't tell you how the bargaining went. If he buys one before the deadline, I'll add what happened.

What I'd charge

My friend's answer shaped this. Buyers like him are students with little to spare, so checking a listing stays free. One check costs me a few seconds of my own GPU and CPU, so a few free checks a day per person costs close to nothing.

The paid plan is for resellers, people who buy and sell used monitors and phones on OLX every week. For them the numbers are bigger. In the demo, the ASUS listing asks Rs 40,000 and pricecheck says a fair deal is Rs 26,500 to 32,000. A reseller who gets that one wrong loses more than a month's subscription. What I'd sell them, for Rs 1,000 a month (about $3.50):

  • unlimited checks
  • their own listings compared with the usual range, so they know when they're asking too much to sell, or too little
  • a message when a new listing in their category goes up well below the usual range

The first two already work. The third is the update I already run, plus a message. I haven't asked a reseller to pay yet, so this is a plan, not a result. The next step is to show it to a few resellers in Islamabad and ask.

What went wrong

  • Gemma marked working monitors as broken. My first schema had one field mixing "what kind of listing is this" with "is something wrong with it". Splitting it into a listing type and a separate "has a fault" field fixed it.
  • It was slow at first: about 20 s per listing. Turning off Gemma 4's thinking mode and using short JSON keys brought it to 5-7 s.
  • Some answers stopped mid-JSON. Those are now retried, and Sentry flags them so I can see how often it happens.
  • The first prices were nonsense for rare items. A 27" 4K monitor "usually" cost 79k to 398k, because a few Apple displays stretched the range. I fixed it three ways: size is required, wildly-off prices are kept out of training, and the "hard to judge" verdict exists for exactly this case.
  • Sellers mislabel brands. One Koorui monitor was listed under the brand "1st Player". Gemma now reads the brand from the title and description instead of trusting OLX's brand field.
  • A cold model is very slow. Sentry's first trace showed one check taking 1.84 minutes because Gemma wasn't loaded on the GPU yet. Warm, the Gemma step is about 5 s.
  • Shop prices from Google are noisy. One Lenovo model was 34k at one shop and 97k at another. That's why the page only shows a single shop price when shops agree.
  • My GPU ran hot. Under load it sat at 88-91 °C with the fan reading 0%. I stopped Gemma with 562 listings still unread rather than push it. Those listings are collected but not priced on the site.

What it can't do

  • OLX only shows asking prices, never sold prices. pricecheck tells you what sellers ask, not what buyers paid. Listings that disappear are kept as the closest thing to a sale price, but that's an estimate.
  • It doesn't know a model's age (my friend's question above).
  • It can't see the monitor. Dead pixels, backlight bleed and broken ports only show up in person, so every listing gets a short "check this in person" list instead.
  • It's monitors only, for now. The recipe system works for other categories, but I've only tested monitors properly.

Prize Categories

  • TabPFN: TabPFN is the decision core of the agent. It produces the 25th/50th/75th percentile price range for every listing (5-fold so no listing sees its own price), beats a same-specs median and gradient boosting on 510 real listings (19.2% vs 28.6% and 22.4% typical error), and its range holds the real price 51% of the time. Code turns that range into the bargaining advice.
  • Gemma: Gemma 4 E4B runs locally through Ollama on a 6 GB GPU. It reads every messy OLX listing into structured specs, reads brand-new links live during a check, and drafts recipes for new OLX categories.
  • Sentry (Agent Tracing): every live check is traced as an invoke_agent span with a chat gemma span and four tool spans; the trace screenshot above is from a live check of the Dell listing in the demo. Tracing is how I found the 1.84-minute cold start and that TabPFN, not Gemma, is now the slow step.
  • SerpApi: Google Shopping results through SerpApi give the new-from-shop price for the same model, so a buyer can see when a used listing costs nearly as much as a new one.

Top comments (2)

Collapse
 
arqamwd profile image
Arqam Waheed •

Cool!

Collapse
 
miawab profile image
Ibrahim Awab •

thanks