Blinkit · 2023
NPR Engine for AOV Growth & Waste Reduction
Using recommendation logic to grow baskets without creating excess inventory
Pricing & Monetization | Growth & Activation
The recommendation rail in action
- Role
- Sr. Data Analyst, product strategy
- Timeline
- ~6 weeks
- Worked with
- Growth, Category, Merchandising, Supply Chain
- Tools
- SQL, BI dashboards, PMI analysis, A/B testing
16% → 25%
rail impression to add-to-cart
₹8
AOV uplift per order
+1.8
items added in rail-driven baskets
5.8%
less perishable disposal
The problem
The rail after add-to-cart ranked items by platform-wide popularity, so it mostly suggested more of what was already in the cart.
What I did
Redesigned the scoring around cart affinity (PMI), persona clusters and subtype affinity, with a time-of-day boost for perishables and inventory guardrails.
The result
Impression to add-to-cart rose from 16% to 25%, AOV went up ₹8 per order, and perishable disposal fell 5.8%. Shipped to all stores.
The problem
Blinkit's Next Product Recommendation (NPR) rail is the strip of suggestions that appears after a customer adds something to cart. It already existed, but it ranked items by overall popularity, often from the same product type.
Old logic: popularity ranked
Add to cart: Bagels
Rail shows: Milk, Bread, Croissant, Pita bread
Near-zero incremental add-to-cart.
What the rail needed to do
Suggest what this customer is most likely to add next, not more of what is already in the basket.
Do it with live store inventory and category priorities in mind.
Why it was harder than it looked
This was not just a ranking problem. The rail had to balance what felt like a natural next add, the right price point for an impulse buy, live inventory at the store, support for niche categories, and the business goal of reducing perishable disposal.
Right next add
The rail had to show what a customer was actually likely to add next, not just something loosely related.
Price matters
Even relevant products would fail if they were too expensive for an impulse add.
Thin user history
Many customers did not have enough order history for strong personalisation.
Live inventory
A recommendation only worked if it was actually in stock at that store in that moment.
Beyond obvious picks
The logic could not only favour the highest-volume products. It also had to support smaller but valid category pairings.
Business tradeoffs
The rail had to improve add-to-cart behaviour while also supporting margin and reducing perishable disposals.
It wasn't a data problem. Blinkit had rich add-to-cart and order history. It was a logic problem: the rail used the wrong signal, item popularity instead of cart affinity. The fix needed three things:
- 01
Signal design
Which data sources to use and how to weight them
- 02
Scoring logic
How to combine signals into a single rankable score
- 03
Operational guardrails
Inventory, time, and pricing filters before serving
The scoring system
For each cart state, the system shortlisted candidates, scored them, then filtered and ranked them before serving.
- 01
Cart state
Customer adds an item to cart
- 02
Score ~30 candidates
PMI + persona + subtype affinity
- 03
Filter and rank
Perishable boost, price check, inventory check
- 04
Top 15 tiles served
Ranked, filtered, real time
Final score = 0.5 × PMI basket + 0.3 × personalisation + 0.2 × subtype affinity
Why these weights:
- Cart context mattered most, because the rail had to respond to what was already in the basket.
- Personalisation helped when history was available.
- Subtype affinity was the fallback, and supported broader category pairings.
Why PMI, not raw counts
Every SKU was scored against every other SKU by how often they appeared in the same cart. Raw co-occurrence has a bias: items like milk and eggs are in so many carts that they top every list. PMI corrects for that.
Raw counts: popular items dominate
Cart: Nutella
Top match: Milk. High volume, low relevance.
PMI: normalise for popularity
Cart: Nutella
Top match: Strawberries. Lower volume, higher affinity.
PMI(A, B) = log [ P(A, B) / (P(A) × P(B)) ]
Personas instead of individuals
Individual history is thin in quick commerce. Most users order 2 to 4 times a month, so 90 days gives only 8 to 12 orders. Instead, users were clustered into behavioural personas, and each persona gave a dense, reliable signal. A user can belong to several personas, and recommendations combine all of them.
Filters before serving
Scoring ranks the candidates. Filters decide what actually gets served, and they run in order.
- 01
Perishable boostAfter 7 PM
Perishables with high disposal risk get a score multiplier, which lifts them within the already-ranked list. Not a separate clearance experience.
- 02
Price range filterImpulse guard
Candidates priced above 2× the customer's average order value are filtered out. Recommendations should feel like natural additions, not upsells that need a separate mental commitment.
- 03
AOV sortAll day
Within the filtered set, sort by descending price to maximise basket value.
- 04
Inventory checkHard filter
Remove anything not in stock at the customer's dark store. Runs at serve time, not when scores are generated.
- 05
Top 15 servedOutput
First 15 tiles, in order: ranked by score, time-adjusted, price-filtered, inventory-safe.
A tradeoff I had to defend
Leadership concern
Surfacing perishables after 7 PM might feel like the app is offloading unwanted products, which could hurt trust.
How I defended it
The boost was invisible to customers. Perishables ranked higher inside an already personalised list, not in a separate clearance experience. After launch: no drop in repeat order rate or rail engagement, and the disposal reduction held.
What the pilot taught us
Before the national rollout, the algorithm was soft-launched to validate the scoring and catch edge cases.
- Rail ATC rate
Cross-ptype logic validated
Users added recommended items at a measurably higher rate than the same-ptype control group.
- Data quality fix
City-level variation surfaced
Personalisation signals were too noisy for dark stores with under 200 daily orders, so they switched to city-level aggregation.
- Bounce rate
Inventory guardrail was critical
Removing out-of-stock recommendations reduced rail bounce rate and improved repeat rail engagement.
The same algorithm gives very different results depending on the cart, the user's history and the time of day:
Results
The rail shipped to all stores. Conversion went up and perishable disposal went down, all without a separate customer-facing experience.
Built at Blinkit · 2023