This article is produced with scandiweb's eCommerce expertise

Collaborate with our development, PPC, SEO, data & analytics, or customer experience teams to grow your eCommerce business.

Magento Loyalty Program Case Study: How We Built Holzkern’s Reward Engine on Magento 2

Holzkern, the Austrian wood-watch brand, came to scandiweb with a specific brief: they wanted a loyalty program that lived inside their Magento 2 catalog, not bolted on as a third-party widget that bled their checkout speed and reroute their order data through a vendor cloud. The Premium Club, they called it. Customers would collect Tree Rings on every purchase, redeem them for products or discounts, and earn extra points for social shares, newsletter signups, and birthdays. The catch: Magento ships no loyalty engine of its own, and the best off-the-shelf extension at the time only awarded points on closed orders, nothing else. So we built the rest.

This case study walks through how the reward engine was built, what we shipped on top of the Mirasvit Rewards extension, the bug we discovered three days after go-live, and what merchants thinking about a native Magento loyalty program should know before they start.

🚀 Quick takeaway

A Magento-native loyalty program gives you the lowest checkout-latency cost and full control over the points ledger, but you will write custom code. Plan for it up front.

Overview

  • Holzkern needed a loyalty program tied to their Magento 2 catalog and customer accounts, not a third-party widget.
  • scandiweb built 4 custom Magento modules on top of the Mirasvit Rewards extension to cover onsite actions, historical-order migration, partial-refund logic, and birthday coupons.
  • 100% of historical Holzkern orders were migrated into the new points ledger via a one-time script at go-live.

The brief: what Holzkern needed from the Premium Club

Holzkern sells handmade watches and accessories made from natural materials, with €1 from every watch sold going to reforestation, sustainable packaging, and disability-employment programs. Their store runs on Magento 2 across multiple country views, and the founders wanted the Premium Club to feel like a native part of the account area, not a popup overlay.

The goals were straightforward on paper:

  • Award 100 Tree Rings per €1 or $1 spent.
  • Give customers a way to earn points outside checkout: newsletter subscribe, Instagram follow, Facebook like, WhatsApp share, birthday and phone capture.
  • Let customers exchange points for products, coupon codes, or exclusive perks.
  • Recognize the full purchase history of any customer who had shopped before the Premium Club launched, including guest orders that were later associated with a registered account.
  • Send a coupon code as a birthday gift 7 days after a customer’s birthday.
Holzkern Premium Club account page showing a customer's Tree Rings balance and earn-actions list
The Holzkern Premium Club account screen, built natively into Magento 2

None of this is exotic in isolation. The challenge was the surface area: every earn action, every redemption rule, every refund scenario had to write to the same points ledger and survive across stores, store views, and the brand’s promotion calendar without doubling points or stranding them. That is not the kind of thing a stock extension does.

🚀 Quick takeaway

The cost of a loyalty program is rarely the points themselves. It is the edge cases: refunds, guest-to-registered conversions, multi-store migration, and the moment a discount stacks the wrong way.

Why Magento-native, not a third-party widget

A merchant deciding between building loyalty natively in Magento (Adobe Commerce) or layering a SaaS widget like LoyaltyLion, Smile.io, or Yotpo Loyalty is really making three trade-offs at once: speed, control, and total cost.

Third-party widgets plug in fast and ship a polished customer-facing UI on day one. The points ledger lives in the vendor’s cloud, the JS loads on every page, and every redemption is an API round-trip out and back. For a brand running a couple of stores in one language, the trade-off is fine. For a brand with multiple store views, custom checkout logic, or a heavy promotion calendar, the round-trips compound: pricing rules conflict with vendor-side discount codes, points balances drift between the widget and your ERP, and the JS payload adds load to the pages that already need to be fast.

Magento-native loyalty flips it. The points ledger is a table in your Magento database. Earn and redeem logic is event-driven inside the platform. There are no extra HTTP calls at checkout, no third-party cloud dependency, and your loyalty rules can read from any Magento entity, customer group, product attribute, cart rule, order, refund. The trade-off is that you build the rules. You also own the bugs.

