|
Point the camera at an ingredient list or a barcode. An AI reader transcribes it, and on-device OCR takes over when there's no signal or no key. |
Every ingredient is looked up in the EU additives database, FDA's Substances Added to Food, IARC, California's Prop 65, and the FSSAI and Codex oil standards, all mirrored daily. |
|
Bans, pending bans, warning labels and hazard listings, by jurisdiction. Each carries its regulation, a link and the date the list was last checked. |
Line up one product's labels from two markets and see exactly what differs. Lay's in India listed palmolein where the US label listed sunflower, corn or canola oil. |
|
A 0–100 score where points come off only for bans, warnings and hazard listings on record. It is withheld when too little of the label has been checked, so an additive nobody has researched never reads as "fine". |
|
Four layers, stored apart on purpose:
| Layer | Schema | What it holds |
|---|---|---|
| 1 | product |
Products from Open Food Facts (ODbL) |
| 2 | canon |
One entity per ingredient, with every name it goes by, in several languages |
| 3 | evidence |
Regulatory status, hazard findings, composition and the mirrored official lists, every row cited |
| 4 | verdict |
Scores, claims and cross-market comparisons |
Two rules hold the design together:
| Rule | How it is enforced |
|---|---|
| Open Food Facts data is never merged with Verso's own data on disk. | The two sides are joined at request time. pnpm lint:layers checks the migrations and the live database for any foreign key, view or materialized view that crosses the boundary. |
| A model never decides what differs between two products. | Differences are computed in code after both lists go through the canon. Every sentence comes from a template, and a claim without a citation can't be inserted: citation_id is NOT NULL. |
The reasoning in full: methodology · claim templates · build plan.
| Source | What Verso reads | Entries |
|---|---|---|
| EU Food Additives Database | Authorised additives and their conditions of use (Regulation (EC) No 1333/2008) | 412 |
| FDA Substances Added to Food | Regulated uses by 21 CFR section; Part 189 prohibitions | 3,971 |
| IARC Monographs, List of Classifications | Carcinogen classifications, Groups 1–3 | 1,128 |
| California Proposition 65 list | Chemicals listed for cancer or reproductive toxicity | 990 |
| FSSAI regulation 2.2.1 | India's standards for edible oils | 32 |
| Codex CXS 210-1999 | International standards for named vegetable oils | 24 |
pnpm sources:sync downloads each list, records every added, changed or removed
entry, and refuses a download that shrinks a list by more than a fifth. With
VERSO_SOURCE_SYNC=daily the API re-runs it once a day.
You need Node 22.13+, pnpm 11, Docker, and poppler (brew install poppler)
for the two PDF standards.
pnpm install
cp .env.example .env # add an AI reader key if you want photo reading
pnpm db:up && pnpm migrate && pnpm seed
pnpm sources:sync # download the official lists
pnpm api # API on http://127.0.0.1:4310Then try the app in a browser:
pnpm --filter @verso/mobile webDevelopment builds show test labels on the Scan tab. They run through the
real API and canon and skip only the camera. Before sending a change, run
pnpm check (layer lint, tests and the phase 0 criteria).
Run it on a phone
pnpm dev brings up Postgres, the API and Metro on the Mac's Bonjour name, so a
phone on the same network (or USB) can reach them. Then install a development
build:
pnpm --filter @verso/mobile ios # or: androidThe camera and on-device OCR need a development build, not Expo Go.
Configuration
| Variable | Purpose |
|---|---|
DATABASE_URL |
Postgres connection. The default matches docker-compose.yml (local development only). |
VERSO_OCR_PROVIDER |
Who reads label photos: gemini, anthropic, opencode, or openai for any OpenAI-compatible endpoint, a local model included |
GEMINI_API_KEY, ANTHROPIC_API_KEY, VERSO_OCR_API_KEY |
The key for that provider. Keys belong in .env, which git ignores. With none set, the phone reads labels on the device. |
VERSO_SOURCE_SYNC |
daily to re-download the official lists from the API process |
.env.example documents every option.
Project layout
apps/mobile Expo app: guided capture, offline cache, verdict and compare screens
services/api Fastify API: /v1/verdict, /v1/compare, /v1/ocr, /v1/sources, …
packages/db migrations, one file per layer
packages/canon ingredient canon: seeder, resolver, on-demand identification
packages/evidence curated evidence; sources/ parses the official lists, sync.js mirrors them
packages/verdict score.js, templates.js, build.js, compare.js
packages/shared label-text normaliser and the product_ref boundary
data/canon ingredient and synonym source of truth (JSON)
data/evidence regulatory, hazard, composition and contaminant findings (JSON, every row cited)
tools/ layer lint, source sync, Open Food Facts ingest, dev stack, demos
docs/ plan, methodology, claim templates, brand
- The API has no authentication. It is built for local development; don't expose
it to the internet as is, because
/v1/ocrspends your AI provider's quota. - Label photos, and the names of ingredients Verso hasn't seen before, go only to the AI provider you configure. With none configured, labels are read on the device.
- Please report vulnerabilities privately through GitHub security advisories, not in a public issue.
Note
Verso does not produce the regulatory or hazard information it shows. Each item is published by the official source linked beside it, a regulator, a WHO agency or a court, and is dated by when that source was last checked. Verso can't guarantee it. It is not medical, nutritional or legal advice.
- Code: MIT.
- Curated data in
data/canon/anddata/evidence/: CC BY-NC 4.0. Free for non-commercial use with attribution; ask about commercial use. - Third-party material keeps its own terms: quotations from regulators inside
data/evidence/, the EU additives data behinddata/canon/eu-additives.generated.json, the downloaded official lists, and Open Food Facts data (ODbL), which is fetched at runtime and is not in this repository.
Built by Aniket Shukla.
