
Personalising your Shopify storefront by VIP tier means reading the customer's tier in Liquid, from a customer metafield where your loyalty app writes one or from customer tags where it does not, and showing a different experience for each one: a gold member sees the sale open now, a silver member sees when their window opens, a guest sees a reason to sign in. It is the point where a loyalty program stops living in email and starts living in the store.
Short answer: your loyalty app writes each customer's tier to the customer record, as a customer metafield, as a tag, or both (Mage does both automatically). In your theme, check customer to see whether they are logged in, then read the tier: customer.metafields.mage.loyalty.value.vip_tier if you use Mage, or customer.tags contains 'vip-gold' as the fallback. Branch by tier with a member fallback and a guest fallback, put that snippet in the sections that matter (announcement bar, PDP, cart, account) and build Shopify customer segments from the same tier data for early access, points drops and bonus campaigns. Metafields are the better option where the app writes them; the tag version comes first below because it is the one most themes already have.
The clip above starts at the point in our customer journey masterclass where Kris walks through this logic.
Why the storefront has to change, not just the email
Most brands that run tiers personalise one channel: email. Silver gets one campaign, gold gets another, and the website looks identical to everyone. But the customer does not experience the brand only through email. They experience it through ads, the storefront, their account and every conversation with support. If the tier only exists in Klaviyo, the customer only feels it in their inbox.
Three things become possible once the tier is visible to the theme:
- Tiered early access. The pattern that is working best right now is early entry to a sale or a drop, staggered by tier: 30 minutes early for tier one, 2 hours for tier two, 24 hours for tier three. That is impossible without the storefront knowing who is looking at it. Our post on early access for VIPs at Black Friday covers the commercial side; this post covers the build.
- Gated drops. A collection or product that is only shoppable by a tier, with a clear "reach gold to unlock this" message for everyone else.
- Different messaging per stage. A guest needs a reason to sign up. A tier one member needs a reason to reach tier two. A tier three member needs to feel recognised. The same hero banner cannot do all three jobs.
This is the step that separates your highest-value customers from customers who are just starting, and it is what makes a VIP feel like a VIP.
The decision flow
Every personalised block on the storefront follows the same logic, so it helps to draw it once.
| Question | Answer | What the customer sees |
|---|---|---|
| Is the customer logged in? | No | Guest experience: a reason to sign in or join |
| Is the customer logged in? | Yes, no tier tag | Member experience: how to reach the first VIP tier |
| Which tier tag do they have? | Tier 1 tag | Tier 1 experience and tier 1 early access |
| Which tier tag do they have? | Tier 2 tag | Tier 2 experience and earlier access |
| Which tier tag do they have? | Tier 3 tag | Tier 3 experience and the earliest access |
The order of checks matters. Test the highest tier first and fall through to the lower ones, so a customer with a higher tag never sees a lower tier's message. Then a member fallback, then the guest fallback. Once the flow is right, every other personalisation on the site is a copy of it with different content.
The Liquid
Shopify's customer object is only available when a customer is logged in, so the outer {% if customer %} doubles as the guest check. customer.tags is an array of the tags on the customer record, and contains does the tier check. Put this in a snippet so you can render it wherever it is needed.
{% comment %} snippets/vip-early-access.liquid {% endcomment %}
{% if customer %}
{% if customer.tags contains 'vip-gold' %}
<div class="vip-banner vip-banner--gold">
Gold members: the sale is open for you now.
<a href="/collections/sale">Shop early access</a>
</div>
{% elsif customer.tags contains 'vip-silver' %}
<div class="vip-banner vip-banner--silver">
Silver members: your early access opens at 8am tomorrow.
</div>
{% else %}
<div class="vip-banner">
Members: the sale opens at 10am tomorrow. Reach Silver to get in earlier.
</div>
{% endif %}
{% else %}
<div class="vip-banner">
<a href="/account/login">Sign in</a> to see your early access window.
</div>
{% endif %}Render it from a section with {% render 'vip-early-access' %}.
Two things to note about the code. It tests gold before silver, so the fall-through order matches the decision flow above. And it has both fallbacks: a member with no tier tag sees the member message, and a logged-out visitor sees the guest message. Leaving either fallback out is the most common bug we see, because the default state is blank and nobody notices until a customer asks why the banner disappeared.
Use the same pattern to gate a collection. On the collection template, wrap the product grid in the tier check and show a "this drop opens for Gold members first" message in the else branch. The collection still exists; it just does not show its products to the wrong tier.
The better option: customer metafields
A customer tag is a string on a list. It can say which tier a customer is in, and that is all it can say. A customer metafield is a typed field on the customer record, so it can hold the tier name, the points balance, the tier expiry date and the next threshold as separate values, and the theme can compare numbers and dates instead of matching strings. Where your loyalty app writes customer metafields, read them; keep tags as the fallback for apps that only tag.
Why metafields win for this job:
single_line_text_field,number_integeranddateare all standard Shopify metafield types, and Liquid returns each one in kind: a string, a number, a date string you can pass to thedatefilter. A tier is text, a balance is an integer, an expiry is a date. No parsing tag names to get a number out.- No tag sprawl. One field per fact instead of a tag per tier, per state and per campaign. There is no naming convention to police, and a tag rewrite by another app cannot strip it by accident.
- Tier, points balance, expiry and next threshold sit on the same record. The cart can say "320 points to Gold" and the account page can say "Gold until 14 March" from the one lookup.
- Customer segments can filter on them. Shopify lets you build a segment from any customer metafield definition of the text, number, date and time, or true or false types, with the filter code built from the namespace and key. A json metafield does not qualify, which matters below.
- They are exposed to the storefront and to Shopify Flow. Liquid reads customer metafields directly, and Flow has an Update customer metafield action, so a workflow can write the field as well as the app that owns it.
What Mage writes
Mage writes one customer metafield, customer.metafields.mage.loyalty, a json value with vip_tier, points_balance, lifetime_points, redeemed_points and status, and a matching shop.metafields.mage.loyalty with the program setup, including the tier list and each tier's points_required. Both are on for every Mage store with nothing to configure, and they refresh when a customer earns or redeems points or changes tier. The full field reference is in the Shopify metafields collection in our help centre.
The Liquid, metafield version
Same shape as the tag version. The outer {% if customer %} is still the guest check, because customer metafields are only available for a logged-in customer. Read the value once, then branch on the tier, highest first.
{% comment %} snippets/vip-early-access.liquid (metafield version) {% endcomment %}
{% if customer %}
{% assign loyalty = customer.metafields.mage.loyalty.value %}
{% assign tier = loyalty.vip_tier | default: '' | downcase %}
{% if tier == 'gold' %}
<div class="vip-banner vip-banner--gold">
Gold members: the sale is open for you now.
<a href="/collections/sale">Shop early access</a>
</div>
{% elsif tier == 'silver' %}
<div class="vip-banner vip-banner--silver">
Silver members: your early access opens in 2 hours.
You have {{ loyalty.points_balance }} points towards Gold.
</div>
{% else %}
<div class="vip-banner">
Members: the sale opens tomorrow. Reach Silver to shop it early.
</div>
{% endif %}
{% else %}
<div class="vip-banner vip-banner--guest">
<a href="/account/login">Sign in</a> to see your early access.
</div>
{% endif %}Three things to note. You compare .value, not the metafield object itself. The default: '' covers a member with no loyalty record yet, so they fall through to the member message rather than a blank. And downcase means the check survives someone renaming the tier from Gold to gold in the app. Because the balance is a number, the same snippet can work out the distance to the next tier: the tier list in the shop metafield carries each tier's points_required, so a loop that finds the first tier above the customer's balance gives you the gap for a progress bar in the cart.
Defining the metafield yourself
If your loyalty app does not write customer metafields, or you want typed fields you can use as segment filters, define them in the Shopify admin under Custom data, one definition per fact in a namespace you control: for example loyalty.tier as single line text, loyalty.points_balance as an integer and loyalty.tier_expires as a date. Then have the app, a Flow workflow or an import write the values. Two access details from Shopify's docs are worth knowing. The Storefronts access setting on a definition controls the Storefront API (custom storefronts such as Hydrogen) and is off by default; it does not affect Liquid, which can read a customer metafield regardless of that setting. And a definition an app creates in its reserved $app namespace is controlled by that app and read-only in the admin by default, so if you want to edit values by hand, use a merchant-owned namespace.
Tags vs metafields
| Customer tags | Customer metafields | |
|---|---|---|
| What it stores | A string on a list | A typed value per field: text, integer, date, json and more |
| Tier | One tag per tier, e.g. vip-gold | The tier name in a text field or json key |
| Points balance, expiry, next threshold | Not practical (a tag per value, rewritten on every change) | Native, and the theme can do arithmetic and date formatting on them |
| Reading in Liquid | customer.tags contains 'vip-gold' | customer.metafields.namespace.key.value |
| Customer segments | customer_tags CONTAINS 'vip-gold' | Text, number, date and true or false definitions can be filters; json cannot |
| Shopify Flow | Triggers and conditions on tags added or removed | Update customer metafield action writes them |
| Failure modes | Tag sprawl, naming drift, other apps rewriting tags | Needs a definition; app-owned namespaces are read-only in the admin |
| Use when | The app only tags, or you need a segment filter fast | The app writes metafields (Mage does), or you need more than the tier name |
Which to use
If your loyalty app writes customer metafields, read them for everything on the storefront. If it only tags, tags work, with the caveats further down. Mage writes both, so the tag stays the key for segments and Flow, and the metafield feeds the theme with the tier, the balance and the status in one read.
Where to put it
The snippet is the same everywhere. The content changes with the location.
Theme section or announcement bar
The most visible spot. Use it for early access windows, sale timing and tier upgrade announcements. This is where a guest gets the reason to sign in and a member gets the reason to reach the next tier.
Product page badge
A small tier-aware line next to the price: what this tier earns on the purchase, whether the product is a VIP exclusive, and for lower tiers, what it takes to unlock it. Product pages are where the purchase decision happens, so this is where "one order away from Gold" does the most work.
Cart
Perks that apply at checkout belong in the cart: automatic free shipping for a tier, a shipping upgrade for the top tier, a progress bar towards the next tier threshold. Showing the perk in the cart, before checkout, is what makes it feel earned rather than accidental.
Account page
The account page is the natural home for status. Show the tier, what it includes, and what the customer is away from the next one. Mage renders this inside the customer account so the tier, points and store credit sit in one place, but the same tag check works in any theme's account template.
Turning tags into Shopify segments
The tags do a second job. Shopify's customer segmentation can filter on customer tags, so every tier becomes a segment you can reuse in the admin and in your ESP without maintaining a separate list. In the segment editor the filter is customer_tags CONTAINS 'vip-gold', and you can save one segment per tier.
Those segments are what run the campaigns:
- Early access. Send the sale link to the gold segment 24 hours before silver, and to silver 2 hours before everyone else, matching the storefront gating exactly.
- Points drops. A bonus points event exclusive to a tier, which is one of the strongest tier two benefits because it requires a purchase to use.
- Bonus campaigns. A higher earning rate for a tier during a launch, announced only to that segment.
- Store-credit drops. A credit issued to a tier as recognition, with a short window to use it.
Segment by tier in email too. The segmentation guide for Shopify email and loyalty covers how the same tier data changes the messaging, from transactional for new members to relational for the top tier. And if you want the tag to trigger something in the admin the moment it changes, Shopify Flow can react to loyalty tags to add a gift, notify support or move the customer into a campaign.
Mage tags and segments automatically as customers move between tiers, so the storefront, the segments and the email all read from the same source. If your current setup is not auto-tagging and segmenting, that is the first thing to fix.
The Shopify loyalty program growing brands trust
See how Mage helps Shopify brands lift repeat purchase rate with loyalty, referrals and store credit.
Book a demoCaveats before you go live
Auto-tagging has to be reliable
The whole system depends on the tag being right. If a customer reaches gold and the tag arrives a day later, they see the silver experience during the one window when it mattered. Equally, when a customer drops a tier at the end of a rolling year, the old tag has to come off. Check that your loyalty app writes and removes tier tags automatically and promptly, and that nothing else in your stack strips customer tags.
Agree a tag naming convention
Pick a pattern, document it, and never deviate. Something like a fixed prefix plus the tier name, in lower case, with hyphens. Liquid's contains on tags is an exact match on the whole tag, so vip-gold and VIP Gold are two different tags. A convention also stops a marketing tag and a tier tag from colliding.
Logged-out customers see the guest version
Liquid can only read the customer object when the customer is logged in. A gold member who is browsing logged out is a guest as far as the theme is concerned. Make the guest state useful ("sign in to see your early access") rather than blank, and make signing in easy. Customer accounts with one-click login remove most of this friction.
Do not rely on a hidden URL alone for a gated sale
Hiding a collection from navigation is not gating it. Anyone with the link can open it, and product URLs can be shared. Use the Liquid check to control what the page shows, and back it with something that holds at checkout: a discount that is only issued to the tier segment, or inventory that is only published when the public window opens. The storefront check is the front door; it should not be the only lock.
Test with a tagged test customer
Create a test customer account for each tier, tag it by hand, and walk the store logged in as each one, plus logged out. Check the announcement bar, a product page, the cart and the account page. Then remove the tag and confirm the experience drops back to the member version. Ten minutes of testing catches the blank-fallback bug before a real customer does.
“I looked into so many different integrations for loyalty and referrals for our Shopify Store, but no one impressed me more than Mage on human connection, customer service, and value.”


