Free resource · use it on this page
Loyalty Data Mapping Template
A field-by-field map from POS fields to loyalty fields to wallet pass fields, with a privacy weight for every field, so integration design and data minimisation happen in one pass.
How this template works
Loyalty data moves through three layers: the POS (where transactions happen), the loyalty layer (where points, tiers, and members live), and the wallet pass (what the customer carries in Apple or Google Wallet). Most privacy problems in loyalty programs come from copying fields wholesale from one layer to the next. This template forces a decision at each hop: does this field need to move right, and in what form?
Every field carries a privacy weight. W0 is operational data with no link to a person, such as a store ID or a points-per-currency ratio. W1 is pseudonymous data that only means something to someone with access to your loyalty database, such as a member ID, points balance, or tier. W2 is personal data that directly identifies or describes a person: name, phone, email, date of birth, purchase history. W3 is sensitive or high-risk data, such as health-related purchase inferences, precise location history, or payment credentials. The working rule for W3 is simple: it never enters the loyalty layer at all.
The governing rule of the whole template: privacy weight must not increase as data moves left to right. The wallet pass is your most exposed surface. It appears on lock screens, in screenshots, and on phones handed to friends and family. A well-designed pass carries only W0 and W1 fields, plus at most one deliberate W2 field (usually a first name) with a written justification. If your wallet platform supports per-customer fields, as PushNotice does, the wallet pass column below maps directly to the pass template fields you configure there.
Work through the three mapping tables for the standard fields, use the worksheet for anything specific to your POS, and finish with the sign-off checklist before anything ships. The tables are sized to print on a single page each.
Identity and contact fields
The fields most likely to be over-copied. Default posture: these stay in the loyalty layer and almost never reach the pass.
| POS field | Loyalty field | Wallet pass field | Privacy weight | Minimisation rule |
|---|---|---|---|---|
| Customer record ID | member_id (newly minted, opaque) | Serial number and barcode payload | W1 | Mint a fresh opaque ID at enrollment; never reuse the raw POS customer ID in a barcode anyone can scan. |
| Phone number | contact_phone (till lookup key) | None | W2 | Keep it as a lookup key for card-forgotten checkouts; index or hash it, never print it on the pass. |
| Email address | contact_email | None | W2 | Needed for receipts and account recovery; excluded from the pass entirely. |
| First and last name | display_name | Optional holder-name field | W2 | First name only, if shown at all; the pass front is visible to anyone holding the phone. |
| Date of birth | birth_month_day | None | W2 | Truncate to month and day; birthday rewards do not need the year, and age is not yours to store by default. |
| Mailing address | Usually omit; postcode district at most | None | W2 | Only migrate if you physically mail rewards. Otherwise this is dead weight with breach liability attached. |
| Payment card token or PAN | Never migrated | Never | W2 | Card data stays inside the PCI scope of the POS. Loyalty matching uses the member ID, not the card. |
Transaction and balance fields
Where raw POS data gets converted into loyalty state. The conversion point is your best data-minimisation opportunity: convert, then discard.
| POS field | Loyalty field | Wallet pass field | Privacy weight | Minimisation rule |
|---|---|---|---|---|
| Transaction total | points_earned (converted per visit) | None (only the resulting balance shows) | W1 | Convert currency to points at the integration layer, then let the raw total age out under your POS retention policy. |
| Line items / SKUs | Category-level tags at most | Never | W2 | Basket contents can reveal sensitive purchases (pharmacy, alcohol). Aggregate to broad categories or drop entirely. |
| Transaction timestamp | last_visit_date | Optional back-of-pass field | W1 | The date is enough for recency logic. Time-of-day is behavioural data you probably do not need. |
| Store / terminal ID | home_store | Relevant-location coordinates on the pass | W1 | Pass geofencing works by storing shop coordinates on the pass, not by tracking the customer. Document that distinction. |
| None (computed in loyalty layer) | points_balance | Primary field on the pass front | W1 | The headline number. Safe to display because it is meaningless without access to your loyalty database. |
| None (computed in loyalty layer) | tier | Secondary field, or pass colour | W1 | Tier names are fine on the front; tier entry criteria (spend thresholds) stay server-side. |
| None (computed in loyalty layer) | points_to_next_reward | Secondary or progress field | W1 | Derived, non-identifying, and the single most motivating field you can put on the front of a pass. |
| Enrollment date | member_since | Optional back-of-pass field | W1 | Harmless and occasionally delightful; back of pass only. |
Derived and behavioural fields
Fields your loyalty layer computes about people. These are inferences, not facts the customer gave you, so the wallet column is almost always empty.
| POS field | Loyalty field | Wallet pass field | Privacy weight | Minimisation rule |
|---|---|---|---|---|
| Visit history (derived) | visit_frequency segment | Never | W2 | Use it to time campaigns, not to display. Nobody wants their pass to say they come in every day. |
| Transaction history (derived) | lifetime_spend | Never | W2 | Feeds tier calculation only. Displaying spend on a pass surprises customers in the wrong way. |
| Line items (derived) | favourite_category | Offer text only, never the inference | W2 | Show the result, not the profiling: the pass says Free pastry this week, never You buy pastries daily. |
| None (captured at enrollment) | marketing_consent + timestamp + source | Never | W2 | Consent is a logged record, not a flag. Installing a pass is not itself consent to marketing messages. |
| Transaction history (derived) | lapse_risk flag | Never | W2 | Campaign trigger only. If you score people, record that processing in your privacy documentation. |
| Date of birth (truncated) | birthday_month | Optional offer text near the date | W1 | A birthday-treat message on the pass is fine; the underlying date field is not. |
Custom field worksheet
Every POS has fields the tables above do not cover. Copy this block once per custom field and fill it in. If you cannot complete the justification line, the wallet column is None.
Field name and POS source
Exact column, export header, or API path it comes from
Loyalty destination field
Name it as it will exist in the loyalty layer, or write: not migrated
Wallet pass surface
Front / back / barcode payload / none
Privacy weight
W0 operational, W1 pseudonymous, W2 personal, W3 sensitive (W3 = stop, do not migrate)
Why the pass needs it
One sentence. If the sentence will not write itself, the surface is none
Retention period
Per field, not per database; note which layer enforces it
Erased when the member leaves?
Yes or no, plus which system performs the erasure and what happens to the installed pass
Reviewer and date
Whoever owns privacy review signs each field, not just the project
Privacy review sign-off
Run this after the tables and worksheet are complete, before the integration goes live. Every unticked box is a launch blocker or a documented exception.
Every wallet pass field has a written justification
One sentence per field, recorded in the worksheet. Unjustified fields come off the pass.
The barcode payload is an opaque member ID only
Scan your own QR code with a generic reader and look at the raw string. No phone number, email, or POS customer ID inside.
No W3 data exists anywhere in the loyalty layer
Check SKU-derived fields especially: pharmacy, medical, and similar categories can turn W1 aggregates into W3 inferences.
Name and date of birth are truncated as mapped
First name only where displayed; birth date reduced to month and day before it leaves the POS.
Payment data never crosses the PCI boundary
The loyalty integration reads transaction outcomes, not card details. Confirm with the integration owner in writing.
Lock-screen content is reviewed like a postcard
Anything pushed to the pass can appear on a lock screen in public. No balances-owed, no health-adjacent offers, no inferences.
Consent is logged with timestamp and source
Marketing consent is separate from loyalty membership, and someone can produce the record for any given member.
Deletion propagates across all three layers
Test it: delete a member, then confirm the POS mirror, the loyalty record, and the installed pass (revoked or blanked) all reflect it.
Retention is set per field, not per database
Raw transaction data, contact data, and derived segments age out on their own schedules from the worksheet.
Till staff see a lookup result, not a profile
The checkout flow returns membership status and available reward, not spend history or contact details.
Location on the pass is shop coordinates, not customer tracking
Geofenced lock-screen relevance stores your locations on the pass; verify no customer location is collected in return.
Processing records and vendor agreements are updated
The loyalty vendor and wallet platform appear in your records of processing and have data processing agreements in place.
No real customer data was used in staging passes
Test passes carry synthetic members. Real records in a test environment fail the review.
From the guide: POS Loyalty Program: Add Loyalty Without Switching POS
This resource accompanies the full article — worth reading before you commit to a tool.