Decision factorMagento-native buildThird-party loyalty widget
Time to first launch6 to 10 weeks of dev2 to 4 weeks of config
Checkout latency costNear zeroAPI round-trip per points operation
Ledger ownershipYour Magento DBVendor cloud
Custom rule flexibilityAnything Magento can expressVendor’s rules engine ceiling
Recurring costDev maintenance only$300 to $3,000+/mo + transaction fees
Best fit forMulti-store, custom checkout, heavy promo logicSingle-store, standard catalog
Magento-native loyalty vs third-party widget: side-by-side decision factors

For Holzkern, native won on three counts: their checkout was already custom, their store ran multiple country views, and the founders wanted the Premium Club’s UI inside the account area, styled in their theme, not in a vendor’s iframe. If your situation is the inverse, a widget is the right call: we cover the platform-agnostic setup walkthrough for that path separately.

🚀 Quick takeaway

If your checkout is already custom and you run more than one store view, building loyalty inside Magento usually pays back inside a year. If you’re on a single stock store, a widget is faster and probably cheaper.

What we built: 4 custom Magento modules on top of Mirasvit Rewards

Holzkern picked the Mirasvit Magento 2 Reward Points, Referral and Loyalty Program extension as the base. Out of the box it handled awarded points from closed orders. That covered roughly one third of the Premium Club’s earn surface area. The rest is what scandiweb shipped:

1. Onsite-action points module

The base extension awarded points only on order completion. To award points for newsletter subscriptions, social shares, Instagram follows, Facebook likes, WhatsApp recommendations, and birthday or phone-number capture, we wrote a Magento module that:

  • Listens to Magento events for each tracked customer action.
  • Writes the corresponding points entry to the Mirasvit Rewards ledger.
  • Enforces per-action frequency limits, once for follow, weekly for share, monthly for like, so a customer can’t farm points by re-subscribing.
  • Surfaces every earn event in the customer account history so users can see what they’ve earned and why.

This is the module that made the Premium Club feel like a program and not a checkout coupon.

2. Historical-order migration script

Holzkern had years of order history before the Premium Club launched. The brief asked that loyal customers retroactively receive points for those orders, including guest orders later associated with a registered account by email match.

We wrote a one-time migration script that:

  • Walked every order in the catalog.
  • Matched each order to a registered customer by email, including guest orders that registered later.
  • Calculated the correct points payout per order at the Premium Club’s earn rate.
  • Wrote each calculation as a discrete points-ledger entry tagged “historical migration”, so it could be audited or rolled back.
  • Migrated 100% of historical orders into the new ledger at go-live.

This was a one-shot job, but the design discipline (every entry traceable, every batch rollback-able) is what made it survive the partial-refund bug we hit days later.

Holzkern earn-actions panel listing point-earning tasks like newsletter subscribe and Instagram follow
Earn-actions UI on Holzkern, powered by the custom onsite-action module

3. Partial-refund logic module

Three days after go-live, support reported points balances that did not match expected calculations. We traced it to partial refunds: the base extension was clawing back the full points payout for an order any time any line item was refunded, regardless of how partial the refund was. A customer who returned one item out of three was losing all their order points.

We rewrote the points-deduction logic to:

  • Calculate the correct point claw-back per refunded line item, not per order.
  • Re-run the calculation against every ledger entry that the bug had touched.
  • Patch every existing balance via a controlled batch correction.

The fix shipped as a permanent module so the same logic applied to every future refund. We also added a guardrail: if the calculation produces a negative ledger balance, the entry is flagged for manual review rather than silently going below zero.

4. Birthday-coupon module

The Premium Club promised a birthday coupon, delivered to the customer account 7 days after their birthday. We wrote a Magento cron-driven module that:

  • Reads the customer’s birthday from the captured profile field.
  • Generates a unique single-use coupon code tied to that customer.
  • Posts the coupon to the customer’s account 7 days after the birthday so it lands when the celebration is over and the customer is back to shopping mood.
  • Expires the coupon on a configurable window (30 days by default) so the redemption window is deliberate.

What we wanted to ship and could not

Instagram earn-actions for liking and sharing posts on the Holzkern Instagram account were in the original brief. Instagram’s Graph API doesn’t expose the per-user like or share data that would have let us award points for those actions, and chasing it via scraping would have violated their terms of service and EU data-privacy rules. We removed the Instagram earn-actions from the program at design time, kept the Instagram follow earn action (it uses an OAuth handshake instead of like or share data), and replaced the missing earn opportunities with the birthday capture and WhatsApp recommendation actions. Worth flagging because every loyalty program on Magento bumps into the same Instagram limitation, and the answer is the same: design around it.

