How to migrate loyalty points between Shopify apps
Changing loyalty apps is not a settings migration. It is moving a liability — your customers were promised those points, and they will notice the day the balance is wrong. This is the failure mode that ruins these migrations, and the checks that catch it.
The one-line version: loyalty exports contain several point columns, and only one of them is a spendable balance. Import the wrong one and you silently over-credit every customer in your store.
Why the export is the dangerous part
A points program is, underneath, a ledger. Migrating it means carrying one number per customer — the current balance — from one system to another. That sounds trivial, and the tooling makes it look trivial: export a CSV, upload a CSV.
The problem is that the CSV rarely contains one number. A typical loyalty export ships a current balance alongside some combination of lifetime points, points earned, points spent, points pending, points redeemed and points expired. Several of those columns are larger than the balance — often much larger, because lifetime totals never go down. They all look like plausible integers in a column with "points" in the name.
Pick the wrong one and nothing breaks. The import succeeds. The dashboard looks healthy. The error surfaces weeks later, one customer at a time, as people redeem rewards they were never actually owed — and by then the ledger is real and clawing it back costs you the goodwill the program existed to build.
The columns that are never a balance
Treat any column whose name contains one of these as cumulative, and never import it as a balance:
- lifetime — the running total since the customer joined.
- total — almost always lifetime under another name.
- earned — gross accrual, before anything was spent.
- spent / redeemed / used — the opposite side of the ledger.
- pending — points not yet approved, which may still be reversed by a refund or a cancellation.
- expired — already written off.
What you want is the column that means spendable right now: usually named balance, points balance, or in LoyaltyLion's vocabulary, approved points. If your export has no such column, the correct action is to stop and get a different export — not to approximate one by subtracting spent from earned, which will not reconcile once refunds and expiries are in the data.
Identity is the second trap
The balance is only half a row. The other half is which customer, and exports are inconsistent about it.
Match on email. Do not match on a bare customer_id: in a loyalty export that is
the vendor's own internal identifier, not your Shopify customer id, and treating one as the
other attaches balances to unrelated people. Only a column explicitly named as a Shopify id is
safe to use as one.
Then decide what happens to rows that do not match anyone in your store — and they will exist, from deleted customers, typo'd addresses and test accounts. The right behavior is to report them back to you as a list. Silently attaching them to the nearest match is how a migration produces phantom balances nobody can trace.
A pre-flight checklist
- Export the current balance, explicitly. If the export screen offers a choice, this is the only choice that matters.
- Open the file and read the header row before uploading it anywhere. Count the columns with "points" in the name.
- Sum the balance column yourself in a spreadsheet. That figure is your control total — whatever you import should reconcile to it.
- Check for duplicate emails. Decide whether they should sum or whether one is stale.
- Install and configure the new app first — earning rate, rewards, storefront widget — and import balances last.
- Confirm the column mapping the importer chose before it writes anything. If a tool will not show you that, it is asking you to trust it with your customers' balances sight unseen.
- Spot-check five real customers against the old system afterwards.
How TruePoints handles it
TruePoints was built around this specific failure. It reads any CSV with an email column and a current-balance column, and it recognizes Smile, LoyaltyLion and Yotpo exports by their characteristic columns.
- It shows you which column it read as the balance, and which it read as the email, before a single point is written. You approve that mapping.
- It refuses files whose only points column is a cumulative total, naming the column it rejected and telling you to come back with a current-balance export. It will not guess.
- It only trusts a column explicitly named as a Shopify id, and matches on email otherwise.
- It reports the totals up front: rows in the file, rows that will import, points that will be credited, zero balances skipped, duplicate emails merged, and rows it could not parse. Those figures are what you reconcile against your control total.
How TruePoints works covers earning, redemption and pricing, and includes an 84-second demo of the whole loop on a live store.
Questions
Why can't I just import the points column from my export?
Loyalty exports usually carry several point columns: a current balance next to lifetime, earned, pending, redeemed, spent or expired totals. Only the current balance is a spendable liability. Import a lifetime total and every customer in your store is instantly owed far more than they actually have, and you will not find out until they try to spend it.
How do I tell a current balance from a lifetime total?
Read the column name, not the number. Anything containing lifetime, total, earned, spent, pending, redeemed, expired or used is a cumulative figure, not a balance. If your export only offers those, go back to the source app and request a current-balance export before you import anything.
What happens to customers who have zero points?
Nothing needs to happen. A zero balance carries no liability, so there is no reason to create a member record for it. In TruePoints those rows are counted and skipped, and the customer enrolls normally on their next order.
What if the same email appears twice in the export?
Decide deliberately rather than letting the importer pick. TruePoints merges duplicate emails by summing their balances and reports how many it merged, so the total credited always reconciles against the file you supplied.
Do reward definitions and tiers migrate too?
No. Balances migrate; rewards, tiers, referral history and past transaction logs do not, in any loyalty migration. Balances are the part your customers can see and will complain about, so that is the part worth protecting. Rewards are quick to recreate.
Should I run the migration before or after installing the new app?
Install first, configure your earning rate and rewards, then import balances last. Importing into an unconfigured program means your first orders after the switch earn at the wrong rate, and unwinding that by hand is worse than the migration itself.