Moving Mama's users from WhatsApp to the app
At the end of September, we switched off Mama's WhatsApp chat service to keep costs down. Getting everyone into the app without losing their history took a little more work.
At the end of September, we switched off Mama on WhatsApp.
WhatsApp was where MoneyMama started, and for most of our users, it was the only way they’d ever used her. They’d been recording expenses, asking questions and receiving reminders there for months.
Then we launched the mobile app in September, first on Google Play and about a week later on the App Store.
We’d spent most of July and August building it. But having a working app was only half the job. We still had to move our existing users over, keep their records intact and make sure Mama could continue doing what she’d been doing on WhatsApp.
That turned out to be a project of its own.
Why we decided to leave WhatsApp
The main reason was cost.
WhatsApp’s business messaging charges had always been something we needed to keep an eye on. When someone messages a business, there’s a 24-hour window during which the business can reply with ordinary messages. Outside that window, we have to use approved message templates, which are charged.
For MoneyMama, that was a problem because a lot of what she does happens without someone messaging first. Bill reminders, spending summaries and other scheduled messages often go out long after the conversation window has closed.
Meta was also changing its pricing again in October. Each business number would have an allowance of 1,000 free delivered service messages a month, with charges beyond that. Utility templates sent within the conversation window, which had been free since July 2025, would also become chargeable.
Then there was the infrastructure. WhatsApp needed a separate webhook service to handle messages going to and from Meta, on top of the chat service running Mama herself.
With the mobile app, we no longer needed to pay WhatsApp every time Mama delivered a reply or reminder. It made more sense to put our effort into the app rather than keep maintaining both channels indefinitely.
Keeping the same Mama
Fortunately, we didn’t have to rebuild Mama for the app.
The app connects to the same chat service we’d built for WhatsApp. Her classifier, tools and knowledge base are shared, so she’s essentially the same Mama regardless of where you’re talking to her.
There were still a few WhatsApp assumptions buried in that service, though.
One was how messages were queued. On WhatsApp, every incoming message was associated with a phone number, and we used that number to keep messages in order, combine several quick messages and handle retries.
When I looked at the queue more closely, there was nothing particularly special about the phone number. It just needed a unique string to identify the user.
So for app users, we could use their internal account ID instead.
The more important difference was how replies were delivered.
On WhatsApp, everything Mama sent, whether it was text, buttons, a document or a reaction, eventually went through one function that sent it to Meta.
I kept the chat service as it was and changed what happened at that last step.
If a message belongs to a WhatsApp user, it goes through the existing delivery process. If it belongs to an app user, the reply is saved to the conversation and published to their realtime channel, where the app displays it as it arrives.
There were a few other differences worth handling.
On WhatsApp, we’d added a short delay to combine messages when someone typed several things in quick succession. The app doesn’t need that, so its messages go straight through. Each message also carries its own ID, which prevents duplicates if the phone retries sending because of a poor connection.
We also updated Mama’s expense, income and reminder tools to look users up by their internal account ID instead of assuming everyone had a phone number. It was a familiar problem after the BSUID changes.
And I didn’t want the app to behave exactly like WhatsApp.
On WhatsApp, Mama sometimes asked people to reply with “1” or “2” because that was the easiest way to present choices. She used asterisks for bold text and broke long replies into smaller messages.
In the app, those choices can be proper buttons, and a longer answer can appear as one message.
Bringing everyone’s history along
The part I was particularly concerned about was our existing users.
People had already been recording their expenses and income through WhatsApp. If they downloaded the app and had to start from scratch, we’d effectively be asking them to leave all that behind.
So we built a way for them to sign in to the same account.
On the app’s sign-in screen, there’s an option that says “Already chat with Mama? Use your WhatsApp number”.
Choosing it tells you to send /login to Mama on WhatsApp. She replies with a six-digit PIN, which you enter in the app.
Once you’re signed in, your existing account and everything you’ve recorded are there.
It works the other way round too. Someone who registered through the app first can generate a LINK- code in Settings and send it to Mama on WhatsApp. That links their WhatsApp number to their app account.
Either way, the person ends up with one account rather than two.
That mattered for our reporting as well. An existing WhatsApp user moving to the app shouldn’t suddenly appear as a new MoneyMama user.
We record when an account first signs in through the app. That lets our daily report count someone as having moved on the day they migrated, without counting them as a new registration.
Reminders needed a little more work
On WhatsApp, receiving a reminder was straightforward. It arrived like any other message, whether the app was open or not.
Our mobile app works differently.
When the app is open, Mama’s replies arrive over a realtime connection. But once the app goes into the background, the phone can suspend that connection.
So when Mama sends something on her own, such as a bill reminder, recurring expense notification or spending summary, we also send a push notification in the user’s selected language.
Tapping the notification brings them back to the chat.
We had to change the reminder delivery logic too.
Previously, if someone had both WhatsApp and the app, the system tried to send the WhatsApp reminder first. If that failed, the app copy could be lost as well.
That didn’t make sense any more. Once someone has the app, their reminders now go there instead of WhatsApp.
Finding everything that still sent a WhatsApp message
Before switching off the old webhook service, I needed to find anything that might still be calling it.
There were more places than I’d expected.
Bill reminders were the obvious ones, but we also found purchase confirmations, split-bill notifications, onboarding tips, broadcasts, back-office tools and even a few commands that still sent WhatsApp templates when the person was using the app.
We went through them one by one, either moving the message to the app or removing it where it was no longer needed.
Purchase confirmations, for example, didn’t need a WhatsApp replacement. Purchases now happen inside the app, and the payment process returns people directly to it.
The last scheduled messages to deal with were reminders for people who’d never moved to the app.
We wanted those to stop at midnight at the beginning of October.
There was a small catch. The reminder job runs five minutes early. If we’d simply checked the current time, reminders due just after midnight could still have been sent at 11.55 pm on the last day of September.
So the cut-off checks each reminder’s actual due time instead.
Meanwhile, I was handling the announcements. Mama started telling WhatsApp users that the end of September would be her last day there, and we also announced the app launch through the Mr Money TV mailing list.
Those WhatsApp notices briefly started appearing inside the app too, because both channels used the same Mama.
We added a WhatsApp-only setting to those messages to stop that happening.
We couldn’t just abandon the number
Even after the shutdown, people were still going to message Mama’s WhatsApp number.
Some wouldn’t have seen the announcement. Others might only return after a few months. And existing users still needed WhatsApp to get their login PINs.
So instead of removing the number entirely, we replaced the webhook service with a small function that handles incoming WhatsApp messages.
It only does a few things.
If someone sends /login, the function asks the chat service to generate their PIN and sends it back. It also handles LINK- codes, so users can still connect their WhatsApp number to an app account.
For everything else, it replies with a short message explaining that Mama has moved, along with a Get the app button.
I didn’t want that automatic reply going out every time someone sent a message, because even a simple redirect counts towards WhatsApp’s messaging allowance.
We had about 250 people who’d messaged Mama in the 30 days before we planned the shutdown. Meta’s allowance of 1,000 free service messages per month should comfortably cover one reply to each of them, along with the login PINs.
But replying to every message could use that allowance much more quickly.
The redirect goes out only once per person per month. Any further messages that month are logged, but don’t receive another reply unless they’re login or account-linking requests.
The back office tracks every outgoing message, including who received it and how much of the monthly allowance we’ve used.
There’s also one security difference from the old setup. Meta now calls this function directly, so it verifies Meta’s signature on incoming requests rather than relying on our usual internal API key.
Switching it over
On the day of the shutdown, I changed the webhook callback URL in Meta’s app settings to point to the new function.
Then I tested it from my own phone.
The move-to-app message arrived. I sent /login, received a PIN and used it to sign in to the app. Meta also marked the reply as a free customer service message, which was what I wanted to see.
I spent the rest of the day watching the service for anything we’d missed.
We didn’t turn off the old webhook service immediately. I left it running for another day because of how some scheduled messages were still handled.
For users who’d recently chatted on WhatsApp, a scheduled message could still go through the old delivery process, which attempted the WhatsApp send before saving the app copy. Turning that service off too soon could have meant losing the app message as well.
But with all new incoming WhatsApp messages going to the replacement function, nobody was opening a fresh conversation window on the old service.
After another day, we could switch it off.
A week later, I checked again. Nothing had gone through the old webhook service since the morning after the switch.
That small replacement function is all that’s left of Mama on WhatsApp.
It’s also where the last group of returning BSUID users appeared in early October, which is how part 2 of the BSUID story ends.