CigarBid Auction Monitor — Deal Scoring & Alerts
Overview
A price-intelligence tool for CigarBid, watching a user's own list of search terms across both auction formats the site runs. Classic lots are ascending-bid, so it captures the current winning bid, quick-buy price, units claimed against units available, close time and the full bid ladder. Free Fall lots descend in price instead, so every drop is recorded as a timestamped floor event — which is what lets the system learn how fast a cycle moves and where a given lot historically bottoms out. Every active lot is then scored 0–100 and tiered HOT / WATCH / SOFT / PASS, with alerts on anything above the threshold.
The engineering constraint shaped the whole design: it runs on a 512 MB VPS, and Chromium alongside Postgres does not fit in that. Postgres was dropped for embedded SQLite in WAL mode behind a custom async connection pool; Chromium runs single-process with a 128 MB JS heap cap and images blocked; scrape concurrency is pinned at one and the container is capped at 420 MB. CigarBid itself sits behind Cloudflare, so collection uses stealth automation, rotating user agents, human-cadence typing and randomised delays, with a block detector and retry when it still trips.
The scoring is deliberately unwilling to be confident before it has grounds. A lot with no confirmed closing history is capped at 70 and can never reach HOT; a benchmark built only from live floors caps at 60; Free Fall walks a four-phase gate from no data through one observed floor, then several, and only reaches the full range once real closes are on record. The timing model is built for a person, not a sniping bot — it peaks 1 to 6 hours before close, when the price has settled but there is still room to act, and drops to almost nothing inside the final 15 minutes.
Outcome
A single-user price-intelligence tool that turns an auction site with no price history into one with benchmarks, surfacing lots trading below their own historical closes — and doing it inside a 512 MB VPS, which is what forced the SQLite-over-Postgres and single-process-Chromium design the rest of the system is built around.
Screens & Demos
Architecture & Pipeline
-
01
Watchlist
User-defined search terms
-
02
Stealth Browser
Playwright · anti-bot bypass
- Playwright
-
03
Classic Lots
Bid ladder · units · close time
-
04
Free Fall Lots
Timestamped price drops
-
05
SQLite (WAL)
11 tables · async pool
- SQLite
-
06
Closed-Lot History
Benchmarks from real closes
-
07
Scoring Engine
Price · competition · timing
-
08
Confidence Gate
Caps score until history exists
-
09
Tiering
HOT · WATCH · SOFT · PASS
-
10
Alerts & Dashboard
Email · Discord · Flask
- Flask
End-to-end flow, in order. Scroll sideways on a narrow screen.
Key Features
- Runs in 512 MB of RAM — SQLite in WAL mode replacing Postgres, single-process Chromium with a 128 MB heap cap, concurrency pinned at 1, container capped at 420 MB
- Cloudflare handling: stealth automation, rotating user agents, human-cadence typing (50–150 ms per keystroke), randomised step delays and a block detector with retry
- Both auction formats: ascending Classic lots with their full bid ladder, and descending Free Fall lots tracked drop by drop
- Timestamped floor events per Free Fall lot, learning cycle speed and where a lot historically bottoms out
- 0–100 deal score tiered HOT / WATCH / SOFT / PASS, with a configurable alert threshold
- Classic scoring: 50% price against the historical midpoint of past winning bids, 30% competition, 20% timing
- Competition weighting halves when two or fewer units remain, and switches to outbid value once a lot is fully claimed
- Free Fall scoring: 65% gap against the expected floor, 35% urgency blended from time left and observed drop cadence
- FLOOR_IMMINENT, ALL_TIME_LOW and FINAL_CYCLE flags on Free Fall lots
- Confidence gating — no confirmed close history caps a lot at 70, live-floor-only benchmarks cap at 60, so nothing reaches HOT on thin evidence
- Timing model built for a human in the loop: peaks 1–6 hours before close, near-zero inside the final 15 minutes
- Five independent services under supervisor loops, each restarting on crash without taking the others down
- Three scrape cadences: watchlist search every 120 minutes, live bids every 30, rescoring every 30
- Fuzzy matching of listings to watchlist terms at a 98% threshold
- Flask dashboard: watchlist management, separate Classic and Free Fall deal views, per-product bid history, live time-to-close, scraper status, log viewer
- Alerts by email with a Resend → Brevo → SMTP fallback chain, plus Discord webhooks, every attempt logged
- One-shot Docker deploy script that rebuilds, rolls the stack, health-checks the dashboard and preserves the SQLite volume