Read the Reelie case study →
Where this fits in your tier design
Storefront personalisation only pays off if the tiers themselves are worth reaching. If tier two is set too far above your AOV, nobody sees the gold banner because nobody gets there. Our guide to designing Shopify VIP tiers that drive repeat purchases covers thresholds, rolling windows and what each tier should include. The Shopify VIP tiers feature in Mage handles the tier logic, the tagging and the account display, so the theme work above is the only custom piece.
FAQ
How do I check a customer's VIP tier in Shopify Liquid?
Wrap the check in {% if customer %} so it only runs for logged-in customers. If your loyalty app writes a customer metafield, read it: with Mage that is customer.metafields.mage.loyalty.value.vip_tier, compared against each tier name, highest first. Otherwise test customer.tags contains 'your-tier-tag' for each tier. Either way, add an else branch for members with no tier and an outer else for guests.
Can I build a Shopify customer segment from VIP tier tags?
Yes. In the customer segment editor, filter on customer tags with customer_tags CONTAINS 'your-tier-tag'. Save one segment per tier and reuse it for early access sends, points drops, bonus campaigns and store-credit drops.
Why does a VIP customer see the guest version of the storefront?
They are not logged in. Liquid can only read the customer object for a signed-in customer, so a VIP browsing logged out is treated as a guest. Give the guest state a clear sign-in prompt and make login as quick as possible.
Should I use customer tags or customer metafields for VIP tier personalisation?
Metafields, where your loyalty app writes them. They are typed, they can carry the points balance and expiry alongside the tier, and they do not pile up as tags. Tags are the fallback when the app only tags, and they remain the simplest key for customer segments, because a segment filter needs a text, number, date or true or false metafield definition and a json metafield does not qualify. Mage writes both, so use the metafield in the theme and the tag in segments.
Kris is the co-founder of Mage Loyalty. I spend most days talking to merchants, and making sure our customers get real results. If you run a Shopify store or Agency we should chat!
















