Loyalty
Loyalty programme
A points programme for your online store: customers earn points on every paid order, and, when you switch them on, for a welcome, a birthday and a yearly anniversary. They redeem points as a single-use discount code on your store: a Shopify discount, or a WooCommerce coupon. The balance sits on each contact's page, every movement is recorded, and the AI assistant reads and moves points for you. Part of the Pro and Enterprise plans.
On this page21 sections
- Switch the programme on
- How points are earned
- Redeem a reward for a customer
- Bring the balances from another programme
- Adjust points by hand
- The ledger and the figures
- Points in your emails and segments
- Automations on points
- Language and sender of the loyalty emails
- The widget on your store
- On the Shopify customer account pages
- On WooCommerce
- With the AI assistant and MCP
- Tiers
- Referrals
- Point expiry
- Members and activity
- What this phase does not do yet
In the left menu, Loyalty lists Programme, Rewards, Tiers, Referrals, Members and Activity, and each one is its own page. Programme is the rules. Rewards is what the points buy. Tiers is the levels. Referrals is the invite. Members lists the addresses that have a movement, highest lifetime first. Activity is the ledger.
Switch the programme on#
- Go to Loyalty.
- Under Rules set Points per 1 unit of currency (1 means one point per euro of the paid order, 0.5 one point every two euros) and how Fractions of a point round: Round down or Round to the nearest point.
- Still under Rules, choose What an order counts: Order total, shipping and tax included or Subtotal, the goods alone. Set Welcome points, Birthday points and Anniversary points if you want them. A box left at 0 keeps that bonus off.
- Open Rewards, click Add reward and describe what points buy: a Name, the Points it costs, the Discount (Percentage, Fixed amount or Free shipping), its Value, and if you like an Expires (days) for the code and a Minimum order.
- Set the switch to Programme on and click Save programme. Points start from this moment.
On Rewards, Minimum order has an i beside it. The customer can still spend points and receive the code. At checkout the code applies only when the products in the cart reach this amount. Leave it empty and it applies to any cart.
Still under Rules, Shipping when points bring the cart to zero is The customer pays shipping until you change it. That is what a redeemed code does today: it discounts the products and leaves shipping to pay, even when the products come to zero. A programme that has not chosen stays that way, and a code already given does not change. Choose Shipping is free when points bring the cart to zero and a code minted after you save waives shipping only for that redemption, and only when the products come to zero. It is not a free-shipping reward: while the products still cost something, the customer pays shipping. On WooCommerce this needs the Sendcore plugin 1.4.0. On Shopify the customer enters that one code: it discounts the products, and when they come to zero checkout takes 100% off shipping.
No retroactivity
How points are earned#
- Points are credited when the store reports the order as paid: on Shopify that is the orders/paid event (at capture, for stores that capture payment by hand); on WooCommerce the order reaching Processing or Completed. An order that is placed but never paid earns nothing.
- The amount is the order's paid total, shipping and tax included, unless What an order counts is the subtotal: then it is the goods alone. When the store does not report a subtotal, the total is used. WooCommerce has no subtotal of its own, so Sendcore subtracts shipping and tax from the total.
- Welcome points are given once: when the store creates the customer's account while the programme is on, the first time that customer opens the programme after logging in (the storefront widget, the Shopify account pages, or the WooCommerce Loyalty points tab), or when a contact newly subscribes to marketing email while the programme is on. An import of past customers does not give them, and the same person never receives them twice.
- Birthday points are given every year on the birthday saved on the contact, from a form, an import, or you editing the contact, on the store's own day. The widget does not ask for a birthday. A birthday on 29 February is rewarded on 28 February in a year without a 29th. Points are not an email, so marketing consent does not decide who receives them.
- Anniversary points are given every year on the day of the member's first movement (a first order, the welcome points, or a balance brought over with Import balances), never in the year of that first movement. The day is the store's day, the timezone Shopify reports. A WooCommerce-only store uses UTC. A day the programme does not reach is not made up later.
- A refund takes points back in proportion to the refunded amount (a full refund takes them all); a cancellation takes back everything the order earned. Neither can take back more than the order credited, and the balance never goes below zero: points already spent on a reward are not turned into a debt. On WooCommerce a partial refund, while the order stays Processing or Completed, takes its share. An order marked Refunded applies each refund it lists; with no list, it takes back everything the order earned.
- Every order is counted once, however many times the store resends its events.
- Points are kept by email address, the same one the contact has in Sendcore, so a customer who checks out as a guest with the same email keeps one balance.
A new subscriber to marketing email joins the programme while it is on. Joining is the same welcome the programme already gives: once per email, including the welcome points when they are greater than zero. It is not a purchase. People who were already subscribed are not added by this change. Neither is a customer your Shopify store already had as subscribed who fills in a form. An import, a CSV or a sync is not a new subscription. Someone who unsubscribed stays unsubscribed, and someone already in the programme is not credited twice.
Earning rules#
Under Rules on Loyalty, Earning rules is one list. Click Add rule and choose Order or Collection. An order rule looks at the order total, a product tag or a collection, then gives fixed points, a multiplier, or excludes the tagged items. The last order rule that matches is the one that counts, and a tag matches exactly, capitals included. A collection bonus gives extra points per currency unit, or a flat number of points per item that replaces the base rate for those items, in the collection or outside it. Bonuses in the list stack. Each rule can start and end on a date. The collection on a rule is the store's list, in alphabetical order, narrowed by Search for a collection…. With no rules, an order earns the programme rate, and the tier multiplier still applies after the rule.
Where a tag or a collection comes from
Redeem a reward for a customer#
Open the contact from Audience → Contacts: the Loyalty points card shows the balance and the last movements. Pick a reward under Redeem a reward for this contact and click Redeem. Sendcore debits the points and creates a discount code on your connected store with the reward's value and expiry; the code appears in the card with a Copy button. When the workflow Your discount code is on, the customer also receives the email with that code, from this button, from the storefront widget and from the Shopify profile. While the programme is on and that workflow is not, a bar at the top of the dashboard links to it. With the workflow off, send the code yourself.
- The code is single use and is not tied to the customer's store login, so whoever enters it at checkout uses it: hand it to the right person. The same rule applies to the codes the email Discount block mints.
- A reward a contact cannot afford is greyed out. The programme must be on to redeem.
- Redeeming needs a connected store. On Shopify the code is a discount; on WooCommerce it is a coupon restricted to the customer's email. An account with both stores mints the code on Shopify, the same store the email Discount block uses.
- A redemption is a movement like any other: the ledger keeps the code and the reward, and the points are gone. To give them back, adjust by hand and void the code: under Discounts in the Shopify admin, or under Marketing → Coupons in WooCommerce.
- The Discount can be a Free product. Where you choose the product, What is free is One product or A collection. One product mints a single-use code for 100% off that Product. A collection is a Shopify collection or a WooCommerce category, chosen in Collection: every product in it costs the same points, except the ones you leave out. The customer picks which remaining one at checkout, and the code takes 100% off one item from it, not every item, and never an excluded product. The points are spent once, when the code is redeemed, the same as a single product. Sendcore does not place an order. Code prefix is optional letters or digits in front of the code. Combines with other discounts left on is the usual code, which combines with product discounts; switch it off and the code combines with nothing. The widget describes a product as 100% off the product name, and a collection as 100% off one product from the collection name.
A collection, and the products left out#
On Rewards, with Discount set to Free product and What is free set to A collection, you choose it in Collection. The list is the connected store's, in alphabetical order: a Shopify collection, or a WooCommerce category. Search for a collection… narrows the list as you type. Choose a collection… is the row until you pick one. There is no field for pasting an id. The programme keeps the id of the collection you pick, so a programme that already saved one still finds that collection.
Once the collection is chosen, Exclude products lists its products. Search for a product narrows that list as you type, and the page does not reload. The checkbox beside a product takes the whole product out of the gift: none of its variants receive it, and the rest of the collection still does. Variants, the chevron on the row, opens that product's variants. The checkbox beside a variant takes only that variant out: the other variants of the same product still receive the gift. Clearing the product's checkbox puts the product and its variants back. When only some variants are left out, the product's checkbox is mixed. The exclusions belong to the programme, on every store.
An excluded product stays at full price
Bring the balances from another programme#
Coming from Glow, Smile, Yotpo or a spreadsheet, your customers already hold points. Open Loyalty and find Import balances.
- Click Upload a file and choose the CSV, or the zip that contains it. The button shows a loader until the file window opens.
- A window opens. While the file is read, and again while the import runs, the window shows a loader.
- The window then says how many contacts will receive how many points in all, and how many rows were rejected. Click Import the balances to write them, or Cancel to close the window and write nothing.
- You can close the page. Open Loyalty again: Import balances shows Import in progress and how far it has got, or that it has finished.
The file has an email column and a points column named points, balance or point_balance (a note column is kept too). With no header, the address and the points are the first two columns. A Glow export also has lifetime_points: that is the lifetime total tiers use, and point_balance is the balance the customer can spend. They are not the same number.
- Every balance becomes one credit in the ledger, on the contact's email. When lifetime points are higher than the balance, a second movement records what was already spent, so the tier follows the lifetime total and the customer still sees the balance.
- A customer who is not yet a contact is created with no marketing consent. Being in the file is not consent, and nobody is resubscribed. A contact who was already here keeps their marketing consent, and their name is left as it was.
- The same file imported twice does not double anything, and an import that stops half-way continues where it left when you import the same file again.
- You can close the page while the import runs. It carries on. Opening the same file again does not add the points a second time. If it stops, click Continue: points already written are not counted twice. A file over 64 MB is refused, and the window says The file is too large..
- A row with 0 points and no lifetime writes nothing. A row with a balance of 0 and a lifetime above 0 is kept, so the tier is right and there is nothing to spend. A row whose address or points cannot be read is rejected and named by its line number; fix the file and import again, only the fixed rows are added.
- The old programme's history (what each customer earned when) is not imported: the customer starts here with the balance they had, and the lifetime total the file states.
Accepted separators and numbers#
Save the file as CSV. The columns can be separated by commas, semicolons or tabs. Sendcore recognises the separator from the first row, so a file saved by Excel in Italian, which uses semicolons, is read as it is. A cell in double quotes can hold the separator itself, for example a note with a comma in it.
Points are whole numbers. Write them the way your spreadsheet does:
1250reads the same in every file. It is the safe way to write points.- Italian:
1.250is one thousand two hundred and fifty, and1.250.000is one million two hundred and fifty thousand. A comma marks the decimals, as in1.250,50. - English:
1,250is one thousand two hundred and fifty, and a dot marks the decimals, as in1250.50. In a file separated by commas the number goes in quotes,"1,250": without them the comma splits it into two columns, and the row is rejected because it has more columns than the header. Excel adds the quotes for you. - Which of the two a file uses comes from its own numbers:
1.250,50can only be Italian and1,250.50only English. When every number could be either, the separator decides: a file with semicolons is read the Italian way, a file with commas the English way. - A balance with decimals (
1.250,50or1250.50) is rejected: points are whole numbers. - A rejected row is named by its line in the file, counting the header and any blank line.
A number that reads two ways is rejected
1,250 in a file with semicolons (1250 or 1.25), 1.250 in a file with commas, either one in a file separated by tabs. The window names those lines and never cuts the number down to 1, and Accepted separators and numbers opens this section. Write the points without dots or commas (1250) and import the file again: only the fixed rows are added.Adjust points by hand#
Open Loyalty → Members. On the customer's row, Actions (the three dots) opens Adjust points: a window for that customer. Choose Add or Remove, enter the Points, and if you like a Note (Note (optional)). Record writes the movement. Add credits those points. Remove takes them away. If you remove more than the customer has, the balance does not go below zero: the movement is not written and the points stay as they were.
The same movement is on the contact's card, Adjust points by hand: a welcome gift, a contest prize, a correction, a reward for orders placed before the programme existed. It is one ledger. The row is a Manual adjustment, with the customer, the points, the time and the note when you wrote one.
The ledger and the figures#
Loyalty shows the programme's figures (Contacts with points, Points outstanding, the liability you carry, Points credited and Points redeemed all time) and the last 50 movements across every contact: Earned on order, Reversal, Reward redeemed, Manual adjustment, Welcome points, Birthday points, Anniversary points, each with the order, the amount, the code or the note behind it. The balance is always the sum of the movements, never a counter that could drift.
The same movements show on the contact's own page: in Contact activity (Audience → Contacts, then the contact), earned loyalty points appears next to the visits and orders with the points credited and the balance they made, and unlocked a loyalty reward names the reward that came within reach. Balances brought over with Import balances are not movements of this kind, so they leave no line there.
Points in your emails and segments#
In the email editor, the Personalization list of a text block offers three tags: {{ loyalty.points }} (the recipient's balance), {{ loyalty.next_reward }} (the reward they are closest to, e.g. “10% off”) and {{ loyalty.points_to_next_reward }} (what is missing for it). Add elements → Loyalty points drops a ready-made block that uses them, which you edit like any text. A contact with no points reads 0, so write a fallback where it matters: {{ loyalty.next_reward | "your first reward" }}.
In segments, the Loyalty points rule under Computed traits selects contacts by balance: at least, at most or between two values. Together they make the classic loyalty emails: “you are 50 points from free shipping” to everyone between 250 and 299, or a reminder to the customers who can already redeem.
Automations on points#
Two workflow triggers follow the programme, so the reminder goes out by itself at the right moment. Earned loyalty points starts every time points are credited (a paid order, a manual credit); with its filter Points to next reward at most N it writes only to the contacts close to a reward. Reward available starts when the balance reaches a reward the contact could not afford before. The ready-made workflows A few points away and A reward to redeem on Automations → Create workflow come with the email written; see Loyalty points in automations for the tags and the details.
The workflow Your discount code, on Automations → Create workflow, emails the code the moment a customer redeems a reward from the storefront widget or the Shopify profile, and from Redeem on the contact. {{ event.code }} is the code, {{ event.reward_name }} the reward, {{ event.expires_at }} the date the code expires (year-month-day; empty when the reward has no expiry), {{ event.balance }} the points left and {{ event.reward_points }} what the reward cost. It also reaches people who are not subscribed. While the programme is on and this workflow is not started, a bar at the top of the dashboard says so and links to the workflow, or to the preset when you have not created it yet. The bar stays hidden when the workflow is already on, and when the programme is off.
An import starts no automation
Language and sender of the loyalty emails#
The loyalty workflows, Your discount code included, create their email like every other email in Sendcore. It is written in the language you use Sendcore in, Italian or English, and that is also its Language. It goes out from your Default sender in Settings → Domain: its Sender name and Sender email, or info@ your domain when the sender email is empty. A workflow that Sendcore AI or an agent creates through MCP gets the same sender, and the language most of your emails are written in.
- Open the workflow from Automations and click the email step on the canvas.
- In the email's panel, change Sender name, Sender email or Language. Each field is saved as soon as you leave it.
- To rewrite the text, click Edit content.
- Changing Language does not translate your text. It changes the words Sendcore writes for you, such as the expiry line of a discount code and the footer.
- The Default sender is copied into an email when the email is created. Changing it later leaves the emails you already have as they are.
- A reply goes to the sender email. The email has no separate reply-to address.
No sender, no email
The widget on your store#
The Storefront widget card on Loyalty puts a button in a corner of your store, Shopify or WooCommerce. A customer who is logged in opens it and sees their points, how many are missing for the next reward, the rewards with their cost, and a Redeem button on the ones they can afford: one tap, a confirmation, and the single-use discount code appears with a Copy button, ready for the checkout. A visitor who is not logged in sees the rewards and a Log in link.
- Switch the card On or Off. The switch is saved at once. Then choose the Position (bottom right or bottom left), the Colour of the button, the Language of the copy and, if you like, a Button label of your own. The still under the fields shows the button as the store will draw it. Click Save widget.
- On Shopify, make sure the theme's Sendcore app embed is on (Online Store → Themes → Customize → App embeds): it is the same embed that shows your signup forms. If your forms appear, the widget follows the switch on the next page load. On WooCommerce the Sendcore plugin does the same job: see On WooCommerce below for the version and the key it needs.
- Open your store logged in as a customer: the button sits in the corner you chose. Redeeming there does exactly what Redeem does on the contact's page: the points leave the ledger with the movement marked as the customer's, and the code is minted on the store.
- The widget learns who the customer is from the store itself, never from the browser: on Shopify the store's app proxy tells Sendcore which customer is logged in; on WooCommerce the Sendcore plugin signs the logged-in customer's identity with a key only it and Sendcore hold. Nobody can read or redeem another customer's points.
- The widget shows only while the programme is on, the Storefront widget switch is On, and your plan carries it. Switching the programme off, or the widget Off, hides the button the next time the store page loads.
- A customer without a store account, or one who is not logged in, sees the rewards but no balance: points are tied to the email of their orders, and the login is what proves the email is theirs.
- Redemptions from the widget show in the ledger like any other, so you always see which code went to whom. The email templates can point their button at any page of the store: the widget is on every page.
On the Shopify customer account pages#
Customers who log in to your Shopify store land on the customer account pages (orders, profile). Sendcore adds the points there too, without the widget: a Sendcore loyalty block on the profile page with the balance and the next reward, and a full Loyalty points page with the rewards and Redeem, which works exactly like the widget (a confirmation, then the single-use code with Copy). Shopify itself tells Sendcore which customer is looking, so the figures are always their own.
- In the Shopify admin, open Settings → Customer accounts and make sure customer accounts are on (the new accounts, with a login code by email).
- Click Customize to open the customer account editor. On the Profile page, add the Sendcore loyalty block where you want the balance to show.
- Still in the editor, open the menu (the navigation at the top of the account pages) and add a menu item pointing at the Sendcore loyalty points page. Name it as you like, for example Loyalty points; that is the page with the rewards and Redeem.
- Save. Log in as a customer to see the block and the page. Redemptions from there show in the ledger as the customer's, like the widget's.
- The account pages show the points whenever the programme is on and your plan carries it; they do not need the storefront widget switched on. Switch the programme off and the block says the store has no programme at the moment.
- See rewards on the profile block shows the rewards and Redeem in the block itself. A customer can redeem there without a menu item. Adding Sendcore loyalty points to the menu still opens the same page.
- The copy follows the customer's language in the account pages (Italian or English), not the widget's language setting.
- If the block or the page do not appear in the editor, the Sendcore app is not yet installed on that store, or the app has not been updated since the account pages were added: reinstalling is never needed, updating the app from the Shopify admin is.
On WooCommerce#
On a WooCommerce store the widget and the redemptions work through the Sendcore plugin, from version 1.2.0. The plugin signs the logged-in customer's identity with a key it shares with Sendcore, and a redeemed reward becomes a WooCommerce coupon: one use, the reward's value and expiry, restricted to the customer's email, so nobody else can spend it at the checkout. The same widget can also sit as a Loyalty points tab in the customer's My account area.
- Update the plugin: Settings → Integrations → WooCommerce → Download the plugin, then in WordPress upload the zip over the installed one (Plugins → Add New → Upload Plugin) or replace the folder. Version 1.2.0 or later is what the widget needs.
- Send the key: in the same card, Loyalty widget key → Send key to plugin. Sendcore hands the key to the plugin using the connection you already have; a green line confirms it. If the plugin is too old or the store does not answer, the key appears next to the button: copy it and paste it in WordPress → Settings → Sendcore → Storefront key, then save.
- Switch the widget on in Loyalty as on any store. The button follows the switch on the next page load; a logged-in customer sees their points, a visitor sees the rewards and a link to My account.
- For the tab: in WordPress → Settings → Sendcore, tick Loyalty points tab and save. WooCommerce → My account now has a Loyalty points entry (the address ends in /loyalty-points/) with the balance, the rewards and Redeem inline.
- A coupon is tied to the email the customer logs in with: at the checkout WooCommerce accepts it only for orders with that billing email. Tell customers who use a different address at the checkout to log in with the one they earned the points with.
- The key is per store. Reconnecting the store keeps it; disconnecting and connecting again mints a new one and sends it to the plugin. Until a store has received its key, its widget behaves as for visitors and refuses redemptions.
- Pages cached for logged-in users by a caching plugin can carry a stale identity for a few minutes; the widget then shows the visitor view until the cache refreshes. Most caching plugins do not cache logged-in pages.
With the AI assistant and MCP#
The assistant in the chat bubble, and any agent connected over MCP, has the same seven actions: read the programme and its figures, read a contact's balance and what they can afford, configure the programme, adjust points with a note, set or clear one contact's multiplier (set_loyalty_multiplier), import balances, and redeem a reward (which returns the code). Every write can be previewed first, and every write is recorded like the other agent actions. Team members get the actions their role allows: configuring the programme needs the settings permission, redeeming, adjusting and the multiplier the audience permission.
Tiers#
On Tiers each level has a name, the Lifetime points it takes, a Multiplier and a colour. Lifetime points are what the contact has been credited, not the balance left after a redemption. The multiplier applies to credits that happen after the contact reaches the level. Changing a level does not rewrite points already given.
On the contact's card, This contact's multiplier replaces the tier when you type a number. Empty means the tier. 0 stops that contact earning. It does not stack on top of the tier.
Referrals#
On Referrals, set Points for the referrer and When they are credited: When the person opens the programme or On their first paid order. Points for the new member are credited at that same moment, on top of welcome points. Reward code for the referrer mints one of your rewards for the person who invited, without spending their points. Minimum purchase still attributes the new member, and an order below it closes the referral so a later order does not pay it. The minimum applies to the first paid order, not to an award at the moment the person opens the programme. Award even when the order earns 0 points is off until you tick it: a paid order that earned nothing (a rule, a member excluded from earning, or a code this programme minted) then still awards the referral. The customer's link is the store address with ?sc_ref= and their code. Each person can be referred once, and nobody can refer themselves. Partner referrals stay in the partner portal.
Point expiry#
Point expiry (months) under Rules is 0 until you set it. From then on, each new credit expires that many months later. Credits already on the ledger do not start expiring. The Points expiring automation writes 14 days before. Points name is the word used in the widget and in {{ loyalty.points_name }}; leave it empty for “points”.
Members and activity#
Members lists up to 500 addresses that have a movement, the ones with the most lifetime points first: balance, lifetime points, tier, a multiplier override and the Referrer when someone invited them. Search narrows the list as you type, without reloading the page, and finds any address in the programme whose email contains the text, including one that is not among those 500. Activity is the ledger, filtered by email or by kind of movement. Export CSV downloads the 500 addresses with the most lifetime points. Importing contacts stays in Audience. Importing point balances stays under Import balances on Loyalty.
An order paid with a discount code this programme minted does not earn points. A reward can be switched off with Reward on, and limited to tiers. With no tier ticked, every tier can redeem it.
What this phase does not do yet#
- The Shopify customer account pages show the points, the tier and the referral code; there is no block in Shopify's checkout, order status page or POS yet.
- A free-product reward does not place an order, whether it points at one product or at one item from a collection. It is not an amount the customer chooses point by point.
- A code that is minted but never used does not give the points back on its own.