India's healthiest grocery, in one basket — priced on all three apps.
A static, dependency-free catalogue of 106 curated Indian grocery products. Every card shows protein, carbs, total sugar and fat per 100 g; every product page shows a computed Nutri-Score with its full arithmetic and links to independent lab reports. Build one basket and see it priced on Blinkit, Zepto and Swiggy Instamart side by side, with a direct product link on each — delivery fees and free-delivery thresholds included.
python build.py # rebuild catalogue + all 137 pages
python scripts/audit.py # deterministic self-check; exits non-zero on failure
python scripts/audit.py --net # ...also verify every image and proof URL resolves
python -m http.server 8000 # then open http://localhost:8000No npm, no framework, no build toolchain. Python 3 standard library only.
| 106 products across 21 categories | one pick per category slot, chosen on the label |
| 95 exact Blinkit product links | resolved from Blinkit's own public sitemap |
| Real product photography | every product; the retailer's CDN where Blinkit stocks it, the brand's own storefront otherwise |
| 23 products with independent lab reports | Trustified pass/fail, re-test and Gold certification pages |
| 137 static pages | one indexable URL per product and per category |
| A four-platform basket | your list priced on all three apps, direct link per item |
| A macro calculator | height + age in, calories and protein/carb/fat out |
| The Superbrain guide | 6-tier cognitive architecture, including the tier that says which popular biohacks to drop |
Each platform stocks a different subset of your basket, charges its own delivery fee, and waives that
fee above its own threshold. The basket page prices your list on all four and shows them side by side —
HO.platformBaskets() in assets/js/app.js:
for each platform:
sum the items that platform stocks
add that platform's delivery fee, unless the subtotal cleared its own free-delivery threshold
list anything it does not stock, explicitly
It does not rank them. An earlier version searched all fifteen platform combinations for the cheapest split; that was removed on purpose. Assortments and prices move daily, three of the four price feeds are modelled rather than live (see below), and you already know which app you have installed and which one has your address saved. Ranking on numbers that soft is false precision.
What the page does instead is make the comparison honest: every item is a direct link on every platform, and an item a platform does not stock is shown as not listed rather than quietly dropped — because a total built from a smaller basket looks cheaper while buying you less. Each platform card says plainly whether it stocks your whole basket.
None of Blinkit, Zepto or Instamart publishes a public add-to-cart API or deep link. No third-party website can fill your cart on those apps — any site claiming to is guessing. HealthOrder gives you a direct link to each product on each platform, and copies your itemised list to the clipboard.
This is the part most product-comparison sites won't tell you, so it's stated plainly here and on
learn/how-we-rank.html.
Per-100 g values come from the FSSAI nutrition panel printed on the pack, or the brand's own product page. They are not modelled from a generic food database. Brands reformulate; if the pack in your hand disagrees with the site, the pack is right — open an issue with a photo.
Tea is the documented exception. A tea pack declares per 100 g of dry leaf, which nobody consumes,
so the five teas are described per 100 ml of the brewed cup — no sugar, no milk — from reference
composition data. That is why all five show near-zero macros and the same Nutri-Score B: unsweetened tea
is nutritionally close to water, and what actually separates these products is residue testing,
certification and leaf grade. The exception is stated on
learn/how-we-rank.html and in a comment above the rows in
scripts/catalog_data2.py.
Every grade is computed from the nutrition table above it by
scripts/nutriscore.py, using the original 2017 Nutri-Score algorithm —
the fully published Santé publique France specification, chosen precisely because it can be checked by
hand. Every product page prints the complete points breakdown so you can verify the arithmetic.
Three scoring tracks exist, and picking the wrong one is the usual source of error:
- Added fats (ghee, cooking oil, butter) score saturated fat as a share of total fat. Without this every cooking oil is an E and the grade carries no information.
- Beverages use a harsher scale on which only water can reach an A.
- Everything else — milk and nut butters included — uses the general-foods track.
Two honest caveats: Nutri-Score isn't used in India (FSSAI has its own front-of-pack rules), and a grade is only comparable within the algorithm version that produced it, so a grade here may differ from one printed on a European pack under the 2023 revision. A grade is a nutrient score, not a verdict on a food — 90% dark chocolate scores D and is still a better buy than a 45% bar that scores C.
| Source | Status |
|---|---|
| Blinkit | Real. Read from the price published on each product's own Blinkit page. 46 of 106 products returned a live price; the rest weren't stocked in the store Blinkit served, and show an est. marker plus a warning on their own page. |
| Zepto / Instamart | A documented estimate, not a live feed. Derived from the observed Blinkit price by a fixed per-platform multiplier plus a deterministic per-product variation, so the same product always shows the same number. Stock is modelled the same way, with direct-to-consumer and regional brands modelled as less widely listed. |
The whole model is about forty readable lines in
scripts/build_catalog.py — read it before trusting a number. It exists so
the comparison is working, inspectable software rather than a screenshot, and it is written so that
swapping in a real price feed changes one function and nothing else. It is also the main reason the
basket refuses to name a winner.
Matched against Blinkit's public product catalogue, published in
Blinkit's own sitemap — crawling of which their robots.txt
explicitly allows (Allow: /sitemap/*). That sitemap carries both the canonical product URL and an
<image:loc> CDN image per product, which is where product photography and canonical names come from.
Independent test reports come from Trustified, which buys products off the shelf, sends them to accredited labs and publishes pass/fail results. Certification links point at Jaivik Bharat (India Organic) and FoSCoS (FSSAI licence lookup). Label data links point at Open Food Facts.
No affiliate links. No sponsored placements. No brand paid to appear.
python scripts/audit.py is the gate. It is deterministic — arithmetic and parsing, no
judgement — so it belongs in a script rather than in a reviewer's head:
- Catalogue invariants — protein + carbs + fat can't exceed 100 g per 100 g, sugar can't exceed carbs, saturates can't exceed total fat, an Atwater 4-4-9 sanity band on declared energy, no duplicate ids or Blinkit prids, every product has an image and a proof link, every offer is either available-with-a-price or unavailable-without-one.
- Nutri-Score reproducibility — every grade is recomputed from the stored numbers and must match, and the points breakdown printed on the page must actually sum to the published score. The site invites you to check the arithmetic, so the arithmetic is tested.
- HTML — no duplicate element ids, no duplicate titles or meta descriptions, meta
descriptions within the SERP limit, valid JSON-LD, every
<img>has alt, canonicals present, og:image resolves to a file that exists. - Links — every internal href resolves on disk; every sitemap entry is a real page;
every product and category has a page.
--netadditionally HEADs every product image and every external proof URL. - CSS — no
var(--token)that is never defined, balanced braces, the two dark-theme blocks defining identical tokens, and WCAG AA contrast computed from the actual hex values for body, secondary and muted text in both themes.
It currently reports 0 failures and 0 warnings. It has already caught two regressions introduced while writing this README.
build.py entry point — run this
data/
products.json generated: the single source of truth the site reads
overrides.json hand-maintained: indicative prices, name/image overrides
creators.json YouTube channels + their top video (resolved from YouTube)
_blinkit_scrape.json cached scrape: name, live price, CDN image, product URL
scripts/
build_catalog.py merges the scrape + catalogue + overrides -> products.json
catalog_data.py hand-authored catalogue, part 1 (nutrition, proof, copy)
catalog_data2.py hand-authored catalogue, part 2
nutriscore.py the 2017 Nutri-Score algorithm
content.py health tips + the Superbrain guide
build_site.py layout, SEO head, JSON-LD, sitemap
pages_shop.py home, catalogue, category pages
pages_product.py product pages + the basket page
pages_learn.py calculator, Superbrain, tips, creators, methodology
make_og_image.py renders assets/img/og-default.png from the live counts
assets/
css/site.css one stylesheet, tokens on :root, light + dark, Google Sans
js/app.js cart, search, and the four-platform basket pricing
Generated output (index.html, p/, c/, learn/, tools/, sitemap.xml) is committed so the repo
can be served straight from GitHub Pages with no CI step.
Edit scripts/catalog_data.py (or catalog_data2.py) and run python build.py. Each row is:
(prid, id, brand, category, pack,
(kcal, protein, carbs, sugar, fat, satfat, fibre, sodium_mg),
tags, why_this_one, [proof_links], optional_indicative_price)prid is the Blinkit product id, or None for products not in Blinkit's catalogue.
Multi-page rather than a single-page app, because evergreen search traffic needs one indexable URL per
thing. Every page carries a unique title and description, a canonical URL, Open Graph and Twitter cards,
and JSON-LD: Product with AggregateOffer and NutritionInformation on product pages, ItemList on
category pages, BreadcrumbList everywhere, and FAQPage on the pages that answer real questions.
sitemap.xml and robots.txt are generated on every build.
Skip link, semantic landmarks, every control labelled, visible focus states, a real modal
dialog for the basket drawer (labelled, focus moved in and restored on close, Tab trapped), the
full combobox keyboard pattern on search (arrow keys, aria-activedescendant, announced result
count), a quantity stepper that keeps focus and announces changes, lang="hi" on the Devanagari
content, prefers-reduced-motion honoured, and a light/dark theme that respects the system
setting with a manual override and announces its state. No analytics
and no third-party JavaScript. External requests are limited to Google Sans from Google Fonts, product
images from the retailer's CDN, and the YouTube embeds on the creators page (youtube-nocookie.com).
Catalogue cards are rendered server-side, so the grid is complete before any script runs, and
CSS and JS carry a content hash so a deploy is never served a stale asset.
The macro calculator and the Superbrain guide are starting points, not a treatment plan. If you are pregnant, diabetic, or have kidney, liver or heart disease, get your numbers from a doctor or a registered dietitian.
Code MIT — see LICENSE. Product names, brand names and product images belong to their respective owners and are used here for identification and comparison.