MedSwitch
Finds a cheaper, chemically identical substitute for Indian prescriptions
₹5,684
annual saving on one real prescription
Overview
Compares pharmacy prices and compositions across Indian retailers so a patient on a chronic medication can find an equivalent that costs a fraction of the brand — and flags anything on the CDSCO banned list along the way.
The problem
Someone on a long-term prescription in India can be paying ten times what the identical composition costs at a different retailer, and there is no way to check without knowing the chemistry. The information is public and spread across sites that describe the same drug in incompatible ways.
Approach
Product listings are ingested from four public sources into a re-parseable raw store, so a parser bug is a re-run rather than a re-scrape. Each retailer's composition text is parsed into structured molecule, strength, dosage form and release modifier by whichever parser matches the grammar it actually uses — one regex handles PharmEasy's rigid strings, a Zod-validated batched LLM parser handles Jan Aushadhi's free text, cached by hash so a re-run only pays for genuinely new strings. Molecule resolution tries exact match, then an alias table, then salt-suffix stripping, before auto-creating a new molecule as a last resort. Equivalents converge on a composition fingerprint, and substitution queries compare real price-per-unit.
What it does
- Resolves molecules across retailers through synonyms and salt-form differences, then matches equivalents by composition fingerprint
- A real prescription resolves to the same composition at ₹17.09 and ₹1.51 per tablet — about ₹5,684 a year at one tablet daily
- Hybrid parsing: regex for rigidly structured retailers, batched LLM for free text, cached by hash — roughly 40% of rows parse with zero LLM calls
- Every scraped composition checked against the CDSCO list of banned fixed-dose combinations
- Nearest Jan Aushadhi store ranked by real haversine distance rather than a pincode-string guess
What I learned
Extraction gaps had to become visible rather than silent. Apollo's extraction is noticeably less reliable under batch scraping — most likely anti-bot rate limiting rather than a collector bug — and the useful move was logging every gap as an `extraction_issue` row instead of dropping it. A pipeline that quietly loses 20% of its rows looks exactly like one that works.