8 July 2026
Building Usalama Voice
Case study · Usalama Voice · Next.js · Supabase

Usalama Voice is the most important thing I have built so far, and also the one that has humbled me the most. It is a platform for responding to gender-based violence in Kenya, and it is currently being readied for a pilot.
I want to write down how I approached it while it is still fresh, mostly the parts that were hard and the decisions I would make again.
The problem that wouldn't leave me alone
When someone in Kenya reaches out for help after an assault, the help exists. Police, shelters, counselors, legal aid, medical care. The problem is that these sit in separate silos. A survivor tells their story to one person, gets referred to another, and has to start over. The journey breaks at every handoff, usually at the exact moment the person has the least energy to repeat themselves.
So the idea behind Usalama Voice is simple to say and hard to build: keep the journey connected, from the first call for help through to recovery, with everyone who needs to help looking at the same coordinated picture.
Reliability when it matters most
The panic button was the feature I lost the most sleep over. It has to work when someone taps it once, quickly, possibly on a cheap phone with one bar of signal.
A normal web request assumes the network is there. Here I could not assume that. I built the app as an installable PWA and used Background Sync, so an alert raised offline gets queued on the device and sent the moment a connection comes back. It captures location and can record audio, and it does not depend on the person staying on the page or the network holding steady.
It is not a flashy feature. Nobody screenshots a panic button. But if it fails once the whole thing is worthless, so it got the most attention.
Privacy had to come first
Every role on the platform sees a different slice of the data. A responder, a counselor, a legal aid worker and a shelter operator should never see each other's full view, and a survivor's evidence should never leak sideways.
I leaned on Postgres row-level security in Supabase so that access rules live in the database itself, not just in the frontend where they are easy to get wrong. There is a public side too, the Mwananchi portal, but it only ever shows anonymized trends. The rule I kept coming back to was that private data should be hard to reach by accident, not just by policy.
Reaching people without smartphones
Not everyone has a smartphone or data, and a GBV tool that only works for people who do is quietly excluding the people who often need it most. Africa's Talking lets me reach beyond the app itself, so the system is not locked to a single expensive device.
The stack, and why
The short version:
- Next.js and a PWA for something installable that behaves offline.
- Supabase and Postgres for data, auth and role-based access, with the security rules living in the database.
- Upstash Redis to rate-limit the sensitive endpoints, because a panic and notification system is exactly the kind of thing you do not want abused.
- Resend for reliable email, and Africa's Talking for reach beyond the app.
- Vercel to host it and stay out of my way.
None of these were chosen because they are fashionable. Each one closed a specific gap I could point at.
Where it is now
It is being readied for a pilot, which is the honest and slightly terrifying stage where real people start using it and tell you all the things you got wrong. I expect a list. That is the point.
Building this changed how I think about my work. It is easy to care about how software feels when the stakes are a nicer checkout flow. It is a different thing when the person on the other side is having the worst day of their life. I would rather ship something small that holds up than something clever that wobbles, and Usalama Voice is where I really learned to mean that.