NVRValueBet
A platform that collects football odds from several bookmakers and an exchange, lines them up on the same match and the same market, and shows where a price drifts away from a low-margin reference. It does not place bets.
Private repository
01What it does
Every few minutes it collects prices from French and international bookmakers and from a betting exchange, and matches the same event across all of them. It removes the bookmaker margin from the reference prices to get fair odds, then compares the best French price with that reference. The result is a board of gaps, with each price marked as fresh or stale. It is a signal tool: nothing in it is wired to real money.
02What I built
A Python service on FastAPI with a background collector, one adapter per venue, and a layer that maps teams, competitions and markets onto one identity. The API serves a paged feed, filter facets, a match page, a board, a coverage report and an audit of suspicious data, plus a second surface shaped like a commercial odds API. In front of it sits a React Native app built with Expo and shipped as a web app, in English, French and Spanish.
03The hard parts
The same match is spelled differently on every venue, so identity does most of the work: aliases for teams and competitions, guards against mixing teams of different gender or squad, and one canonical id per venue. Collection runs on a budget per venue, with a circuit breaker that backs off after repeated failures, and matches close to kickoff are refreshed more often than distant ones. The audit flags duplicated events, impossible team pairs, incoherent kickoff times and outlier odds.
04How it runs
The API runs as a systemd service on a small Linux VPS, bound to the loopback interface. The web app is on Cloudflare Pages, a Pages Function forwards its calls through a tunnel, and one Cloudflare Access application guards both, so the API is never public. Prices live in SQLite, and the feed is served from a cache built once per collection cycle. GitHub Actions run the tests and ship each side on a push to main. The project began as a set of scrapers and spreadsheets where every step was a manual copy and paste, which I documented before rebuilding it as a service.
How it is built
- A viewer opens the board
- A collection cycle
- Fair odds and gaps
- A push to main
Client
Web today
Edge
Cloudflare
Backend
One Python service
Storage
Sources
Outside my control
Delivery
GitHub Actions to production
Select a part of the diagram to see what it does. Each color is one flow through the system.