Back

Brand Add-on Deals


Background

Role:Product Manager
Company:HappyFresh
Platform:iOS, Android

Timeline: 3-week build cycle
Status: Delivered & Live ๐ŸŸข


TL;DR
Bringing a Purchase-with-Purchase (PwP) mechanic to HappyFresh's checkout, so a spend threshold turns into a moment of delight instead of a wall.

Results

GMV Contribution
+7%
From total GMV per Month
Avg. Basket Size
+30K
From Avg. BS per Month
CVR Rate
+3%
Home to Checkout
Take-up Rate
+5%
From GMV Orders

Opportunity
HappyFresh already had supermarket partners ready to fund Purchase-with-Purchase (PwP) deals โ€” but the app had no way to show these deals to shoppers. So shoppers never saw them, and partners never got the extra sales they paid for. Meanwhile, competitors already offered this exact feature at checkout. Every week we waited, we lost partner budget, missed a chance to grow basket size, and fell further behind what shoppers already expected from a grocery app.


Problem
Shoppers rarely go looking for a Rp15,000 pack of biscuits. The urge to buy it has to be manufactured โ€” the way a checkout aisle in a physical store does it. Our own 2023 research into impulse buying pointed at exactly why that's harder online.

Offline stores trigger impulse purchases through sensory presence. Online shopping keeps people conscious of their running total โ€” the environment has to do the nudging instead.

The product question wasn't "will people want this item" โ€” it was "how do we recreate the checkout-aisle moment inside a cart screen, without turning it into a distraction from the primary task of finishing a grocery order."


Goals

Increase GMV
New incremental order value by partner-funded promotions
Increase Avg. Basket Size
By showing impulsive items
Increase CVR
Increase Conversion Rate from Home to Checkout
Enhance Value Perception
Visible discounts reinforce that HappyFresh is worth shopping on

What shaped the design
Before touching a wireframe, I pulled three behavioral patterns out of our impulse- buying research to use as design constraints โ€” not just inspiration.

Insight A
No urgency โ‰  no interest
Shoppers won't proactively search for a "someday" item โ€” but they'll grab it the moment it's surfaced at the right point in their flow. The environment has to do the asking.
Insight B
Familiarity drives add-to-cart
Items a shopper has already used or bought before convert far better than novel ones โ€” recognition removes the evaluation step entirely.
Insight C
Steep discounts offset low perceived value
A large enough percentage off makes even a "not worth it" item feel worth grabbing โ€” the discount becomes the value proposition.

Sizing the opportunity, before building anything
I framed the opportunity as a funnel so we could estimate impact before committing engineering time, and so the same funnel could later become our measurement plan:

Step 1 - Basket Penetration
How many eligible SKUs do partners supermarkets offer, and what's their basket penetration?
Step 2 - Eligiblity rate
What share of baskets naturally cross the minimum-purchase threshold?
Step3 - Take up Rate
Customers who unlock the offer, how many actually add the item?

The Solution
A Tebus Murah section, placed inside the cart screen โ€” above "Just for You" โ€” where shoppers land right before checkout. Unlike the app's usual product listing, this section scrolls horizontally, borrowing the visual grammar of an end-of-aisle display: present, noticeable, but never blocking the shopper's primary task of reviewing their basket.

Design rule
The section should be impossible to miss but easy to ignore โ€” it earns attention through placement and pricing, not through interrupting the checkout flow with a modal or forced step.

Every promo card needed to clearly communicate why a shopper could or couldn't claim it yet โ€” so I designed three explicit states:

"Add" is visibly disabled โ€” the min-purchase label tells the shopper exactly what closes the gap.

Card unlocked
Once the basket crosses the threshold, "Add" activates automatically โ€” no extra tap, no page reload.

Card Maximum Product Quantity
The stepper caps out instead of failing silently โ€” protecting margin on promo-funded SKUs without a confusing error.

Key decisions & trade-offs

Two intake paths for promotions
Built two onboarding flows instead of one: an internal-fund path (Marketing sets rules directly in Spree) and a supermarket-partner path (Content team uploads partner SKUs in Sirius, tagged as PnQ). This let non-engineering teams launch or swap promotions without a dev ticket every time.
Designing around an imprecise SKU-price mapping
Ops-side dummy SKU codes (e.g. representing "~Rp10,000") didn't map to exact prices the way engineering's systems expected. Rather than block launch on a full data-model fix, I scoped the experience to tolerate an approximate mapping and flagged the precision gap as a fast-follow.
Real-time re-validation, not one-time eligibility
If a shopper removes an item and drops below the minimum basket size, the promo item is automatically dropped from the cart โ€” eligibility is re-checked continuously, not just at the moment it was added.
Fixing a defect we found along the way
QA surfaced a null-pointer crash risk on Android's cart screen specifically for free/promo products. Rather than defer it, we folded the fix into this release's scope since it shared the same code path.

I split the build across two parallel task forces so the timeline wasn't gated by a single team's capacity โ€” coordinating scope and dependencies between them as PM.

Front End Task Force
  • New horizontal card format for the cart screen
  • Built the Tebus Murah section & its three eligibility states
  • Real-time validation of promo items against basket changes
  • Android null-pointer fix for free products
Backend Task Force
  • Sirius admin tooling for Content team to upload partner PnQ items
  • Spree tooling for Marketing-funded promotions
  • Fetch API for Tebus Murah items + promotion-ID based claim logic

Timeline

Development
Week 21
Testing
Week 22
Release
Week 23

Measuring it

I worked with our analytics partner to define a tracking taxonomy that mapped directly back to the funnel from Item 04 โ€” so the eligibility-rate and take-up-rate questions could actually be answered post-launch, not just estimated.

Product Added
cart ยท pwp
Fires when a shopper adds a Tebus Murah item, tagged with promotion type and trigger source.
Cart Viewed
eligible vs. applied
Captures both eligible and applied promo product IDs โ€” the raw input for eligibility & take-up rate.
Alert Maximum Promo Quantity
product_id
Signals when a shopper hits the quota cap โ€” useful for tuning quota sizing over time.
PWP Promotion Applied
new event
Ties the applied promo to supplier, store, and minimum-purchase threshold โ€” enabling store & supplier-level promo performance reporting.
Order Completed
applied_pwp_product_id
Confirms whether the promo item actually survived to checkout.

Results

GMV Contribution
+7%
From total GMV per Month
Avg. Basket Size
+30K
From Avg. BS per Month
CVR Rate
+3%
Home to Checkout
Take-up Rate
+5%
From GMV Orders

What's Next

Personalize the line-up
Every shopper currently sees the same partner SKUs. Ranking Tebus Murah items by prior purchase history should lift take-up rate further,
Close the SKU-price gap properly
Replace the approximate ops-to-tech price mapping with a single source of truth, removing a fragility we accepted to hit the launch date.
Support tiered thresholds
Let a single promo unlock better rewards at higher basket sizes, instead of one flat minimum-purchase gate.