Fetching latest headlines…
How we built a live has_active_wishlist flag for Shopify (and why it was harder than it looks)
NORTH AMERICA
πŸ‡ΊπŸ‡Έ United Statesβ€’July 6, 2026

How we built a live has_active_wishlist flag for Shopify (and why it was harder than it looks)

1 views0 likes0 comments
Originally published byDev.to

Most Shopify wishlist apps have the same quiet flaw: the wishlist data lives in the app, and the merchant's email platform never sees it. The store knows who wants what β€” but can't email on it.

We built WishList Ninja to fix exactly that. Here's how the interesting bits work.

The core idea: profile properties, not just events

Everyone fires events ("Added to Wishlist"). Events are fine for triggering flows, but useless for segmentation β€” you can't build a clean segment of "people with items saved right now" from a two-month-old event.

So on every save/remove we write profile properties to Klaviyo, Mailchimp or Omnisend in real time:

  • has_active_wishlist β€” true only while the wishlist has items in it
  • wishlist_count β€” items currently saved
  • wishlist_value β€” what they're worth
  • top_saved_item β€” the product they want most

That first flag sounds trivial. It isn't.

Why a boolean was the hard part
**
has_active_wishlist has to flip **false
again β€” otherwise it's just "has ever used the wishlist," which is worthless. So every path that empties a wishlist has to re-evaluate it:

  • shopper removes the last item βœ…
  • shopper buys the last item (orders webhook marks items purchased) βœ…
  • guest list merges into an account βœ…
  • and the subtle one: saved collections don't count. A shopper following a collection but holding zero items is not "active intent." Items only.

One rule, five code paths. The rule lives in exactly one function so the paths can't drift apart.

*7 flow triggers from 2 webhooks
*

The email moments merchants actually want are mostly store-side changes, not shopper actions:

Added to Wishlist Β· Price Drop Β· On Sale Β· Low Stock Β· Back in Stock Β· Collection Saved Β· New in Saved Collection

Five of those seven come from diffing products/update webhooks against what shoppers have saved: price went down β†’ find everyone holding that product β†’ fire Price Drop into their ESP. No polling, no cron scanning the catalog.

*Multi-ESP fan-out without domino failures
*

Supporting three ESPs means three APIs that can each be down, rate-limited, or misconfigured. Early version: Klaviyo throwing meant Mailchimp and Omnisend never got the event. Bad.

Now each delivery is isolated β€” a failure is caught and logged, and the job only retries if nothing was delivered. One dead API key can't block the other platforms.

*The storefront budget: ~12KB
*

The whole storefront (hearts on product cards, slide-out drawer, wishlist page, share links, save-for-later on the cart) is vanilla JS, minified to under ~12KB. No framework, no fonts, no CSS libraries. Core Web Vitals are a ranking signal; an app that slows the store is stealing from the merchant to fund itself.

*Stack
*

Laravel + MySQL + Redis on Cloudways, Shopify theme app extension for the storefront, Mailjet for transactional email β€” and a large amount of Claude Code for the build itself.

Launching on the Shopify App Store now. If you run (or build for) a Shopify store, I'd love your take: wishlist-ninja.com πŸ₯·

Happy to go deeper on any of this in the comments β€” especially the webhook diffing.

Comments (0)

Sign in to join the discussion

Be the first to comment!