Building Customer Loyalty via Apps

A customer visits once, leaves happy, and never returns. Not because the service was bad, but because nothing gave them a reason to choose you over the shop next door. A well-desig...

Building Customer Loyalty via Apps

A customer visits once, leaves happy, and never returns. Not because the service was bad, but because nothing gave them a reason to choose you over the shop next door. A well-designed loyalty program provides that reason and tells you who your best customers are and who is quietly drifting away.

Many programs fail because the rules are confusing, rewards feel out of reach, or the economics eat the margin. This guide covers how to design one that is healthy for the business, easy for customers, and simple to implement in an app.

Pick a Goal Before Writing Rules

Choose one primary goal for the first three months:

  • Drive the second visit: many first-timers, few returners.
  • Increase frequency: customers return, but not often enough.
  • Raise basket size: regulars who spend little each time.
  • Win back lapsed customers: a long list of people who stopped coming.

The goal shapes the rules. To drive a second visit, a bonus on the second purchase beats a platinum tier that takes a year to reach.

Choosing a Program Model

ModelHow it worksBest forRisk
Digital punch cardBuy 9, get 1 freeCoffee shops, barbers, laundriesGets stale over time
Points per spend1 point per $1 spentRetail, restaurants, online storesCustomers cannot judge point value
Membership tiersSilver, Gold, Platinum by annual spendHigh-value repeat customersComplex, and demotions frustrate people
Paid membershipMonthly fee for perksRecurring servicesMust deliver clear value every month

Small businesses should start with the simplest model that proves whether the program changes behavior at all.

If you add tiers later, base them on a rolling 12 months of spend rather than the calendar year. Customers then do not all drop a tier on January 1, and you can warn them a month before a downgrade so they have a chance to keep their status.

Pricing Your Points Responsibly

  1. Decide what share of revenue you can return as rewards. For example, 2%.
  2. Set the earn rule: 1 point per $1.
  3. Value per point: 2% of $1 = $0.02.
  4. Build the reward menu: a $5 reward costs 250 points, meaning $250 of spend.

These numbers are illustrative only. A low-margin grocery cannot use the same rate as a café. And never design a program that only works because people forget to redeem.

Data Design: Use a Points Ledger

Storing points as a single number on the customer row is fast but makes audits, refunds, and expiry painful. A ledger table, where the balance is derived from history, is safer:

CREATE TABLE point_ledger (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  customer_id BIGINT UNSIGNED NOT NULL,
  type ENUM('earn','redeem','expire','adjust') NOT NULL,
  points INT NOT NULL,             -- positive on earn, negative on redeem/expire
  reference VARCHAR(50) NULL,      -- order number or reward code
  expires_at DATE NULL,
  created_at TIMESTAMP NULL,
  INDEX idx_customer (customer_id, created_at)
);

The balance is simply SUM(points). If an order is refunded, insert a negative adjust row instead of deleting history. That same history answers "why did my points drop?".

Awarding points in Laravel once an order is paid:

public function awardPoints(Order $order): void
{
    $points = (int) floor($order->total);
    if ($points < 1) {
        return;
    }

    PointLedger::create([
        'customer_id' => $order->customer_id,
        'type'        => 'earn',
        'points'      => $points,
        'reference'   => $order->number,
        'expires_at'  => now()->addYear()->toDateString(),
    ]);
}

Trigger it from an event or job when payment status becomes paid, not when the order is created, so cancelled orders never earn points. At volume, move it to a queue as described in Laravel queues and jobs.

Expiring points automatically

Expiry should run on a schedule, not by hand. Register a command in routes/console.php (Laravel 11):

use Illuminate\Support\Facades\Schedule;

Schedule::command('points:expire')->dailyAt('01:00');

The points:expire command finds earn rows whose expires_at has passed and that were not fully used, then writes a negative expire row. Notify customers about seven days in advance; "your points expire soon" is one of the few messages people genuinely appreciate. Make sure cron runs php artisan schedule:run every minute on the server.

Practical Segmentation

  • New: one purchase so far. Focus on the second visit.
  • Active: bought in the last 30 days and more than twice. Recognize them; do not train them to wait for discounts.
  • At risk: used to be regular, absent 45 to 90 days. Send a personal reminder.
  • Lapsed: over 90 days. One targeted offer, then stop chasing.

The day ranges are examples; a business with long purchase cycles, such as HVAC servicing, needs wider windows. A nightly scheduled command in Laravel can recompute each customer's segment automatically.

Notifications That Help, Not Annoy

  • Send only when there is real value: points about to expire, a reward now unlocked, or an offer matched to purchase history.
  • Cap frequency, for example one promotional message per customer per week.
  • Always include an easy opt-out, which privacy rules in many regions require anyway.
  • Respect reasonable hours and time zones.

Common Mistakes

  • Rewards too far away: make the first reward reachable in 3 to 5 visits.
  • Heavy sign-up: a phone number or email at checkout is enough to start.
  • Discount-only programs: mix in experiences like priority service or member-only items.
  • Points as a single number: use a ledger.
  • No measurement: you cannot tell if it works or just costs money.

Measuring Results

  1. Repeat purchase rate over a fixed period.
  2. Average days between visits.
  3. Average order value of members versus non-members.
  4. Reward cost as a share of revenue.

Be careful with conclusions: members are often people who were already loyal. Comparing the same customers before and after joining gives a more honest picture. To turn this into a recurring report, see automating reports with spreadsheets.

Launch Checklist

  • One primary goal for the first three months.
  • Point value derived from margin, not guesswork.
  • Rules explainable in two sentences.
  • First reward reachable within a few visits.
  • Staff trained to enroll customers and redeem points.
  • Expiry policy written down and communicated.
  • Baseline numbers recorded before launch.

If you do not yet capture customer data on each sale, start there. Loyalty depends on it, and some POS apps on GudangCode can serve as a base for adding a points module.

Yudhi
Written by
Yudhi
Founder & Lead Developer, GudangCode

Yudhi is the founder of GudangCode and a Laravel developer who has built dozens of ready-to-use business information systems — from POS and HRIS to management apps. He writes guides and articles on GudangCode to help Indonesian developers run, understand, and deploy Laravel source code correctly.

LaravelPHPMySQLSistem Informasi Bisnis See all articles by Yudhi
Want the full source code & apps?

Sign up free to download ready-to-use business applications, information systems, and Laravel source code.

Sign Up Free & Download
Aplikasi Loyalitas Pelanggan Bisnis & Aplikasi
Share this article
Back to Blog
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Get Full Access Now!

Join our membership and unlock exclusive access to all premium features. Fast, easy, and ready to use instantly.

Join Membership Now