🚀 Quick takeaway

The most expensive part of a Magento loyalty build is not the happy path. It is the refund logic, the historical migration, and the social earn-actions you’ll discover you cannot ship the way the brief assumed.

Results and technical outcomes

The Premium Club went live on Magento 2 with all four custom modules, the historical migration completed against 100% of past orders, and the partial-refund bug closed inside the first week.

DeliverableOutcome
Custom Magento modules shipped4 (onsite actions, historical migration, partial-refund logic, birthday coupon)
Historical orders migrated into the points ledger100% via the migration script
Partial-refund calculation bugFound 3 days post-launch, fixed and patched against all prior ledger entries
Earn actions live at launch6 (purchase, newsletter, Facebook, WhatsApp, follow, birthday)
Redemption options live at launch3 (products, coupon codes, exclusive perks)
Birthday coupon deliveryCron-driven, 7 days post-birthday
Engineering deliverables shipped on the Holzkern Magento 2 loyalty program

For the industry context around what a well-designed loyalty program returns: Antavo’s Global Customer Loyalty Report 2026 finds that most brands operating mature programs report a positive ROI from them, and LoyaltyLion’s 2025 Starbucks Rewards analysis shows active loyalty members are roughly 4x more likely to repurchase than non-members during low-confidence periods. The structural reason this works is simple: it costs 5 to 7x more to acquire a new customer than to retain an existing one, which is why retention math drives the case for loyalty at all. None of these benchmarks are a substitute for Holzkern’s own redemption and repeat-purchase data (those numbers belong to Holzkern), but they frame what the build was reaching for.

Holzkern points redemption page showing rewards customers can claim with Tree Rings
Redemption UI: customers can spend Tree Rings on products, coupons, or exclusive perks

🚀 Quick takeaway

The most useful “result” of a Magento loyalty build often isn’t the launch screenshot. It’s the fact that the ledger survived a refund bug without losing a single customer’s points.

Lessons learned: 3 things to check before launching a points program on Magento 2

These came out of the Holzkern build. They aren’t generic loyalty advice. They are the questions you want answered before you sign off on a Magento loyalty plan.

  1. Audit your refund flow before you design your earn rate. Most off-the-shelf extensions claw back points at the order level, not the line-item level. If your store does any partial refunds at all (most do), you will hit this. Decide the policy first (per-line claw-back is the merchant-friendly default), then write the code to match.
  2. Decide what happens to pre-launch order history. A customer who has bought from you for 3 years and signs up to your new loyalty program with zero points is going to feel like a stranger. Migrating historical orders into the new ledger is one of the highest-impact features you can ship, and it costs one script. Tag every migrated entry so you can audit or roll back without touching the rest of the ledger.
  3. Pair the program with email from day one. A loyalty program is a redemption mechanic. It does not sell itself. The customers who actually compound their lifetime value are the ones who get reminded their balance is sitting there waiting to be spent. See the math in our lifecycle email program case study for what the integration looks like in practice.

Loyalty mechanics work best when paired with a clear view of customer lifetime value, because without CLV you reward the wrong cohorts. And if you’re still deciding what model fits your catalog, we’ve catalogued 20+ loyalty program examples by industry for reference before you commit to a structure.

🚀 Quick takeaway

The three questions to answer before you spec a Magento loyalty program: how do you handle partial refunds, what happens to pre-launch order history, and what does the email flow around it look like? The build follows from the answers.

How do you build a loyalty program natively in Magento?

A native Magento loyalty program is built as a custom module on top of either a base rewards extension (Mirasvit, Amasty, or similar) or from scratch. You write the points ledger as a database table, attach earn logic to Magento events (order place, newsletter subscribe, social action), attach redemption logic to cart and quote events, and write a refund handler so points claw-back matches your refund policy. Plan 6 to 10 weeks of senior Magento dev time for a multi-store program with custom earn actions and historical migration.

What does it cost to build Magento-native loyalty vs use an extension?

