Product safety recall intelligence, built entirely on free, keyless, CORS-enabled government APIs. No backend, no build step, no accounts, no tracking — it deploys as static files.
index.html |
Marketing site. Positioning, comparison, pricing, stated limits. |
check.html |
Free tier. One search box: car, medicine, food, home & kids, medical devices. |
app.html |
Console. Radar, register, actions, scanner, feed, compliance records. Licence-gated. |
BUSINESS_PLAN.md |
Competitive research, positioning, roadmap, risks. |
assets/ |
engine.js (sources + geo + cache), inventory.js (register + evidence), radar.js, scanner.js, app.js, app.css |
python3 -m http.server 4711 --directory .
# marketing → http://localhost:4711
# free check → http://localhost:4711/check.html
# console (demo) → http://localhost:4711/app.html?demo=1The camera scanner needs a secure context — localhost works, but a deployed
copy must be served over https://.
Every request goes from the user's browser straight to the issuing agency. Nothing is proxied, logged, or stored on a server.
| Source | Coverage | Images | Barcodes | In live feed |
|---|---|---|---|---|
| EU Safety Gate (RAPEX) via Opendatasoft | 31 European countries, 32k+ alerts | 100% | ~45% | yes |
| CPSC | US consumer products | 100% | sparse | yes |
| openFDA food / drug / device | US | none | in text | yes |
| NHTSA + vPIC VIN decode | US vehicles | none | n/a | no — see below |
| Open Food Facts | global barcode → product | yes | n/a | lookup only |
1. Two clocks, never conflated. Every alert carries the date the agency published it and the timestamp when Radar first saw it. Those are different numbers and both are shown, because a recall downloaded today may have been issued months ago.
2. A first sighting is not automatically a live detection. Two independent
guards, both in engine.js / app.js:
- First run. On a fresh browser every record is unseen by definition. Flagging
400 historical alerts as breaking news would be a lie, so the first sync is
marked
backfilland never flashes the map. - Recency.
LIVE_WINDOW_DAYS = 21. Anything the agency published before that window is something we merely hadn't downloaded yet — stored as history, no flash, no notification.
3. Deterministic paging. RAPEX publishes in weekly batches, so dozens of
alerts share one alert_date (42 on a single date at time of writing). Ordering
on date alone leaves ties unsorted, and when the limit boundary falls inside a
tie group each call returns a different slice — which made unchanged records look
brand new. The query now sorts on alert_date DESC, alert_number DESC;
alert_number is unique, so the order is pinned.
Point the camera at a whole cart. BarcodeDetector returns every barcode in the
frame with a bounding box, so each one gets its own outline drawn in place:
| Verdict | Meaning |
|---|---|
| 🔴 RECALLED | The scanned digits exactly match a barcode published on a recall notice. Definitive. |
| 🟠 POSSIBLE MATCH | The product's name matched a recall. Two products can share a description — check your batch. |
| 🟢 NO RECALL FOUND | Resolved to a real product, nothing matched. |
| ⚪ UNKNOWN | Not in any product database. Deliberately not green. |
It reads barcodes, not products. It cannot identify an item from its shape or packaging. An item whose barcode faces away from the lens is simply not assessed, and the UI says so rather than implying a clean bill of health.
Requires Chrome or Edge (Android, Windows, macOS). Safari and Firefox don't ship
BarcodeDetector; the app detects this and says so instead of failing silently.
openFDA allows 1,000 requests/day per IP without an API key (120,000/day with a free key). Each register item costs 3 openFDA calls, so a 500-item compliance run is 1,500 calls — over the free quota, and users behind one NAT share it. An API key shipped in client-side JS is public and its quota can be burned by anyone.
engine.js mitigates this with a 15-minute response cache and optional operator-supplied
key (Config.set({fdaKey})), but the paid tier genuinely needs a server that holds the
keys and caches a normalised index on everyone's behalf. That shared index is also the
defensible asset — the feeds themselves are public and are not a moat.
app.html ships a licence gate: keys are RR-XXXXX-XXXXX-CCCC, where CCCC is
an FNV-1a checksum of the rest, so random strings are rejected. Mint keys from the
console:
RecallRadar.mintKey("customer-001") // → "RR-HWP45-JBQR6-7N46"Be clear-eyed about what this is. Every byte of this app is on the client, so anyone who opens devtools can set the localStorage flag and walk in. A browser-only gate keeps honest customers honest and nothing more.
Real enforcement needs the data path to run through a server you control:
- Move the five
poll()calls inengine.jsbehind your own endpoint. - Have that endpoint verify the licence key (against Stripe, Lemon Squeezy, or your own table) before returning any alert JSON.
- Keep the client rendering exactly as it is — it never needs to know how the data arrived.
That is a genuine change in architecture, not a config flag. Until it's done, treat the gate as a speed bump.
- "Live" means polled, not streamed. No agency publishes a realtime firehose. CPSC posts most days, openFDA weekly, EU Safety Gate every Friday. The console re-checks all five every five minutes.
- Vehicles are absent from the live map. NHTSA offers lookup by year/make/model but publishes no "recently issued" endpoint. Cars are fully searchable; they cannot appear in a feed. There is no way around this short of scraping.
- Vehicle results are per year/make/model, not per VIN. A previous owner may already have had a listed recall repaired. The UI says so and links to NHTSA's own free VIN lookup.
- Blips are country- and US-state-level. That is the resolution agencies publish. Nothing is jittered to look more precise than the data is.
- Coverage is the US and Europe. Those are the jurisdictions with open recall APIs. Asia, Latin America and Africa appear as countries of origin only.
- USDA meat and poultry recalls are missing. The FSIS API returns 403 to every non-browser client, UA spoofing included. Excluded rather than shipped broken; the footer points users to fsis.usda.gov/recalls.
- Text matching is imperfect. FDA records are free text, so a product described differently than you searched can be missed.
- Storage is
localStorage, capped at 900 events. A deployment tracking more history wants IndexedDB or a server.
Recall Radar is not affiliated with any government agency. Always confirm on the official notice before acting.
If this is useful to you, a ⭐ on the repo helps other people find it. Issues and pull requests are welcome.
Built by Priyankar "Sunny" Chakraborty · everbuiltstudio.com
