Magento extensions

Personal coupons your customers can find again

A goodwill code only helps if the customer can find it when they next order. How personal coupons work in Magento 2, and how to put them where customers will see them.

An open customer coupon wallet containing personal discount tickets

Say a parcel arrives four days late. The customer writes in, your team apologises and sends a 10% code by e-mail. Three weeks later she comes back to buy again. The code is somewhere in her inbox, under a pile of newsletters and delivery notices. Either she pays full price and the apology did nothing, or she writes to customer service again to ask for the code, which costs you a second conversation about the same late parcel.

Personal coupons are one of the cheapest things a shop can give, and they are easy to waste. The code exists, the discount is set up, and the only thing missing is that the customer cannot see it at the moment they would use it. This post looks at what Magento 2 does with personal codes on its own, and how to put them in front of the customer in the account, the mini cart, the cart and the checkout.

What Magento does with coupon codes on its own

Magento's cart price rules can generate many codes for one rule. You choose "Specific Coupon", tick "Use Auto Generation", and the rule can produce as many unique codes as you need, each with its own usage limit1. That part works well and you do not need an extension for it.

What Magento does not do is tie a code to a person. A generated code is a code: whoever types it can use it, as long as the rule's customer groups, websites and conditions fit. Expiry belongs to the rule as well. The coupon model in Magento's source marks the per-coupon expiry date as deprecated, with the note that coupon expiration must follow the sales rule's expiration date2. So a code you give one customer today and another you give next month end on the same day, unless you build a rule per batch.

There is also no list of codes in the customer account, and Magento Open Source keeps one coupon code on a cart (the quote has a single coupon code field)3. The customer has to remember the code, find it, copy it and type it into the discount field at the right step.

If you send one shared code in a newsletter to everyone, none of this matters much. Magento's rule is fine for that. It starts to matter when codes are personal: apologies, thank-yous, loyalty gestures, prizes from a promotion.

Giving a customer their own coupon

In our Coupon Wallet module, you still start from an ordinary cart price rule with "Use Auto Generation". The module generates one code per customer on that rule, or assigns an existing code if you would rather hand out a shared one such as a VIP code.

There are three ways to give coupons in the admin. The customer page gets a Coupon Wallet tab with every personal coupon that customer has, and a Give Coupon form: the rule, a reason the customer will read ("Sorry for the late delivery"), the date it is valid until and the number of uses. From the customer grid you can select up to 2,000 customers and give each of them their own code. And there is a CSV import (email,rule,reason,expiry) that checks every row first and shows a preview with errors per row; nothing is assigned until you confirm.

The Give Coupon form on the Coupon Wallet tab of a customer in the admin

Two things happen that Magento does not do by default. The expiry date you set is enforced per code by the shared Promotions core the wallet is built on, so codes given on different days can end on different days. And with the core setting "Only the Owner Can Use a Personal Coupon" (on by default) a customer's code only works in that customer's cart. A code issued to an e-mail address without an account is linked to the account when someone registers or logs in with that address.

An e-mail saying "You have a new coupon" is available but off by default. Whether to send it is your call; the wallet works without it.

Where the customer sees it

The point of the wallet is that the code shows up in the places where the customer is already deciding to buy. My Account gets a My Coupons page with a card per coupon: the discount in words ("15% off orders over £50"), the reason, the code with a Copy button, the expiry date (highlighted when it is close, three days by default) and the minimum basket. The mini cart says how many coupons the customer has. The cart page lists them next to the discount code field with an Apply button, and the checkout payment step shows the same list. Applying a coupon there uses Magento's own coupon request, so totals and payment methods reload as they normally would and all of Magento's own coupon checks still apply.

The customer's coupons on the Luma cart page, with the best one marked

Coupons that do not fit the current cart say why, which saves a support message or two: "Add £12.00 more to use this coupon.", "Not valid for the items in your basket.", or "Expired". Used and expired coupons go into a collapsed history, so the page stays short.

Picking the best coupon for the basket

A customer with three codes usually does not know which one is worth more on this particular cart. Ten percent off and £5 off give different answers depending on the basket, and a code with a £50 minimum is no use on a £40 cart.

The wallet works this out. For each active coupon it calculates the cart totals on an in-memory copy of the cart, then marks the coupon with the highest saving as "Best for your basket" and offers "Apply best coupon". On a tie, the coupon that expires first wins. Nothing is saved and the customer's real cart does not change while this happens. Results are kept for five minutes per cart state, at most ten coupons are calculated per cart by default (you can set 1 to 50), and the calculation only runs where the wallet is shown, not on every page.

The savings shown are estimates for the current cart; Magento calculates the final discount at checkout as it always does. A free shipping coupon has no amount until a shipping method is chosen, so before that it is listed without one.

What it does not do

The wallet is for logged-in customers. Guests can still use their codes, but they type them as usual; codes given to a guest e-mail appear in the wallet once that person registers or logs in. Because Magento Open Source holds one coupon per cart, applying a wallet coupon replaces the coupon already in the cart rather than adding a second one. Coupons given from the grid or by CSV are processed while you wait, which is why there is a 2,000 limit per run. On Hyvä the account page, cart and cart drawer have their own templates, and the checkout uses the Luma checkout fallback; Hyvä Checkout is not supported.

For headless stores there is a REST endpoint and a GraphQL query that return the customer's active coupons with what each would do for the current cart.

The wallet also collects coupons from the other modules in the same family. If you use Next Order Coupon, for example, the thank-you code for a customer's next order appears in My Coupons with its own reason, and the best-coupon logic considers it alongside the rest.

If your personal codes keep ending up unused in inboxes, the Coupon Wallet module page has the full setup and screenshots of each place the coupons appear.

Sources

  1. Adobe Commerce Admin documentation, "Create a cart price rule", https://experienceleague.adobe.com/en/docs/commerce-admin/marketing/promotions/cart-rules/price-rules-cart-create, checked 12 October 2026. ↩
  2. Magento Open Source 2.4.9 source code, app/code/Magento/SalesRule/Model/Coupon.php (expiration date marked deprecated: "Coupon expiration must follow sales rule expiration date"), checked 12 October 2026. ↩
  3. Magento Open Source 2.4.9 source code, app/code/Magento/Quote/etc/db_schema.xml (one coupon_code column on the quote), checked 12 October 2026. ↩

From our shop

Related Products

Keep reading

All posts