Skip to content

Repository files navigation

HealthOrder

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:8000

No npm, no framework, no build toolchain. Python 3 standard library only.


What's in it

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

The basket: three platforms, no winner

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.

What it deliberately does not do

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.

Where every number comes from

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.

Nutrition — transcribed from the pack

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.

Nutri-Score — computed, not copied

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.

Prices — Blinkit real, the other three modelled

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.

Product identity and images

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.

Lab reports

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.


The self-check

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. --net additionally 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.

Repository layout

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.

Changing the catalogue

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.


SEO

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.

Accessibility & performance

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.


Not medical advice

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.

Licence

Code MIT — see LICENSE. Product names, brand names and product images belong to their respective owners and are used here for identification and comparison.

About

India's healthiest grocery, in one basket - 97 curated products with computed Nutri-Score, independent lab-test proof, and a cheapest-basket engine across Blinkit, Zepto, Instamart & JioMart.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages