I build retention programs. This is how they work.
I'm Mohammad Ayub, a CRM and retention specialist with almost five years in iGaming across the India and Bangladesh markets. Everything here runs live in your browser. Change a number and watch the whole thing recalculate. Nothing is a picture of a result. I built it because retention is easier to show than to describe.
Retention, month by month
One reactivation program
Same players, different market
A monthly CRM and promotional budget of INR 2.2 crore, split across messaging, promotions, cashback and retention incentives. Module 09 is that same tradeoff, live, so you can move the money around and watch the return change.
Why I built this instead of writing another case study
A case study asks you to take my word for the numbers. This doesn't. You can regenerate the dataset, change the cluster count, retrain the model, move the budget, and watch what happens. If the thinking is sound it holds up under your hands, not just in my summary of it.
It also answers the question I get asked in every interview, which is some version of "walk me through how you would build a win-back journey." The answer is module 06, and you can run it yourself.
One honest note on the localization in module 07. I use AI heavily in my day to day work, for drafting, translation and analysis. What I've learned running it against real Bengali campaigns is that the output is confidently wrong in specific ways: it defaults to the informal তুমি register when respectful আপনি is correct, mixes Latin characters into Bengali script, and orders reassurance before acknowledgment in a complaint reply, which reads as dismissive to the player. Knowing where the tool fails is the part that took market experience to learn.
Module 03, Predictive and Uplift. Work out who is about to leave, then check whether your campaign actually caused them to stay or whether they would have anyway. Most teams only do the first half.
Module 13, Send Governance. How many messages is too many. The question almost every retention team gets wrong, and the one I get asked about most.
Sidebar, market selector. Switch between India, Bangladesh and Global. It changes more than currency. It rebuilds the cohort with that market's real channel behaviour, because Telegram carries retention in Bangladesh while WhatsApp and SMS carry it in India. Module 07 shows the routing and the copy shifting with it.
AI segmentation groups players automatically
Manual segments only answer questions you already thought to ask. This module groups your players on its own, using their real behavior. It runs a real grouping method called k-means on your cohort's recency, frequency, and deposit value.
How this really works
Optimove and MoEngage both group players automatically on top of their manual rules. The method used here is called k-means. Start with a few random center points, place every player next to the nearest one, then move each center to the average position of its group, and repeat. The groups keep re-forming until the centers stop moving much. At that point they've settled.
Click the button below to run this live, right in your browser, using three numbers for each player: how recently they played, how often they deposit, and how much they deposit. The chart shows how far players sit, on average, from their group's center after each round. That distance should drop fast at first, then flatten out. Once it flattens, the groups have settled.
Real platforms use many more signals, such as session behavior, game preferences, and channel response, and they redo this grouping on a schedule. So a label like "VIP Core" or "Cooling Off" isn't fixed. It's recalculated every night against whoever qualifies that day.
| Segment | Players | Avg. recency score | Avg. frequency score | Avg. monetary score |
|---|
RFM scoring, the classic method
Before there was clustering, there was RFM. Every player is scored 1 to 5 on how recently they played, how often they deposit, and how much they deposit. That three-digit code sorts them into a named segment.
How RFM scoring really works
RFM stands for recency, frequency, monetary value. Instead of clustering players by distance the way module 01 does, RFM ranks every player against everyone else on each of those three measures separately, then splits each ranking into five equal buckets. The player at the very top of recency gets a 5, the bottom gets a 1, and so on for frequency and monetary value. Put the three scores together, like 5-4-4, and you get a code.
Those codes aren't random. Specific combinations get a name. A player scoring high on all three is a Champion. High recency and frequency but low spend is a Loyal Player still building value. Low recency with high past frequency and spend is someone you're at real risk of losing. This is a fixed rulebook, not a learned model, which is exactly why it's still the first thing most CRM teams build: it's fast, it's easy to explain to a room full of stakeholders, and it doesn't need any machine learning to work.
The tradeoff against module 01's clustering is real. RFM's buckets are fixed by definition, always five even splits, while clustering finds however many natural groups actually exist in the data. Most mature CRM teams run both: RFM for the quick, explainable read, clustering for the deeper one.
Each score runs 1 to 5. A code of 544 means top-fifth recency, top-fifth frequency, one step down on spend. Read left to right: recency, frequency, monetary.
| Player | R | F | M | Code | Segment |
|---|
Predictive scoring shows its math
A real prediction model, trained live on this cohort's behavior, plus a test that proves a campaign actually caused a result instead of just assuming it did.
How churn scoring really works
Under the hood, most churn and lifetime-value models work the same basic way. Each signal about a player gets a weight. The weighted signals are added together, then squeezed into a probability between 0 and 1. Training means adjusting those weights until the model's predictions match what actually happened in the past. The method used here is called gradient descent: check how wrong the current guess is, nudge every weight a little in the direction that reduces that error, and repeat this many times.
Click train below and watch the error curve fall. That drop is the model getting better, round by round, at predicting who actually stopped playing in this simulated cohort. It uses four signals: how long since the player last played, how much their sessions have dropped off, how much their deposits have dropped off, and how fast they wager. Once training finishes, each weight tells you how much that signal matters. A large positive weight pushes risk up. A negative weight pushes risk down.
This is what a genuinely explainable score looks like in a CRM tool. Not a number pulled from a black box, but each signal's weight multiplied by that player's own value, shown openly, so you can say exactly why a player was flagged.
How this proof test really works
Here's the trap in most retention reporting. You send a reactivation campaign to 1,000 lapsed players, 80 come back, and someone reports that the campaign drove 80 reactivations. But some of those 80 would have come back anyway, campaign or not. This module fixes that by holding back a random group of players who get no message at all, then comparing how many came back in each group. The difference between the two groups is the campaign's real, proven effect. This is what Optimove calls proving incremental impact, and it's the only honest way to measure what a campaign actually did.
The simulation below splits your at-risk players randomly into two equal groups. The group that gets the message converts more if they're already more engaged on their channels, since a nudge works better on someone who already pays attention. The result shows how many extra conversions are truly caused by the send, not just correlated with it.
LTV prediction estimates what a player is worth
A second model, trained the same way as the churn model, but predicting a number instead of a probability: how much a player is likely to deposit over the next 90 days.
How LTV prediction really works
The churn model in module 03 is a classifier: it predicts one of two outcomes, churned or not, as a probability. This model is a regressor: it predicts an actual number, a dollar figure, using the same weighted-sum idea but without the final squashing step that turns a churn score into a 0 to 1 probability. It looks at a player's current deposit value, deposit frequency, tenure, and recency, and learns what combination of those historically led to higher or lower future spend.
Training works the same way as the churn model: guess, measure the error, nudge the weights, repeat. The one new number worth knowing is R-squared. It runs from 0 to 1 and tells you how much of the real variation in future value this model actually explains. An R-squared near 1 means the model's predictions track reality closely. Near 0 means the model isn't capturing much at all, and you'd do about as well guessing the average for everyone.
The table below shows the model's top-predicted players against what they were actually simulated to be worth. Real platforms only get to check this after the fact, once the next quarter has actually happened, which is exactly why every serious predictive model gets validated this way before anyone trusts it enough to act on.
| Player | Segment | Predicted value | Actual (simulated) |
|---|
Personalization finds the best offer
Five offers, each built for a different kind of player. Every player is scored against all five, and the best match wins, with the reason shown, not hidden.
How next-best-offer really works
This works by matching profiles, not by copying what similar players did. Each offer has an ideal player profile built from five signals: how long they've been lapsed, how often they deposit, how much they deposit, how fast they wager, and how long they've been playing. Every player has that same set of signals. To score a match, multiply each of the player's values by the offer's matching weight, then add those up. The offer with the highest total wins for that player.
The reason shown per player is simply the single signal that contributed the most to that winning score. Optimove's one-to-one personalization and MoEngage's content optimization run on the same basic idea, just with more offers, more signals, and weights the system learns on its own instead of ones set by hand. The core mechanic is still the same weighted match.
| Player | Segment | Recommended offer | Why | Best channel |
|---|
Journeys trigger, branch, and exit
A reactivation journey, triggered by behavior, simulated across your lapsed players. Each player's own channel habits decide whether they open, click, and come back.
I ran this shape of journey against 35,000 dormant accounts and recovered 7,000, a 20% reactivation rate. The thing that made the difference was not the offer size. It was splitting lapsed players by the likely reason they stopped, then matching the message to that reason instead of sending one blanket win-back to everyone.
How orchestration engines really work
A journey is really just a flow of steps: trigger, wait, message, decision, exit. Every player moves through it on their own, based on their own behavior. Here, the trigger is a 14-day deposit gap. From there, a push notification goes out, because it costs almost nothing and reaches anyone who still has the app installed. If the player opens it, they get a short wait and then a soft offer. If they don't open it, or don't come back, the journey falls back to SMS, which costs more but reaches players who have notifications switched off. If that doesn't work either, it escalates to a WhatsApp message from a host, but only for players who clear a value threshold. In production tools this is called channel fallback and frequency capping: a hard limit on how many times someone gets contacted, with the more expensive channels saved for the players worth the cost.
Run the simulation and watch the funnel below. Each player's own channel habits, the same numbers shown in the heatmap in module 05, decide their own path. So the funnel changes with who's actually in the cohort, not just with the trigger you set.
Omnichannel routing and live content
Each player's own channel habits decide where a message goes. Merge tags decide what that message actually says, and the market you pick in the sidebar decides both the language and which channels actually perform.
Localization here is written the way CRM teams in these markets actually write, not as formal translation. That distinction cost me real corrections to learn: respectful আপনি rather than informal তুমি, Bengali script with no Latin characters mixed in, digits rather than spelled out numbers, and acknowledgment before reassurance in any complaint reply. Get that last one backwards and a correct answer still reads as dismissive.
How channel routing and dynamic content really work
Reaching every channel doesn't mean sending on every channel. It means picking the one channel each player actually responds to, based on their own history, so someone who only ever replies on WhatsApp isn't chased through four other channels first. The heatmap below is that raw data: a score between 0 and 1 for each channel, for each player. This is the same kind of table a real channel-optimization model reads from.
Dynamic content works the same way in every CRM tool. A message template holds placeholders like {{first_name}}, and at the moment it's sent, the platform swaps each placeholder for that specific player's own data, including data calculated live, like the recommended offer from module 05. Pick a player below and watch the message rewrite itself with their real details.
The preview below is also localized to whichever market is selected in the sidebar. This isn't a straight translation. Real CRM teams in India and Bangladesh write the way players actually message each other: mostly English, mixed naturally with everyday Hindi or Bengali, with offer names left in English because that's how they show up in the product. Switch to the in-app inbox and you'll also see a title line appear, and switch to SMS or push and the same message gets shorter, because those channels charge per character or per notification and a real team writes for that limit.
Channel performance is not the same in both markets, so switching the sidebar rebuilds the cohort. In Bangladesh, Telegram is the channel that carries retention. Players are already in group chats there, and a message lands in a place they check. In India, WhatsApp and SMS do that job instead, with SMS still pulling weight because it reaches players regardless of app or data state. Push and the in-app inbox perform well in both, which is why they anchor the early, cheap steps of any journey. Switch the market above and watch the routing table and the ROI split move, because a channel plan that works in Dhaka is not the plan that works in Mumbai.
One deliberate omission: there is no email channel here. Email is a default in most CRM tooling and most Western retention playbooks, but in these markets it barely moves anything. Players sign up on mobile, many without an email they check, and the conversation lives on Telegram and WhatsApp instead. Running an email program here mostly produces reporting that looks busy. I left it out because including it would misrepresent how retention actually works in this region.
| Player | Inbox | SMS | Push | Telegram |
|---|
Loyalty and VIP tiers, calculated live
Drag the sliders below. This is the exact formula computing tier and loyalty points, recalculating with every change you make.
How tiering formulas really work
Behind every VIP badge is a weighted score compared against fixed cutoffs. In this model, deposit value carries half the weight, session activity carries three-tenths, and how long someone's been playing carries the rest, so deposit value matters most. That score then places the player into a tier: Bronze, Silver, Gold, Platinum, or Diamond. Real loyalty programs tune these weights and cutoffs constantly against churn and profit data. A tier that's too easy to reach wastes the VIP host team's time. One that's too hard makes genuinely high-value players feel unappreciated.
Loyalty points use a simpler formula: one point per dollar deposited, plus five points per session. That's the basic mechanic behind almost every points program, before multipliers and bonus events get added on top.
ROI and budget, spend versus return
Drag the budget and the channel weights below. Reach, conversions, and return recalculate live, the exact tradeoff a CRM budget owner makes every month.
This was my monthly decision on a INR 2.2 crore budget, split across omnichannel communication and the promotions, cashback and retention incentives underneath it. The hard part is never the arithmetic. It is defending why the cheap channel does not get the whole budget just because its cost per message looks best.
How budget allocation and ROI really work
Every channel has a cost per message and a different rate of return. This module spends each channel's budget on its most engaged players first, then works down the list as more budget is added. That single design choice is what makes diminishing returns show up naturally: the first players a channel reaches are the ones most likely to respond, so early spend converts well. As you push more budget into that same channel, it has to reach further down into less-engaged players, and the average return per dollar falls. You don't need to be told this happens. Drag a budget slider up and watch the ROI number on that channel drop on its own.
The same logic applies across channels, not just within one. Moving weight toward the channel with the best return usually raises your blended ROI, right up until that channel also runs out of highly-engaged players to reach. This is the actual daily decision behind managing a real CRM budget: not "spend more," but "spend where the next dollar still returns the most," and knowing when that stops being true.
Weights are relative, not percentages that must add to 100. The budget splits in proportion to what you set.
| Channel | Allocated | Players reached | Est. conversions | Est. revenue | ROI |
|---|
One player, every number in one place
Every module above looks at one slice of a player. This one pulls all those slices together for a single person, the way a real CRM agent would look someone up before deciding what to send them.
Why this view matters
A CRM platform doesn't just produce charts. Day to day, a retention agent needs to open one player and see everything about them at once: which group they belong to, how likely they are to stop playing, what they're probably worth, and what to send them next. That is what this page pulls together. Nothing here is calculated again from scratch. It simply reads the results already produced by the modules above: the group from module 01, the recency-frequency-value score from module 02, the risk score from module 03, the value prediction from module 04, and the offer match from module 05.
If a section below says to run an earlier module first, that's not a bug. It means this player's risk score or value prediction hasn't been calculated yet in this session. Train those modules once, and every player's profile fills in from then on, even after you switch to a different player.
Are newer players sticking around better than older ones?
Eight weekly groups of new players, each one tracked forward in time. This is the single chart every retention team checks first: is retention getting better, staying flat, or slipping.
How a cohort curve really works
A cohort here just means everyone who joined in the same week. Instead of looking at your whole player base as one blob, you split it by join week and then track each week's group separately over the days that follow: day 1, day 3, day 7, day 14, day 30. The result is a line for every week, and a shape almost everyone recognizes: it starts high, near everyone is still around on day 1, then falls off, some players stop returning, and it eventually flattens out around whatever share of that group actually sticks for the long run.
What makes this chart useful isn't any single line. It's comparing lines against each other. If the newest week's line sits above the older weeks at the same day mark, whatever changed recently, a new onboarding flow, a better welcome offer, a smoother sign-up, is working. If it sits below, something got worse and is worth investigating before it shows up in next month's overall numbers. This is exactly the kind of chart Optimove and MoEngage put on the first screen of a retention dashboard, because it answers the question leadership always asks: is retention actually improving.
| Cohort | Group size | Day 1 | Day 7 | Day 30 |
|---|
Turn a segment into a one-page brief
Pick a segment, set a budget, and this builds the same kind of one-page summary a CRM manager hands to a campaign team or shows in a budget meeting. Print it or save it as a PDF.
What a campaign brief is for
Every real campaign needs a short document before it goes out: who it's for, how many people that is, which channel reaches them best, what offer fits them, how much it will cost, and what return is realistic. That document is a campaign brief. It's what a CRM manager writes to get sign-off from a budget owner, and what gets handed to whoever is actually sending the messages, so nobody has to guess who the audience is or what the goal is.
This module builds that brief automatically from a segment you pick, either an RFM segment from module 02 or a behavioral cluster from module 01. It reuses the same channel-engagement data from module 07 to recommend a channel, the same offer-matching logic from module 05 to recommend an offer, and the same reach-and-return math from module 09 to project a budget outcome. Nothing new is invented here. It's the earlier modules' work, assembled into the format a real stakeholder actually reads.
How many messages is too many?
Every module above sends its own messages without knowing what any other module is doing. In a real platform, several campaigns are always running at once, and the same player can qualify for more than one of them in the same week. This module decides who actually gets contacted, and who gets skipped so they aren't overwhelmed.
Why this is one of the most important pieces of a real CRM platform
Picture one player who is both a lapsed depositor and a Gold-tier VIP. The win-back module wants to message them. So does the VIP loyalty module. So might a general promotion going out to everyone. If nothing stops it, that one player gets three separate messages in the same week. That doesn't triple your results. Real players respond less and less to each additional message they get in a short window, and past a certain point they stop opening messages altogether or unsubscribe entirely. Sending more isn't free, it actively damages the relationship and wastes budget.
This is what "frequency capping" means in practice: setting a limit on how many messages one player can receive in a given period, no matter how many separate campaigns want to reach them. But a limit alone isn't enough, because you also need to decide which message wins when a player qualifies for several. That's what "priority" is for below: each campaign is ranked, and when a player hits their cap, the lower-priority campaigns are the ones that get skipped, or "suppressed", for that player that week. The highest-priority message still goes out.
The numbers on this page assume something realistic: a player's second message in the same week is worth roughly half as much as their first, in terms of how likely they are to act on it, and each message after that is worth about half of the one before. That's why capping barely reduces your total expected results even though it can cut the number of messages sent by a lot. You're mostly suppressing the messages that were going to do the least good anyway, while protecting the player from being contacted so often that they tune out or leave. This exact trade-off, contact frequency versus fatigue versus cost, is one of the first things a CRM or lifecycle marketing interviewer will ask you to reason through.
| Priority | Campaign | Channel | Qualified (uncapped) | Actually sent | Suppressed |
|---|