I turned grocery order history into a personal shopping experience.

A shopping prototype that uses past orders to suggest familiar groceries and new discoveries. I compared five recommendation approaches, built the interface, and explored how people used it.

Role
Product manager & data analyst
Skills
Product scoping, SQL and Python, model evaluation, prototyping, user testing
Duration
Oct 2026

Results at a glance

Results at a glance

Vs. A Shared Best-Sellers List5× Found five times more of a shopper’s next basket than showing everyone the same popular products.
Basket Match Rate24% Measured across 131,209 shoppers by comparing suggestions with each shopper’s later basket.
Average Time to Find an Item4.5s Average time to find a familiar item with suggestions, compared with 21s using search across 4 sessions.

Overview

Three versions, then a prototype

Data: Instacart’s public 2017 dataset contains anonymous grocery orders, products and purchase sequences. I used an archived copy on Zenodo. These records do not represent all Instacart shoppers.

Version 1Suggest familiar groceries

Compared five methods. Chose a simple rule that gives recent purchases more weight.

Selected
Version 2Check purchase timing

Tested whether usual buying gaps improved suggestions. The gain was too small to justify adding it.

Not adopted
Version 3Suggest something new

Used patterns across shoppers to suggest unfamiliar products. Found more next-basket matches than popularity alone.

Added
PrototypeBuild the shopping page

Built both recommendation sections. Four early sessions covered repeat purchases; discovery user testing is next.

Discovery testing next

The problem

Shoppers rebuy the same groceries, but still have to find them

A visible list could help returning shoppers reach familiar groceries with less searching. Historical orders let me test prediction accuracy; testing with people is needed to assess shopping effort.

Tested

Does personal history predict the next basket better than one list for everyone?

Matched comparison on 131,209 customers

Tested

Does machine learning add enough value over a simple rule?

Two fixed model attempts against the same baskets

Explored

Can people understand and use the list?

Four early sessions with the prototype

Not proven

Does it actually save time without causing mistakes?

Needs a controlled test with more people


Scope

What I chose to build, and what I left out

I started with five familiar products and reversible controls. Discovery came later as a separate feature; prices, stock and checkout stayed outside scope.

In Version 1
  • Up to five familiar products
  • Add with one tap, never automatically
  • Hide one exact product, then Show it again later
  • Fewer than five when history is short, never random filler
  • Popular products as a clear fallback for a new shopper
Left out
  • New-product discovery (tested later in Version 3)
  • Prices, stock and checkout
  • Real accounts or an Instacart connection
  • Learning from clicks in real time
  • A separate dashboard

How I tested

Use earlier orders to predict a later basket

Every method faced the same 131,209 shoppers. Lists used earlier purchases only and were saved before checking final baskets.

Earlier ordersSecond-lastLast orderHeld-back basket
Train the modelsanswer
Try and compare ideasanswer
Final check, onceanswer

Recall measures how much of the next basket the list found. Precision measures how many suggestions matched. Hit rate asks whether at least one matched.

Methods

Start simple, then test the extra complexity

I compared three simple rules and two learned models. Recent purchases earned more weight in the rule I selected.

  1. 1

    General popularity

    The same popular products for everyone.

  2. 2

    Personal frequency

    The products each shopper bought most often.

  3. 3

    Weighted recency

    Add purchase points, giving recent orders more weight.

  4. 4

    Logistic regression

    Learn how to combine five purchase-history clues.

  5. 5

    Boosted trees

    Use small decision trees to combine those clues more flexibly.


Results

Personal history made the biggest difference

Personal history found about five times more of the next basket than one popular list for everyone. The two learned models added almost nothing over the simple rules.

MethodRecall@5Precision@5Hit rate@5
General popularity4.69%9.48%36.24%
Personal frequency23.12%35.41%78.23%
Weighted recency chosen24.28%37.32%79.37%
Logistic regression24.28%37.30%79.38%
Boosted trees24.45%37.58%79.45%

My decision

I chose a simpler method, even though another scored slightly better

Boosted trees scored 0.18 points higher on recall. I picked the simpler rule after validation, before the final check.

Easy to trace

Each earlier purchase contributes a visible number of points.

Less to maintain

The default uses a fixed rule rather than a separate trained model.

Not about speed

Both ran fast locally, so the choice came down to clarity.


Version 2 · An idea I stopped

Purchase timing added too little

I gave extra points when a product looked due, based on its usual purchase gaps. The recall gain was 0.025 percentage points against a 0.25-point criterion fixed beforehand. I stopped this attempt instead of moving the goalposts.

−0.050Bar to clear: +0.25

+0.025 points. Its 95% range (−0.003 to +0.052) even includes zero.


Version 3 · Discovery

A separate list for something unfamiliar

I used shared-buyer patterns to rank products absent from each shopper’s recorded history. This keeps discovery separate from buying familiar products again.

  1. 1

    Start with familiar products

    Take up to ten products, weighted by recent purchases.

  2. 2

    Find product connections

    Look for shared buyers, adjusted for each product’s popularity.

  3. 3

    Add personal contributions

    Multiply each familiar product’s weight by its connection strength.

  4. 4

    Remove familiar candidates

    Rank the unfamiliar products; popularity fills any empty slots.

Historical comparison · 15,000 shoppers
Popular products9.31%
Related products10.77%

Share of shoppers with at least one match among five suggestions. Related products reached a net 219 more shoppers; most still had no match.

These shoppers’ records had already been reviewed, so new data would be the real check.


Prototype

A shopping page with personal suggestions

Two lists: Buy it again for products the shopper has bought before, and You might also like for products new to them. Shoppers A and B use real anonymous records; C is a new shopper.

Three shoppers, three states

Shopper AFull listA regular shopper sees five familiar products.
Buy it again row with five familiar products
Shopper BShort listOnly one familiar product, so only one is shown. No random filler.
Buy it again row with only one product
Shopper CNo historyPopular products instead, under their own heading.
Popular products row for a shopper with no history
Shoppers A and BYou might also likeFive products missing from the shopper's recorded purchase history. Add works the same way. There is no Hide here yet.
You might also like row with five unfamiliar products for Shopper A

User testing

Faster on the second try

Each person searched for their usual products, then found the same products again using suggestions.

Time comparison · searching with suggestions
Person 122s → 5s
Person 221s → 4s
Person 322s → 5s
Person 420s → 4s

All participants were given the same products in the same order.


Try it

Use the prototype

Add a product, hide one from Buy it again, then switch between Shoppers A, B and C. A and B also show You might also like. Open full screen ↗


What I learned

Good scores are only part of a useful product

Three lessons I would carry into the next product.

Choose deliberatelyAccept a small accuracy cost

A result the team can explain can be worth more than the top score.

Stop with evidenceDo not move the goalposts

Set the bar before testing, and stop when an idea misses it.

Keep claims separatePrediction is not product value

Matching past baskets shows a list is accurate, not that it saves shoppers time.