A Magento-native loyalty build typically runs $25,000 to $80,000 in one-time dev cost depending on earn-action complexity, store-view count, and refund-logic depth. Ongoing cost is whatever your dev team charges for maintenance. A third-party SaaS loyalty widget runs $300 to $3,000+ per month plus transaction fees, with no upfront cost but no equity in the code or data either. The native build pays back over 18 to 36 months for most multi-store brands and is the wrong choice for a single-store catalog without custom checkout. Scope is the deciding factor, not budget.

🚀 Quick takeaway

Native Magento loyalty looks expensive on day one and gets cheaper every year after. A widget is the inverse. Pick the curve that matches how long you’re keeping the store.

When should you skip a loyalty program entirely?

Skip a loyalty program if your repeat-purchase rate is already above 35% without one, if your AOV is below $20 (the points math rarely works at low order values), or if your customer base is mostly one-time gift buyers (think wedding registries or one-shot luxury). Loyalty rewards the second-purchase decision. If there’s no second purchase to incentivize, the program is friction without payoff. Audit your repeat-rate cohorts first, decide if you have a retention problem worth solving, then evaluate loyalty as one of three or four tools you could use to solve it (the others are lifecycle email, retention and loyalty strategies more broadly, and pricing).

FAQ

Can you add a loyalty program to a default Magento 2 install without an extension?

Yes, but it’s the slow path. You’d write the points ledger as a custom module, build the customer-facing account UI in your theme, and write earn and redemption logic against Magento events from scratch. Most teams start from a base extension (Mirasvit, Amasty Rewards, Aheadworks) and customize on top because the base extension’s admin UI, the customer points-history page, and the cart-rule integrations are already there. The customization is the work, and the foundation is reusable.

How long does it take to build a Magento 2 loyalty program?

For a multi-store catalog with custom earn actions, historical-order migration, and partial-refund handling, allow 6 to 10 weeks of senior Magento dev. For a single-store program with order-only earn and no historical migration, 3 to 5 weeks. Add 2 weeks if you want a custom frontend UI rather than the base extension’s stock screens. The Holzkern build sat in the upper half of that range because of the multi-store + historical-migration + Instagram-fallback scope.

Will a Magento loyalty program slow down checkout?

A well-built native loyalty program adds zero to a few milliseconds to checkout because every operation is a Magento event hitting a local database. A third-party widget adds 200 to 800ms per redemption operation because it’s an API round-trip. If checkout speed is a known KPI for your store (and it should be), this is one of the strongest arguments for the native build.

What’s the difference between a Magento loyalty extension and a custom build?

The extension gives you the foundation: a points ledger, an admin UI, a customer points-history page, and basic earn or redeem rules tied to orders. The custom build adds everything the extension doesn’t cover for your specific brand: non-order earn actions (social, newsletter, profile completion), historical-order migration, multi-store rules, custom refund handling, and integration with your specific checkout. Most successful Magento loyalty programs are extension plus custom modules, not pure custom and not pure extension.

Should the loyalty program be visible at checkout or hidden in the customer account?

Both. Customers need to see their balance and the redemption options inside the account area (that’s where the program lives), and they need a points-balance reminder and “redeem available points” toggle at checkout (that’s where the redemption decision happens). Hiding the program entirely at checkout means customers forget they have points. Making the points-redeem flow opt-out by default means you’ll redeem balances customers wanted to save up. The right pattern is visible-but-opt-in at checkout, with a clear running balance.

How do you handle loyalty points when a customer returns a product?

Per line item, not per order. The Holzkern partial-refund bug was caused by the extension defaulting to per-order claw-back, which punished customers who returned one item out of three. The correct logic is: calculate the points earned for the refunded line, claw back that amount from the customer’s ledger, and leave the rest of the order’s points intact. If the claw-back would drop the customer’s balance below zero (they already spent points earned on this order), flag it for manual review rather than silently negative-balance.

If you’re deciding between a Magento-native loyalty build and a third-party widget for your store, the answer usually comes down to checkout latency, store-view count, and whether your refund logic is standard or custom. Talk to our Adobe Commerce team and we’ll walk you through which path fits your catalog, including what we’d reuse from the Holzkern build.

If you enjoyed this post, you may also like