Up next.
Concrete, scoped, and worth doing in the next session or two.
Up next
Friends test outreach
The launch-kit playbook is ready, no friends contacted yet. The single highest-value move on this list — every feature past this point improves a product no stranger has touched.
Effort: ~15 min to draft, hours of conversation to learn from
Up next
Claim social handles
@kindlychecked on Instagram, X, TikTok, Bluesky. Brand insurance — claiming costs nothing now, costs everything later if someone else grabs them first.
Effort: ~10 min
Up next
Submit to Google Search Console
Get the site crawlable and indexed. Won't drive traffic for weeks, but starts the clock.
Effort: ~5 min
Up next
Real-device polish pass
Open the app on a phone, scan real groceries, write down anything weird. Laptop testing has limits — actual phones surface UX issues you can't see in dev tools.
Effort: ~30 min
Soon-ish.
Worth building once we have early-user signal to inform the design.
Soon-ish
Deepen use of what Open Food Facts already gives us
We currently use maybe 30% of what OFF exposes per product. An audit of a rich product entry surfaced a dozen high-value fields we're leaving on the table — most of which strengthen our info-advocate positioning without requiring new data sources. In priority order:
NOVA ultra-processed classification. Shipped v1.6.6. Every food result includes NOVA Group 1-4 with tap-to-expand showing what NOVA means, the specific ingredient markers, and an evidence pill. Also folded into the plain-language takeaway when Group 4.
Nutri-Score component breakdown. OFF exposes not just the letter grade but the raw points — "Sugar 1/15", "Fiber 5/5", "Salt 5/20", etc. Perfect for the "how did we get this score" transparency work already on the wishlist. Complements v1.6.0's plain-language takeaway.
Serving size + per-serving nutrition. Actually already shipped — the "Per serving / Per 100g" toggle at the top of the nutrition section defaults to per-serving on any product with a serving size defined. Turned up in the audit for this wishlist item after the fact. Left here as honest correction.
Category comparison. "Compared to Wholemeal sliced breads: +32% fiber, -13% sugar." OFF computes this automatically. Deeply useful shopping context.
Nutrient level qualifiers. Shipped v1.6.7. Small Low / Moderate / High badges under the Sugar, Sat fat, and Salt cells — sourced from OFF's nutrient_levels_tags, which uses NHS/WHO reference values. Answers "is 1.1g of salt actually a lot?" without the user needing to know reference ranges.
Per-ingredient percentages. "Whole wheat flour 39.3%, water 30.4%..." Deep ingredient transparency — helps shoppers understand what they're really eating.
Vegan / vegetarian / palm oil flags. Automated from ingredients taxonomy. Useful for a real subset of US shoppers with dietary preferences.
Common name and taxonomy hierarchy. Would improve alternatives matching quality (we're currently matching on brand + one category level; OFF has 5-level taxonomies).
Positive labels — "No added sugar", "High fibre", USDA-organic. Would need filtering to US-relevant labels (EU-organic doesn't help US shoppers).
Data completeness indicator. OFF marks pages as complete/incomplete. Displaying this respects the user's ability to judge how much weight to give the info — matches our honest voice.
NOVA ultra-processed classification. Shipped v1.6.6. Every food result includes NOVA Group 1-4 with tap-to-expand showing what NOVA means, the specific ingredient markers, and an evidence pill. Also folded into the plain-language takeaway when Group 4.
Nutri-Score component breakdown. OFF exposes not just the letter grade but the raw points — "Sugar 1/15", "Fiber 5/5", "Salt 5/20", etc. Perfect for the "how did we get this score" transparency work already on the wishlist. Complements v1.6.0's plain-language takeaway.
Serving size + per-serving nutrition. Actually already shipped — the "Per serving / Per 100g" toggle at the top of the nutrition section defaults to per-serving on any product with a serving size defined. Turned up in the audit for this wishlist item after the fact. Left here as honest correction.
Category comparison. "Compared to Wholemeal sliced breads: +32% fiber, -13% sugar." OFF computes this automatically. Deeply useful shopping context.
Nutrient level qualifiers. Shipped v1.6.7. Small Low / Moderate / High badges under the Sugar, Sat fat, and Salt cells — sourced from OFF's nutrient_levels_tags, which uses NHS/WHO reference values. Answers "is 1.1g of salt actually a lot?" without the user needing to know reference ranges.
Per-ingredient percentages. "Whole wheat flour 39.3%, water 30.4%..." Deep ingredient transparency — helps shoppers understand what they're really eating.
Vegan / vegetarian / palm oil flags. Automated from ingredients taxonomy. Useful for a real subset of US shoppers with dietary preferences.
Common name and taxonomy hierarchy. Would improve alternatives matching quality (we're currently matching on brand + one category level; OFF has 5-level taxonomies).
Positive labels — "No added sugar", "High fibre", USDA-organic. Would need filtering to US-relevant labels (EU-organic doesn't help US shoppers).
Data completeness indicator. OFF marks pages as complete/incomplete. Displaying this respects the user's ability to judge how much weight to give the info — matches our honest voice.
Deliberately not adopting — Green-Score / Eco-Score, carbon footprint, life cycle analysis, packaging materials, origins of ingredients, producer platform links, "report vandalism to moderators" tools. These are excellent features of OFF but sit outside our health-first, US-focused identity. Adding them would dilute the brand.
Why this is high-priority. Adopting these expands what makes KindlyChecked feel authoritative and helpful without new data sources, new APIs, or infrastructure — the fields are already in every OFF response we fetch. Strengthens the info-advocate positioning we've been building. Best done as a series of focused ~1-hour ships (one field per release), not one big drop.
Why this is high-priority. Adopting these expands what makes KindlyChecked feel authoritative and helpful without new data sources, new APIs, or infrastructure — the fields are already in every OFF response we fetch. Strengthens the info-advocate positioning we've been building. Best done as a series of focused ~1-hour ships (one field per release), not one big drop.
Effort: ~8-12 hours total, shipped incrementally as ~1-hour bites per field
Soon-ish
Two-product comparison
Scan (or manually enter) two products, see them side-by-side: scores, verdict bands, per-serving nutrition deltas, flag counts, notable ingredients. Serves the "which one should I buy?" moment in the aisle — a genuine research-tool use case that scanner-only apps like Yuka don't offer.
Design intent: stacked layout with delta highlighting (works cleanly on narrow mobile screens rather than cramped two-column). Verdict copy tuned to the "considerate friend" voice — "B is stronger overall," "Different tradeoffs," or "Roughly the same" instead of a bare score comparison. Gentle acknowledgement when the two products are from different categories: "These are different types of products — comparison may be less useful."
Design intent: stacked layout with delta highlighting (works cleanly on narrow mobile screens rather than cramped two-column). Verdict copy tuned to the "considerate friend" voice — "B is stronger overall," "Different tradeoffs," or "Roughly the same" instead of a bare score comparison. Gentle acknowledgement when the two products are from different categories: "These are different types of products — comparison may be less useful."
Positioned after the OFF field expansion work above because per-serving nutrition is a hard prerequisite — Americans read per-serving, and comparing two products per-100g wouldn't feel right. Compare gets much stronger once per-serving lands.
Effort: ~3.5-4.5 hours
Shipped v1.6.14 · Extended v1.6.16 · Tuned v1.6.18 · Re-plumbed v1.6.19 · Cached v1.6.20 · Prewarmed v1.6.21 · Paginated v1.6.22 · Unfiltered v1.6.23 · Unblocked v1.6.24
Search functionality
Type a product name, see US-filtered results with preview scores, tap to open. Debounced 300ms so we don't hammer OFF's servers. Reuses the same three-layer US filter (whitelist + foreign blocklist + positive-US-signal) as alternatives, so results feel consistent across the app. Entry point: "Or search by name" text link below the Scan CTA on home.
v1.6.16 extension: search now covers all three OFF-family databases (food, cosmetics, cleaners) in parallel via Promise.allSettled. Each result carries a type tag and gets scored by the appropriate engine (scoreFood / scoreCosmetic / scoreCleaner). Results are interleaved round-robin so no single type dominates. The original v1.6.14 shipped food-only, which turned out to be inconsistent with the scanner's three-database promise — user callout led directly to the fix.
v1.6.18 US-filter tuning for cosmetics: after v1.6.16 landed, a French Venus shampoo ("Shampoing micellaire") slipped through as a 100/100 US product. Root cause was three-layered: (1) the script check only caught non-Latin alphabets, missing Latin-script European languages; (2) the blocklist was food-only, missing European cosmetics brands; (3) cross-category brands like Gillette (razors + Venus EU cosmetics) got fast-path acceptance from the whitelist. Fixed all three: added a hasNonEnglishPrimaryName heuristic (diacritics + European product terms + no English variant), extended the blocklist with EU cosmetics/personal-care brands, and introduced CROSS_CATEGORY_BRANDS which require positive-US-signal verification even when whitelisted.
v1.6.19 architecture fix (the real bug): user ran the app with DevTools open and shared the console. The truth was that OFF's
v1.6.20 (the actual real bug, this time verified): v1.6.19's CORS diagnosis was wrong — OFF's CGI does send CORS headers. The real problem was two-fold: (a) OFF's popularity-ordered search results are dominated by foreign products with countries_tags mis-tagged as en:united-states (top result for "milk" was Moroccan Jaouda), and (b) OFF rate-limits our server on expensive queries — "milk" failed 3/3 times, "coffee" 1/3. Three real fixes, verified by user-run diagnostics: (1) added
v1.6.21 (zero-friction completion): pre-warm cron. A daily cron at
v1.6.24 (the rest of the overreach): "Maybelline" still returned nothing after v1.6.23, which ruled out the proxy and pointed at the client-side US filter. Three problems, all introduced in v1.6.18 while chasing a single French shampoo. (1) The cosmetics blocklist swept up L'Oreal, Garnier, Vichy, La Roche-Posay, Avene, Nuxe, Caudalie, Weleda, Schwarzkopf, Lush and The Body Shop — every one of which sells in US drugstores, Target or Ulta. Trimmed to EU-only house brands and explicit foreign SKU tags. (2) The blocklist ran before the whitelist, so a parent-company tag could veto a confirmed US brand: OBF tags Maybelline entries ["maybelline","l-oreal"], and "l-oreal" killed "maybelline". Whitelist now wins when both match. (3) The heuristic path required countries_tags plus a positive US signal — fields OFF populates and OBF/OPF almost never do — so no cosmetic could pass on merit. Filter is now type-aware. The through-line across v1.6.18 through v1.6.24: a fix verified against one product, generalized to a whole category on assumption, three times running.
v1.6.23 (walking back an overreach): searching "Maybelline" returned nothing even though the mascara was in the database and its barcode resolved fine. Cause: the server-side country filter added in v1.6.20 to fix food search, then applied to all three proxies without checking whether it suited them. OBF and OPF tag countries far more sparsely than OFF, so the filter dropped nearly every cosmetic and cleaner upstream. Removed it from those two proxies; food keeps it. Same lesson as the CORS episode — a fix verified in one place got generalized to three on assumption.
v1.6.22 (progressive disclosure): user noted search felt truncated at 15 total results, especially for popular brand queries. Client fetch cap raised 15 → 25; OFF proxy page_size 25 → 50 so the US filter has more raw material to work with. First 10 render by default; a "Show more results (N)" button reveals the rest instantly (all fetched in one call — no page 2 request). Resets to 10 whenever the query changes. Cache size roughly doubles per entry but still small (~200KB per query per database).
v1.6.16 extension: search now covers all three OFF-family databases (food, cosmetics, cleaners) in parallel via Promise.allSettled. Each result carries a type tag and gets scored by the appropriate engine (scoreFood / scoreCosmetic / scoreCleaner). Results are interleaved round-robin so no single type dominates. The original v1.6.14 shipped food-only, which turned out to be inconsistent with the scanner's three-database promise — user callout led directly to the fix.
v1.6.18 US-filter tuning for cosmetics: after v1.6.16 landed, a French Venus shampoo ("Shampoing micellaire") slipped through as a 100/100 US product. Root cause was three-layered: (1) the script check only caught non-Latin alphabets, missing Latin-script European languages; (2) the blocklist was food-only, missing European cosmetics brands; (3) cross-category brands like Gillette (razors + Venus EU cosmetics) got fast-path acceptance from the whitelist. Fixed all three: added a hasNonEnglishPrimaryName heuristic (diacritics + European product terms + no English variant), extended the blocklist with EU cosmetics/personal-care brands, and introduced CROSS_CATEGORY_BRANDS which require positive-US-signal verification even when whitelisted.
v1.6.19 architecture fix (the real bug): user ran the app with DevTools open and shared the console. The truth was that OFF's
/cgi/search.pl endpoint blocks CORS — food searches were silently failing from v1.6.16 onward. Cosmetics (OBF) and cleaners (OPF) worked because those hosts happen to allow CORS. Which meant every "milk" search had been returning only what OBF happened to have. Real fix: three minimal PHP proxies at /api/search-food.php, /api/search-cosmetic.php, /api/search-cleaner.php that forward to the OFF-family CGI endpoints and return with proper CORS headers. Client now hits same-origin URLs — CORS is a non-issue by construction. If OBF/OPF ever tighten CORS too, we're already routed through our own proxy and nothing breaks.
v1.6.20 (the actual real bug, this time verified): v1.6.19's CORS diagnosis was wrong — OFF's CGI does send CORS headers. The real problem was two-fold: (a) OFF's popularity-ordered search results are dominated by foreign products with countries_tags mis-tagged as en:united-states (top result for "milk" was Moroccan Jaouda), and (b) OFF rate-limits our server on expensive queries — "milk" failed 3/3 times, "coffee" 1/3. Three real fixes, verified by user-run diagnostics: (1) added
tagtype_0=countries&tag_0=united-states to the OFF query so we filter server-side; (2) 24-hour file-based response caching in /api/cache/<database>/; (3) retry-on-503 with 800ms backoff plus stale-cache fallback. Extracted shared logic into _search_helper.php. The pattern this exposed: I shipped five broken versions in a row because I kept theorizing instead of verifying. The user's persistent diagnostics (four rounds of debug output) is what got us to the actual bug.
v1.6.21 (zero-friction completion): pre-warm cron. A daily cron at
/api/prewarm.php?key=<secret> reads common-queries.txt (~95 hand-picked common queries — cheerios, oat milk, shampoo, dish soap, etc.) and calls each against all three search proxies with 2.5s delay between calls. Rate-discipline friendly with OFF (~12 minutes total). Result: cache is populated before real users arrive, so common searches are instant instead of hitting the OFF rate limiter. Idempotent — already-fresh cache entries return X-Cache: HIT and never touch OFF. Auth via shared-secret. Ships with a static seed list; can be replaced with real usage-tracked queries once we have telemetry.
v1.6.24 (the rest of the overreach): "Maybelline" still returned nothing after v1.6.23, which ruled out the proxy and pointed at the client-side US filter. Three problems, all introduced in v1.6.18 while chasing a single French shampoo. (1) The cosmetics blocklist swept up L'Oreal, Garnier, Vichy, La Roche-Posay, Avene, Nuxe, Caudalie, Weleda, Schwarzkopf, Lush and The Body Shop — every one of which sells in US drugstores, Target or Ulta. Trimmed to EU-only house brands and explicit foreign SKU tags. (2) The blocklist ran before the whitelist, so a parent-company tag could veto a confirmed US brand: OBF tags Maybelline entries ["maybelline","l-oreal"], and "l-oreal" killed "maybelline". Whitelist now wins when both match. (3) The heuristic path required countries_tags plus a positive US signal — fields OFF populates and OBF/OPF almost never do — so no cosmetic could pass on merit. Filter is now type-aware. The through-line across v1.6.18 through v1.6.24: a fix verified against one product, generalized to a whole category on assumption, three times running.
v1.6.23 (walking back an overreach): searching "Maybelline" returned nothing even though the mascara was in the database and its barcode resolved fine. Cause: the server-side country filter added in v1.6.20 to fix food search, then applied to all three proxies without checking whether it suited them. OBF and OPF tag countries far more sparsely than OFF, so the filter dropped nearly every cosmetic and cleaner upstream. Removed it from those two proxies; food keeps it. Same lesson as the CORS episode — a fix verified in one place got generalized to three on assumption.
v1.6.22 (progressive disclosure): user noted search felt truncated at 15 total results, especially for popular brand queries. Client fetch cap raised 15 → 25; OFF proxy page_size 25 → 50 so the US filter has more raw material to work with. First 10 render by default; a "Show more results (N)" button reveals the rest instantly (all fetched in one call — no page 2 request). Resets to 10 whenever the query changes. Cache size roughly doubles per entry but still small (~200KB per query per database).
Honest correction on effort: originally estimated at ~1 hour. Actual v1.6.14 was 3-4 hours; the v1.6.16 extension added another ~2 hours. The "1 hour" estimate was for a version that shouldn't have shipped as-is. Recording the correction so future estimates land closer to reality.
Soon-ish
Manual top-100 US product curation
Find the most-scanned US groceries, hand-edit each one's OFF entry to ensure clean category tags + complete data. Brute force, hours of focused work, but moves the needle on hit rate more than any code change.
Why this matters. The "alternatives feel useless" problem isn't fully solvable with smarter algorithms — OFF's US category data is structurally patchy. Yuka's curated category mapping is what makes their alternatives feel coherent. We don't have to match Yuka, but we have to fix the worst cases.
Effort: 10–20 hours, mostly OFF data entry
Soon-ish
Detailed scoring math on result page
Show the math breakdown — "Nutri-Score B = 60 → ×0.7 = 42, additives = 100 → ×0.3 = 30, total = 72." Reinforces the "no black box" promise.
Major progress shipped (v1.4.5 + v1.5.12 + v1.6.0). Full ingredient list visible on every result. Every flag expands into plain-English explanations with regulatory body citations and evidence levels (Strong / Moderate / Mixed / Emerging / Limited). "Where we got this info" footer at the bottom of every result page links to Nutri-Score, IARC, EFSA, FDA, EWG. Every result also opens with a plain-language takeaway synthesizing the score in 1-2 sentences. The only remaining piece is the literal math breakdown — showing the user "B grade × 0.7 + additives × 0.3 = your score."
Effort: ~30 min remaining
Soon-ish
Better cosmetics scoring
Current cosmetic scoring is simpler than food — just hazardous ingredient counts. Could include allergen flags, fragrance disclosure quality, EWG cross-reference, certification bonuses (or not, given we just removed organic bonus from food).
Effort: ~1–2 hours research + code
Soon-ish
Position write-up: KindlyChecked vs Yuka explicit
A page that goes hard on the differentiation — open algorithm, no organic bonus, no paywall, considerate verdicts, "what we won't do" promise. The marketing site hints at it; an explicit comparison would be the SEO play and the link-share play.
Effort: ~2 hours writing
Soon-ish
Roadmap doc
What comes after v1. Different from this wishlist — actually picks an order, sets expectations, becomes shareable with friends/early users so they know what's coming.
Effort: ~1 hour
Someday.
Real ideas, but require either real time, real money, or real users to justify the work.
Someday
Second data source for cosmetics coverage
Open Beauty Facts is genuinely smaller than Open Food Facts — nowhere near the "3M+ products" you get on the food side. Real US shoppers scanning cosmetics from Sephora, Ulta, Target, or Walmart hit "not found" much more often than they do with packaged food. The v1.6.9 not-found copy is honest about this, but honesty is a floor, not a ceiling. To actually make cosmetics scanning work well, we'd probably need a second cosmetics database layered behind OBF.
Real candidates: INCI Beauty (proprietary, licensing conversation required), EWG's Skin Deep (public database but licensing terms unclear for a commercial app), CosIng (EU regulatory database — free but limited to ingredient identity, no product-level data). Each has a different tradeoff between coverage, licensing cost, and data richness.
Real candidates: INCI Beauty (proprietary, licensing conversation required), EWG's Skin Deep (public database but licensing terms unclear for a commercial app), CosIng (EU regulatory database — free but limited to ingredient identity, no product-level data). Each has a different tradeoff between coverage, licensing cost, and data richness.
Why Someday and not sooner. Every option involves either a real licensing conversation or a legally-ambiguous re-use of someone else's work. None are the "just add an API call" work that our OFF integration was. Also: cosmetics scanning isn't currently our primary use case — most of our audience-fit work has been food-shopper focused. Adding a second cosmetics source would be justified once we have (a) real signal that US users care about cosmetics scanning as a primary need, and (b) enough traffic that licensing conversations with data providers would be taken seriously.
Cheaper alternative worth exploring first. An honest FAQ or About page section that names Yuka as the better tool for cosmetics scanning at our current scale. Not competitive with our identity — we're food-first — and honest positioning about our limits is on-brand.
Cheaper alternative worth exploring first. An honest FAQ or About page section that names Yuka as the better tool for cosmetics scanning at our current scale. Not competitive with our identity — we're food-first — and honest positioning about our limits is on-brand.
Effort: weeks of licensing/legal work + weeks of integration, once justified
Someday
International expansion: Canada → UK → EU
v1 is explicitly US-focused. The "Made for US shoppers" positioning we shipped in v1.5.0 is honest, but it also creates a roadmap commitment. Canada is the natural first international launch (English-speaking, similar grocery brands, OFF coverage decent). UK and EU follow.
What's required for each region. A meaningful Pantry staples list for that country. A solid OFF data audit for the country's top grocery items. Region-specific copy ("Made for Canadian shoppers"). The `_isCountry` filter logic generalized from `_isUS`. Possibly local-currency support if we add price awareness. Not technically hard — just needs real research time per region. Should only happen after we have meaningful US user adoption to justify the work.
Effort: 1–2 weeks per region, mostly research not code
Someday
MindYoPet — sister app for pet food
The concept doc exists at /mindyopet-concept. The data path is easier than expected: Open Pet Food Facts already exists as the fourth OFF-family database, and OFF now offers a universal barcode-scan API (
What isn't plug-and-play: the scoring engine. Pet food is a genuinely different scoring domain. Nutri-Score doesn't apply to pet food (per OFF's own docs). NOVA classification wasn't designed for it. What counts as "healthy" depends on species — dogs, cats, rabbits, birds, and fish have radically different nutritional needs. What's toxic to one is fine for another (chocolate is fatal to dogs, taurine is essential for cats but not humans). Additive concerns are different too. A "considerate friend" voice for pet nutrition requires actual pet-nutrition expertise, not our human-food heuristics ported over.
Data availability caveat: Open Pet Food Facts is much smaller than OFF — coverage of US mainstream pet food brands is likely thin.
?product_type=all) that returns pet-food results with a petfood product_type. That part is essentially plug-and-play.
What isn't plug-and-play: the scoring engine. Pet food is a genuinely different scoring domain. Nutri-Score doesn't apply to pet food (per OFF's own docs). NOVA classification wasn't designed for it. What counts as "healthy" depends on species — dogs, cats, rabbits, birds, and fish have radically different nutritional needs. What's toxic to one is fine for another (chocolate is fatal to dogs, taurine is essential for cats but not humans). Additive concerns are different too. A "considerate friend" voice for pet nutrition requires actual pet-nutrition expertise, not our human-food heuristics ported over.
Data availability caveat: Open Pet Food Facts is much smaller than OFF — coverage of US mainstream pet food brands is likely thin.
Decision: build as sister app, not KindlyChecked tab. After actually looking at the data situation and the scoring problem, the answer is clearer than it was. Bolting petfood into KindlyChecked would either (a) show human-food scores that are misleading for pets, or (b) skip scoring and just show ingredients — thin value that undermines the "informant that helps you understand" identity. A separate app lets MindYoPet be designed for pet owners with the right scoring engine, right voice, and right species-specific educational content. Shares infrastructure (build pipeline, brand family, hosting) but is its own product.
Real prerequisites: (1) KindlyChecked has meaningful US user adoption to justify the founder attention split. (2) Real pet-nutrition research to design the scoring engine — probably needs consultation with vets or pet nutritionists, not just "read a few papers." (3) Understand the species matrix — how the app handles "dry dog food vs cat treats vs fish flakes" as radically different scoring contexts.
Real prerequisites: (1) KindlyChecked has meaningful US user adoption to justify the founder attention split. (2) Real pet-nutrition research to design the scoring engine — probably needs consultation with vets or pet nutritionists, not just "read a few papers." (3) Understand the species matrix — how the app handles "dry dog food vs cat treats vs fish flakes" as radically different scoring contexts.
Effort: weeks of research + weeks of build, on top of the ongoing OFF-integration patterns we've already established. Realistically a 2-3 month solo project.
Someday
Crowdsourced US barcode contributions
Every "not found" scan is a chance to grow the database. With 100+ active users, you build a real US product database in months. But this needs a backend — which we don't have, and which contradicts the "everything stays on your device" privacy promise.
The current "Be the first" not-found state already routes contributions to Open Food Facts directly — which is the right pattern. Our own backend is the wrong scope.
Effort: backend infrastructure work, weeks
Someday
Price awareness
OFF doesn't store price. Adding it requires either (a) a separate price data source — most have legal/ToS issues, none are free, (b) user-contributed price, requires a backend, or (c) just acknowledging the limitation in copy.
(c) shipped already — we now show "We score nutrition, not price" under the alternatives list. That's the honest version. Real price data is a someday-maybe-never project.
Effort: months if real, vs minutes if just acknowledged
Someday
Phase 2 alternatives engine improvements
Beyond what's shipped (brand-first matching, offender-fixing requirement, three-layer US filter — ~250-brand whitelist with major private labels, ~50-entry foreign brand blocklist, comprehensive non-Latin script check, positive-US-signal requirement for non-whitelisted brands — parallelized fetching with 7-day version-keyed cache, "why better" tags, four distinct empty states) — could add price awareness, "available at my store" filtering, "similar to my purchase history" personalization, and per-product "mute alternatives" opt-out.
Effort: varies wildly by which improvement
Someday
Profile/settings deep-dive
Audit what's in the profile screen now, what's missing. Likely candidates: dietary preferences beyond allergens (vegan, vegetarian, low-sodium, low-sugar), language preference, units (metric vs imperial), default scan category if multiple match.
Effort: ~2 hours, dependent on what users actually ask for
Someday
Regenerate the OG share image
The current og-image.png at /og-image.png is from May 5 — pre-scanner-redesign and pre-organic-policy. When someone shares a link to kindlychecked.app on Twitter/iMessage/Slack, the preview card uses this image. Worth refreshing once we hit a stable visual milestone, since redoing this for every minor release is wasted effort.
Effort: ~1 hour to design + export
Someday
Dark mode
Current design is light-mode only. Dark mode is real work given the brand color system (lime on cream is the signature; it doesn't cleanly invert). Done well, it's nice. Done poorly, it dilutes the brand.
Effort: ~3–4 hours of design + implementation
Someday
Animations + micro-interactions polish pass
The app has functional animations (loading screen, detection pulse, page transitions) but nothing distinctive. Could add more delight — score reveal animation, scan-success haptic, parallax decorations. Lots of work, marginal value, easy to overdo.
Effort: 5+ hours, easy to over-engineer
Someday
USDA FoodData Central as second source
~400K US products with proper nutritional data. Would dramatically improve US coverage. The catch: no barcode lookup — they use NDB numbers. Requires a UPC→NDB bridge, which doesn't exist as a free public service.
Effort: weeks, possibly requires a paid lookup service
Killed.
Ideas considered and explicitly rejected. We log these so we don't accidentally rebuild them later.
Killed
10% organic bonus in food scoring
Yuka adds 10% to organic products. We did too, originally. Removed in the algorithm honesty pass.
Why killed. Organic doesn't make food more nutritious — it just changes how it was grown. Adding score points pushes users toward more expensive products without making them healthier. Same critique we leveled at Yuka. We surface organic certification as info (with a thoughtful "what organic does and doesn't mean" treatment), but don't reward it numerically.
Killed
Onboarding: Sample scan preview
Show a faked-up "here's what a scan looks like" card during onboarding to give users a taste before they scan.
Why killed. Tempting, but adds complexity and a fake-feeling element. The "What we won't do" trust panel does more brand work without pretending to show real data.
Killed
Onboarding: Explicit Skip button
A "Skip — just let me scan" link that bypasses the form entirely.
Why killed. Both fields are now labeled "(optional)" with a soft tone. That does the same work without adding a button. Tap "Start scanning" with empty fields and you're in.
Killed
Onboarding: Email signup for updates
"Drop your email if you want to hear about new features."
Why killed. Conflicts directly with the "no accounts, no tracking" promise. The trust panel becomes a lie if there's an email field five inches below it. Hard kill.
Killed
Onboarding: Animated category cards
Three large interactive cards for Food / Cosmetics / Cleaners during onboarding, possibly with hover/tap animations.
Why killed. Real estate cost greater than benefit. The trust panel is more impactful, and the user can discover the three categories naturally on their first scan. Premature visual flourish.
Killed
Onboarding: Dismissable privacy modal
A separate "your privacy matters" modal you have to dismiss before reaching the main onboarding screen.
Why killed. Modals are friction. Embedded the privacy promise inline in the main flow instead — readers see it without having to dismiss anything.
Killed
Hard US-only filter on alternatives
Filter the alternatives list to only products tagged with countries_tags including United States.
Why killed. OFF's countries_tags is too patchy — hard filter would shrink results to near-zero for many categories. We do soft prioritization instead (US products sort first, but non-US can still appear if much better). Soft sort > hard filter.
Killed
Plausible analytics
Aggregate-only, privacy-friendly analytics ($9/mo) for total visitor counts.
Why killed. Conflicts with the "no tracking" privacy promise. The launch-kit doc was rewritten to teach learning at this scale through conversations with users instead of metrics dashboards. If we ever cross 100+ users and need analytics, we'd update the privacy page first — but we don't need it now.
Killed
Set User-Agent on OFF API requests
Send a custom User-Agent header identifying KindlyChecked, as Open Food Facts requests.
Why killed. Browsers don't allow setting User-Agent via fetch — it's a forbidden header per browser security rules. Most browser-based apps using OFF have the same constraint. As long as we stay under rate limits (we will easily), we're fine. Would need a server-side proxy to comply, which we don't have and don't need.
Killed
Excellent / Good / Poor / Avoid verdict labels
The original verdict labels in the app code. Yuka uses essentially these.
Why killed. Moralizing. The brand promise is "considerate, never alarmist" — we explicitly criticized Yuka for this exact pattern. Replaced with Strong / Solid / Mixed / Heavy, which describe rather than judge. Stragglers in the marketing site's interactive demo and allergen copy were caught and aligned in the May ecosystem audit.
Last updated · May 2026 · Claude session