← All guides

Operational deep-dive

Cannabis loyalty program — earn rates that don’t bankrupt the margin

Most cannabis loyalty programs leak margin because the earn rate was set by feel (‘1 point per $’) and the redemption math was never modeled. The customer earns points at retail prices, redeems against retail prices, and the operator absorbs the discount on already-thin margin. Here’s how to run loyalty that holds — what to build, what to avoid, and the audit cadence that keeps the program from quietly turning into a 12% margin haircut.

By CannAgent7 min read

The default-bad earn rate

Most operators ship loyalty with ‘1 point per dollar’ + ‘$10 off when you hit 100 points.’ That math is 10% off every customer’s purchase, applied retroactively. On 30% gross margin, that’s a one-third margin haircut on every loyalty member who redeems. The operator doesn’t see it until quarter-close.

The earn rate that doesn’t leak

Set the earn rate as a percentage of MARGIN, not retail. Two-step calculation:

  1. Pick a target loyalty cost. Doug’s rule at Green Life + SCC: 3% of net revenue, hard cap. That number gets accounted for as a marketing expense, not a cost-of-goods item — it’s an investment in retention.
  2. Back into the earn rate from the gross margin. If gross margin is 30% and target loyalty cost is 3% of net revenue, then redemption-discount-as-%-of-redemption-purchase = 3% / 30% = 10% of the redemption transaction. Translate to earn: 1 point per $1 + redemption at 100 points = $1 off (not $10 off). That’s a 1% discount on each redemption transaction — but at the redemption rate of ~10%, the blended cost equals 0.1% per dollar earned, well inside the 3% cap.
  3. Kill the round-number redemption tiers. ‘100 points = $10 off’ is round, easy to remember, and bankrupts you. ‘100 points = $5 off’ or ‘200 points = $15 off’ both run the math under control. We use 200 points = $5 off at Green Life — the inconvenient ratio is a feature; it slows redemption velocity without telling the customer the system is hostile.

Redemption tiers that protect the basket

The classic loyalty trap: a customer accumulates 1,000 points, walks in to redeem, and the budtender applies $50 off a $52 basket. Customer leaves with $2 of cannabis at a 96% effective discount. Three tier rules that stop this:

  • Cap redemption at a % of the current basket. No redemption can exceed 25% of the pre-discount basket total. $80 basket → max $20 redemption. Forces the customer to keep buying real product to use their points; prevents the ‘$2-of-cannabis-for-points’ raid.
  • Lock redemption to in-store, never online. Online basket is already discount-stacked (delivery, first-visit, online-only deals). Letting points pile on top is a margin compounding event. We allow redemption ONLY at the in-store register where the budtender can see the full basket math.
  • Disable redemption on already-discounted items. If the customer already has industry / heroes / medical / sale discount applied, no points on top. The budtender stops the redemption and the customer chooses one or the other. Stacking is the silent margin killer.
  • Expire points after 12 months of inactivity. A customer who hasn’t shopped in a year isn’t coming back; their 800 points sitting on the books is a contingent liability. Annual expiry on the customer’s account anniversary, with a 30-day-before-expiry email that triggers re-engagement. Doubles as a clean balance-sheet practice.

What the audit cadence catches

  1. Monthly: loyalty cost as % of net revenue. Calculated as (sum of redemptions in dollars) / (sum of net revenue in dollars). Target 2.5-3.0%; alert at 3.5%.
  2. Monthly: redemption velocity per active member. Number of redemptions / number of active members in the month. Sudden spikes signal a stacking exploit or a budtender ringing wrong.
  3. Quarterly: top-redeemer concentration. What % of redemptions came from the top 5% of members? If >25%, the program is rewarding heavy-discount-seekers more than retention. Re-tune.
  4. Quarterly: re-engagement rate from the 30-days-before-expiry email. What % of expiring-points members shop within the email-trigger-to-expiry window? >15% = the program is doing real retention work; <5% = the email is wasted send and the points were already abandoned.
  5. Annual: full earn-rate re-tune. Pull the prior 4 quarters of data; recalculate the blended discount-as-%-of-redemption; adjust earn rate or tier structure to keep loyalty cost inside the 3% cap.

What WSLCB / OLCC / DCC actually care about

  • Loyalty discounts get the same per-transaction audit-log treatment as any other discount. Activity row stamped with discount type, points used, $-discount applied. Per WAC 314-55 family the audit log is queryable on demand.
  • No loyalty discount on already-discounted items where the stack would push effective discount above 50%. Same 50% cap as the industry-discount rule; once the stacked discount approaches that line, the WSLCB starts asking whether the ‘loyalty’ is actually a dressed-up kickback.
  • Loyalty data is customer-level PII. Treat it like any other contact data. Don’t sell, don’t share with brand partners without explicit consent, don’t leak via vendor-portal scoping.
  • Customer can request their loyalty data + opt out. State privacy laws (WA HB 1155 / OR ORS 646A.602 / CA CCPA all apply). Build the export + delete flow before someone asks; CannAgent ships both as one-click admin actions.

Takeaways

  • Default 1pt/$1 + 100pts/$10-off is a 10% margin haircut on every redemption — set earn rate as % of margin, not retail
  • 3% of net revenue is the operator-side cap; back into the earn rate from the gross-margin number; expect blended cost around 2.5%
  • Cap redemption at 25% of basket / lock to in-store / no stacking on already-discounted items / 12-month expiry — these four rules prevent every common margin-leak failure
  • Audit monthly (cost-as-%, velocity-per-member) + quarterly (top-redeemer concentration, re-engagement-rate) + annually (full earn-rate re-tune)
  • WSLCB cares: loyalty discount in the audit log, no stacking past 50% cap, customer can request export + delete — build all three before someone asks

Frequently asked

What earn rate should I set so my loyalty program doesn't eat my margin?
Set the earn rate as a percentage of margin, not retail. Pick a target loyalty cost first (the rule at Green Life and SCC is 3% of net revenue as a hard cap, accounted for as a marketing expense), then back into the earn rate from gross margin. At 30% gross margin with a 3% target, the redemption discount works out to 10% of the redemption transaction, which translates to 1 point per $1 and redemption at 100 points equals $1 off, not $10 off.
How do I stop a customer from cashing in a big points balance for almost-free product?
Cap redemption at 25% of the current pre-discount basket total, so an $80 basket allows a maximum $20 redemption and the customer has to keep buying real product to use points. Lock redemption to the in-store register only, never online where baskets are already discount-stacked, and disable redemption on items that already carry an industry, heroes, medical, or sale discount. Also expire points after 12 months of inactivity, with a 30-day-before-expiry email that triggers re-engagement.
What does the WSLCB actually care about with a loyalty program?
Loyalty discounts get the same per-transaction audit-log treatment as any other discount, with the activity row stamped with discount type, points used, and dollar discount applied, queryable on demand per the WAC 314-55 family. Don't let a loyalty discount stack on already-discounted items to a point where the effective discount pushes past the same 50% cap that applies to the industry-discount rule. Loyalty data is customer-level PII, so build the customer export and delete flow before someone asks, since WA HB 1155, OR ORS 646A.602, and CA CCPA all apply.

Related guides

Ready to talk through your migration?

30-minute demo. We end by quoting the cutover from your current setup — fixed scope, no hourly games.