The Quiet Five‑Year Thank You: A Loyalty Playbook for Shopify Apps
A detailed journey for Shopify and e‑commerce apps to quietly recognize five‑year customers in Spreeflo, using cyclic triggers, VIP splits, and founder‑style emails to reduce long‑tenure churn and deepen loyalty with high‑LTV merchants.
Industry
Niche
Pattern
Loading sequence...
Every quarter, Lina, co‑founder of CartWizard, pulls a revenue report.
One tab shows the shiny stuff: last month’s installs, trial conversion, net new MRR. Another shows a less glamorous list: stores that have paid CartWizard $79 every month for more than five years. No drama. No feature requests. Just quiet, consistent revenue.
Those merchants have contributed north of $4,700 each. Yet the only “special” treatment they’ve ever seen is the same onboarding and Black Friday blasts everyone else gets.
No wonder long‑tenure churn feels like a punch in the gut. When one of those logos uninstalls, it’s rarely about price. It’s the slow erosion of relationship. They stopped feeling seen.
The sequence at the top of this page is the whole journey, end to end. It’s a simple, date‑driven automation that spots five‑year customers, treats them differently from ordinary anniversaries, and does it in a quiet, bespoke way that feels like you remembered them personally.
This article walks through that journey node by node, explains why each piece is there, and shows how to adapt it for your own Shopify app or e‑commerce tool.
Why multi‑year customers deserve their own play
If you run an app on the Shopify App Store or a headless e‑commerce stack, your economics are straightforward:
A modest $49/mo customer who sticks around for 5 years is worth almost $3,000 in ARR.
Losing one long‑tenure account can cancel out a cluster of fresh installs.
The merchants who stay that long are often the ones who refer you, survive platform changes, and take your beta features seriously.
But most lifecycle marketing treats them exactly the same as a customer in month 6.
You might already have:
A generic “happy 1‑year with us!” email.
Usage nudges.
Launch campaigns.
Those are fine, but they don’t acknowledge tenure. After a while, the relationship feels one‑sided: they keep paying, you keep promoting.
This pattern fixes a specific leak:
It captures a bit more detail: how long a customer has been with you, which “loyalty tier” they’re in, whether you’ve already recognized them.
It uses that detail to send a single, bespoke, low‑key thank‑you at the multi‑year marks that actually matter.
No confetti GIFs. No “everyone gets 10% off” voucher. Just a smart, founder‑ish check‑in that says: “We know you’ve been with us for a long time. That matters.”
For founder‑led SaaS, this is how you stop leaving long‑term lifetime value on the table.
The data you need before you build anything
This journey only works if Spreeflo knows who your long‑time customers are.
For a Shopify or e‑commerce app like CartWizard or ShopMetrics, you typically already track:
First installation or first payment date.
Current plan or monthly spend.
Whether the app is still installed.
Primary contact email for the merchant.
You want to get a couple of those into Spreeflo as contact attributes so you can segment on them:
billing_started_at(TIMESTAMP) – when they first became a paying customer.loyalty_tier(TEXT) – e.g."3y","5y","7y", updated in your own system when they cross each threshold.loyalty_5yr_recognized(BOOLEAN) – whether you’ve already sent the five‑year recognition touch.
You can sync these from your billing database or app backend using the Spreeflo API. A daily cron that recalculates tenure and updates loyalty_tier for each customer is more than enough.
One constraint to keep in mind: the Update Contact Attribute action inside journeys writes static values that you configure ahead of time. It can increment numbers or set timestamps to “now”, but it can’t derive dynamic values from event payloads. That is why you compute loyalty_tier in your own system, then push it in via the API.
Once that’s in place, you’re ready to wire the actual recognition.
Step 1: A Cyclic trigger that only wakes up loyal, emailable customers
Pattern: Date‑based scan for loyalty tier
Node: Cyclic trigger
At the top of the sequence is a Cyclic trigger.
Configuration:
Run every day at a quiet hour in your main customer timezone (for example, 09:00).
Re‑enrollment enabled.
Then use the embedded segment builder to define who gets picked up on each daily tick:
Email Subscription Status is
Subscribed.Segment Membership is member of segment
Active subscribers(your own saved segment that excludes churned / uninstalled accounts).Contact attribute
loyalty_tieris"5y".Contact attribute
loyalty_5yr_recognizedis false OR is blank.
Why a Cyclic trigger rather than a Custom Event?
Loyalty is fundamentally about time. A daily sweep is robust (and easier to reason about) than trying to track an exact anniversary moment.
When a customer crosses the five‑year mark and your backend updates
loyalty_tierto"5y", the next day’s Cyclic run picks them up automatically.With re‑enrollment turned on, the same journey can later be reused for a seven‑year tier, as long as you protect each tier with its own recognized flag.
This trigger is the gatekeeper. Only active, opted‑in, unrecognized five‑year customers proceed.
If you’ve never built a recurring automation like this in Spreeflo before, the campaigns and journeys overview is worth a quick skim to see how Cyclic triggers behave.
Step 2: Split VIPs from steady‑but‑smaller customers
Pattern: Treat high‑value stores more personally
Node: Multi‑way Split
Not every five‑year customer is equal in revenue terms.
A Shopify Plus merchant paying $299/mo and referring friends should not receive the exact same touch as a hobby store on your lowest plan. Both deserve recognition, but the VIPs justify extra human effort.
Drop a Multi‑way Split node straight after the trigger.
Suggested branches:
Branch “VIP” – condition
monthly_mrr(NUMBER attribute) greater than 199.Branch “Standard” – condition
monthly_mrrgreater than 0.Else branch – catches edge cases where you don’t have MRR data yet.
This uses the same segment builder conditions, just applied inline. Order the branches carefully so someone who qualifies as VIP doesn’t also match a broader condition first.
Why split here?
It keeps the core logic shared: eligibility, tagging, and recognition flags are identical.
You can tune the email tone, sender, and even whether a human gets involved based on real value.
From this split, the VIP and Standard branches follow slightly different micro‑journeys, then rejoin at a Merge node later.
Step 3: VIP branch – cue a personal touch, then a gentle email
Pattern: Human plus automation, not automation alone
Nodes: Send Internal Email → Time Delay → Send Email
On the “VIP” branch, start with a Send Internal Email action.
Configuration:
Recipient: your founder, success lead, or a shared inbox.
Content: a short alert that this store has just hit five years, plus key context (store name, MRR, plan, last feature they adopted).
The goal is simple: give a human the chance to respond personally if they want to. For example:
Record a 2‑minute Loom video saying thanks.
Offer a quick check‑in call.
Ask if there’s a feature they’ve always wished for.
Next, add a Time Delay of 1 day. This spacing does two things:
It gives your team a window to send that personal reply first.
It prevents your automated recognition email from landing in the merchant’s inbox at the same moment as an ad‑hoc human note.
After the delay, use a Send Email node to send the VIP recognition email itself.
A few configuration choices that matter:
Turn on “Send only once”. If the contact ever somehow matches this path again, they won’t get a duplicate.
Use a template built in the email builder that feels like a letter, not a campaign. Plain layout, text‑forward, signed by a real person.
Keep the subject quiet: “Thank you for five years with [AppName]” is enough.
Content‑wise, this is where you lean on the detail you’ve captured:
Reference specific outcomes: “In the last year your recovered revenue grew X%”, or “Most people in your segment use feature Y, but we’ve noticed you rely heavily on Z.”
Offer a small, relevant gesture: a month’s credit, priority access to a beta, or a free strategy review for their niche.
No confetti banners, no discount code screaming “SALE”. This is relationship‑building, not promotion.
Step 4: Standard branch – same respect, lighter touch
Pattern: Automated, bespoke‑feeling acknowledgment
Nodes: Send Email
On the “Standard” branch, you usually skip the internal alert and go straight to a Send Email action.
Differences from the VIP email:
Tone is still warm, but slightly more generic. You probably don’t promise a call with the founder for every $29/mo store.
The gesture might be softer: a curated “best practices we’ve learned from long‑time users like you” guide, or an invitation to a customer‑only webinar.
You still:
Turn “Send only once” on.
Use a template that looks like a personal note, not your regular newsletter.
Anchor the copy in tenure: “You installed [AppName] back in 2019. In SaaS years, that’s a lifetime. We really appreciate it.”
Because the VIP and Standard branches are both simple here, you just point them each into a Merge node afterwards so the rest of the flow can be handled uniformly.
Step 5: Tag, mark as recognized, and optionally record the timestamp
Pattern: Persist what happened for future journeys
Nodes: Merge → Add Tag → Update Contact Attribute
After the branches come together at Merge, you add the housekeeping actions that make this pattern safe and reusable.
Add Tag
Update Contact Attribute – mark the tier as recognized
Optional: record when you did this
Apply tags like:
loyalty-5yr-recognizedloyalty-vip(for the VIP branch only, if you want to differentiate later)
Tags make it trivial to slice these customers in reports, or to build future campaigns that speak directly to “people we’ve already thanked at five years”.
Use an Update Contact Attribute node to set loyalty_5yr_recognized:
Attribute:
loyalty_5yr_recognized(BOOLEAN).Update type: set to
true.
Because the Cyclic trigger only picks contacts where this attribute is false or blank, this write protects you from accidentally re‑emailing someone if your backend ever glitches loyalty_tier or replays data.
If you want to know when you last ran a loyalty touch, add another Update Contact Attribute node:
Attribute:
last_loyalty_recognition_at(TIMESTAMP).Update type: Set to now.
That timestamp lets you build analytics segments like “five‑year recognized customers who churned within 90 days” and is also handy if you decide to add a “two years since we thanked you” follow‑up later.
After these actions, the journey for that contact ends. They fall out of the flow until they qualify for another tier.
Guardrails: how to avoid awkward or spammy moments
A small flow like this can do damage if you don’t think through edge cases. The sequence at the top of this page includes a couple of implicit guardrails; here’s what to watch for.
Respect unsubscribes and consent
Don’t fire for churned or trial‑only accounts
Watch re‑enrollment rules if you add more tiers
Avoid stacking this on top of hard promos
The Cyclic trigger’s criteria already checks Email Subscription Status is Subscribed. That ensures you never pull someone who has opted out into a recognition email. Keep this rule in place even if you’re tempted to treat this as “transactional”.
Use Segment Membership in your criteria so you only reach actual long‑tenure paying customers, not someone who re‑installed briefly or bounced around trials.
If you later introduce three‑year and seven‑year recognitions in the same journey, you’ll add more Cyclic triggers with different criteria (e.g. loyalty_tier is "3y" and loyalty_3yr_recognized is false). In that case:
Set Re‑enrollment to on for each Cyclic trigger.
Make sure each tier has its own boolean flag, so someone who has already been through the three‑year path can still enter the five‑year path later when they qualify.
If you’re running a heavy sales campaign, you may not want a heartfelt “thank you” email landing in the same week for the same customer. The easiest fix is an extra If/Else right after the trigger:
Condition: Email Activity “opened at least 1 marketing email in the last 7 days”.
“Yes” branch: Add a tag like
loyalty-5yr-deferredand end.“Else” branch: continue into the main flow.
That way, your recognition touch lands in a quieter inbox moment.
Adapting the play for other milestones and channels
The pattern you see here is built for the five‑year moment, but it generalizes cleanly.
Three‑year gratitude: Same structure, lighter gestures, possibly skipping the VIP split if your ARPU is more uniform at that age.
Seven‑ or ten‑year “inner circle”: You might reverse the order – a fully personal note first, then a more structured offer only if they respond.
Plan upgrades: Instead of tenure, key off a
planattribute and use similar recognition when someone has been on your top tier for a long stretch.
You can also introduce other channels, but be deliberate:
Web push notifications require the Professional plan and tend to feel more urgent, so they’re rarely right for something as intimate as a loyalty thank‑you.
A Webhook node (also Pro‑only) can be powerful here: you could ping a Zapier endpoint that drops a “Send handwritten postcard” task into your ops system, or post into a private Slack channel when a five‑year VIP is recognized. If that’s interesting, check how this fits into Spreeflo’s pricing plans before you design around it.
The core stays the same: a recurring scan for a specific kind of tenure, a split by value, a quiet email, and permanent markers so you know who you’ve thanked.
Measuring whether this actually moves the needle
Because every step in this journey adds tags and updates attributes, you don’t have to guess.
You can use the segment builder and your app’s own metrics to answer questions like:
How does churn over the next 6–12 months compare between five‑year customers you’ve recognized vs those you haven’t yet?
Do recognized customers click through to new‑feature announcements or upgrade offers at a higher rate?
Are VIPs more likely to respond when the founder personally replies to the recognition email?
For a team shipping fast on limited time, this is where the compounding benefit shows up. You design the journey once, run it quietly in the background, and watch a specific slice of high‑LTV customers behave differently.
The bigger idea: loyalty is data plus small, consistent gestures
Founder‑led SaaS companies usually obsess over acquisition. ASO rankings, install rate, trial conversion curves.
But the healthiest revenue lines for Shopify apps and e‑commerce tools are often the least noisy ones – merchants who just keep paying, month after month, for years.
Capturing detail on those customers – when they started, how much they spend, which tier they’re in, whether you’ve ever thanked them – is what lets you speak to them uniquely. Not with a giant VIP “program”, but with a few well‑timed gestures that acknowledge the relationship.
Most businesses simply don’t bother. They rely on generic campaigns and hope tenure takes care of itself. That’s the lifetime‑value leak this pattern closes.
The sequence at the top of this page is not complex. A Cyclic trigger, a split, a couple of emails, some tags, and a flag. But for a small team running a serious app business, it’s the kind of automation that quietly compounds: fewer painful “why did they uninstall after five years?” moments, more merchants who feel like you actually noticed they stayed.
Set it up once, wire your tenure data into Spreeflo, and let it run. Your long‑time customers are already holding up their side of the relationship. This is how you hold up yours.