01Project overview
Kyndsy is a mobile app that answers a question most people cannot answer about themselves: how do I actually speak? It listens for its owner's voice during an ordinary conversation and counts the rough words, the polite ones, the fillers and the moments the tone gets sharp. It shows the trend over days and weeks. And then it stops — it does not tell the person what kind of human that makes them.
The premise is that self-improvement apps mostly draw a chart of your own opinion. You report on your day, they visualise the report. Kyndsy starts from something harder to argue with: the words that were actually said, counted while the person was busy living rather than sitting down to reflect.
That is also what makes the product hard. Counting speech means a microphone, and a microphone means the person has to trust the app more than they trust almost anything else on the phone. So the entire product is built around a promise that had to be structural: the sound is never kept, the words are never written down, other people's voices are not analysed, and there is no account to attach any of it to.
We designed and built the whole thing: the app for iOS and Android, its content in thirty languages, the light backend, the store release path and the product site. Below is the problem, the decisions, and the parts we deliberately refused to build.
02Context and the problem
An app that listens is a category where the obvious implementation is also the wrong one. Unpacking the task produced a set of constraints that shaped everything after it.
- Trust is the product. An app that measures speech has exactly one asset, and it is not the algorithm. If a person suspects the audio leaves the phone, no amount of accuracy matters — they uninstall.
- Other people did not consent. A microphone in a room picks up whoever is in it. Analysing the people around the owner would be a different app entirely, and a much worse one.
- A number about a person is dangerous. Any single score that claims to summarise a human being is a claim the product cannot honestly make — and one people will read as a verdict regardless of the disclaimer.
- Raw counts lie. "You swore nine times today" rewards silence. A person who says nothing looks like a person who improved.
- Words are ambiguous. The same word is a joke, a quote, a self-directed complaint or a genuine insult depending on tone and context. Counting the string alone produces numbers nobody recognises as their own day.
- People do not speak one language. They switch mid-sentence. A counter that follows only one of them reports a suspiciously calm day every time its owner code-switches.
- The stores have rules about microphone use, about health and psychology claims, and about what a subscription may gate — and they are enforced on submission, not on launch day.
All of that had to hold on a phone, in the background, without draining the battery or the person's patience.
03Project goals
- Measure speech on the device. Analysis happens on the phone; audio is never stored and never uploaded.
- Only the owner's voice. Other voices are dropped rather than analysed, and there is no mode for pointing the app at another person.
- No account, no name. Nothing to leak, because there is nothing collected to leak.
- Rates, not raw counts. Everything per thousand words spoken, so a quiet day is a quiet day and not an achievement.
- Thirty languages, including mixed speech — the dictionaries have to exist in all of them at once, or the number is wrong for the people who switch.
- Distinguish shades. Irony, sarcasm, a joke and a genuine sharp remark told apart and labelled as a guess, never as a verdict.
- Useful without the microphone. The diary, the values compass, the tests and the evening questions work on their own.
- Motivation that cannot be gamed. Runs, levels and programmes judged by measurement rather than by opening the app.
- No overall score of a person. Not in version one and not later.
04What we did
The app is built as four places, each answering a different question, plus the parts that hold them up:
- Today — what just happened: the speech score, the day's goals and a single suggestion, never a list of six.
- Progress — whether it is going anywhere: runs, levels, programmes and the weekly report.
- The Compass — what the person decided to aim at: three to five values they chose themselves, and movement towards those.
- You — everything that belongs to them alone: the self-check tests, family access, their data and support.
Underneath sit the pieces that make those four honest: on-device speech analysis, dictionaries and rules for thirty languages, the shade classifier, the counting model that works in rates rather than totals, a light backend that knows almost nothing, and a settings registry that lets the product change without a store release.
05Privacy as code, not copy
The privacy claims on the site are not marketing copy that a later optimisation might quietly invalidate. They are properties of the build, and the project treats a change that makes any of them untrue as a defect rather than a trade-off.
- The sound is not written anywhere — not to a file, not to a temporary buffer on disk, not to a log. Not in a debug build either, because a debug build is how these things escape.
- Only the owner's voice is analysed. Other people's speech is dropped before it becomes words at all.
- Nothing is transcribed. The app produces counters, not text; there is no stored sentence to leak, subpoena or accidentally sync.
- A session starts only when a person starts it. No auto-start after a reboot, no resuming quietly in the background.
- The voice profile never leaves the phone and is excluded from device backups — it is biometric data, and a backup is the one place people forget it can travel.
- The backend is told four things and no more: a request for settings, a one-off model download, a support message if the person wrote one, and a subscription receipt. There is no account.
- A person is a pair of random numbers their own phone made up. We do not issue them and do not count them — which means we do not know how many installs there are, and that was a deliberate price.
- Signing in is optional and unlocks nothing. It exists to move a subscription and history to a new phone. Making it mandatory would have created a link to a real identity where none exists today.
That last point is the one worth dwelling on. The owner's requirement was to know nothing but an anonymous id — and the tempting way to satisfy it is a mandatory login that we then promise not to read. We did the opposite: no account at all, and an optional sign-in that reads exactly one field from the token and stores it hashed.
06What the app actually counts
Four things: rough expressions, polite expressions, filler words and a raised or sharpened tone. All of them are reported per thousand words spoken, never as a raw total — because a raw count makes silence look like progress, and an app that rewards its owner for not talking has misunderstood its own job.
The day's headline is a respectful speech index, and the rules around it are as considered as the number itself:
- It is hidden entirely until fifty words have been heard. A zero on a quiet morning reads as an accusation, not as missing data.
- Days under fifty words are shown but not counted — visible as blank rather than pretending to be a good day.
- Politeness can lift it by ten points at most. Any further and the score would be cheaper to game with pleasantries than to earn by not being sharp.
- Any single event can be marked as wrong, and doing so changes the number rather than just crossing a line off a list.
The views on top of that are ordinary in form and careful in detail: a seven-day trend, an hour-by-hour picture of the day, a thirty-day grid of one square per day. The hour view refuses to declare a "worst hour" until it has ten events to base it on; the thirty-day grid leaves quiet days beige rather than colouring them as calm. Charts that are confident on thin data are how a measurement product loses the reader's trust — usually for good.
07Shades of speech: irony, a joke, a jab
A joke and an insult are not the same word twice. Kyndsy separates irony from a genuine sharp remark, a joke from a jab, a quotation from something the person meant — and shows what it thinks it heard, in words, next to the event.
Two rules keep that feature honest. First, it is presented as a guess, not a verdict: the app says "possibly irony" or "a joke — not counted" and shows what it based that on. Second, and more importantly, the shade classification never moves the index. It informs the person; it does not silently adjust their score. A confidence-weighted number would be impossible for anyone to check and would quietly become the product's most disputed feature.
The same care applies to context: the same word counts differently when the person is quoting somebody, talking about themselves, or in the middle of an argument. And because no dictionary can know what a particular person's words mean to them, they can keep their own lists.
08Thirty languages — and the mix
The app works in thirty languages — English, Spanish, Portuguese, German, French, Italian, Dutch, Swedish, Danish, Norwegian, Finnish, Polish, Czech, Croatian, Romanian, Hungarian, Greek, Turkish, Russian, Ukrainian, Belarusian, Hebrew, Arabic, Hindi, Indonesian, Vietnamese, Thai, Chinese, Japanese and Korean — and in several of them at once, because that is how a great many people actually speak.
Thirty languages is not thirty translations of the interface. It is thirty sets of dictionaries — rough expressions, polite formulas, fillers — and they have to land at the same time. A language whose dictionary is half-finished does not fail loudly; it reports a calm day. The person sees a good number and believes it, which is worse than an error message.
One lesson from this project generalises well beyond it: a feature detected from the shape of the text breaks on the first language written differently. Treating "a phrase" as "a string containing a space" works until Japanese, Chinese and Thai, which are written without them — and there the app finds nothing at all, silently, while looking like it is working. Language behaviour has to come from the language's own data, and it has to be covered by a test that runs across all thirty.
09The compass and the diary
Speech is only half of the product. The other half is what the person decided to aim at: they pick three to five values from seven — respect, honesty, self-control, responsibility, care, fairness, reliability — and the app shows movement towards those, rather than towards somebody else's idea of a good person.
Movement is drawn from two sources: the speech measurements, and the person's own diary of things they did — kept a promise, apologised, snapped at someone, repaired the damage. Three questions at the end of the day, when they want them.
And there is no overall morality score, now or later. That is the single thing the product refuses to compute. It is also the reason the compass works: a person will pick honest values only for an app that is not going to grade them on the result.
Everything in this half works without the microphone. The diary, the compass, the tests and the evening questions stand on their own, so a person can set the voice part up later, or never, and still get something out of the app. That was a product decision with real consequences for retention, and we would make it again — a permission prompt on the first screen is where a privacy-sensitive app loses the people it was built for.
10Programmes, runs and the weekly report
Motivation in this app had to be immune to the two usual cheats: opening the app a lot, and saying nothing. So:
- Programmes run 7 to 30 days with one aim and one number — seven days without rough words, softer answers for a fortnight, fewer fillers over a month. Whether it worked is decided by the measurements, not by ticking a box.
- A run counts days the person actually held the level. Silent days neither break it nor extend it — putting the phone away is not a way to win.
- Levels are earned by days, not by app opens: Watching, Control, Calm speech.
- Shields cover a slip, up to a point, and a broken day can be bought back — but a run of thirty days with four bought days is not a run of thirty days, so those are counted and shown separately.
- The weekly report says plainly when there is not enough to compare. A summary in which something always improved stops being read by the third week.
One deliberate asymmetry is worth naming: the free tier limits how much history is shown, not how much is counted. Computing a run only over the visible window would have displayed a thirty-day run as seven — not a limitation of the free plan but a false statement about the person.
11A hundred self-check tests
Alongside the measurements sit a hundred structured self-check tests: twenty-five statements each, about four minutes, scored across five facets separately so the answer is never one flat number. They cover speech, feelings, people close to you, work, yourself, habits and life online.
They are explicitly not diagnoses and not personality measurements — they are structured self-reflection, and the app says so where a person will read it rather than in a settings screen. The answers stay on the phone like everything else.
The engineering point here is that a hundred tests cannot be maintained as a hundred hand-written screens. They are a resource, not code: generated from sources, validated at build time, and refused if a test does not have its full set of statements and facets. That check is what makes it possible to have a hundred of them at all, and it is why their unlock rules could be distributed consistently rather than sprinkled by hand.
Half of them open through use, half through purchase. The store products behind the paid half are deliberately few rather than one per test — nobody creates a hundred store listings by hand, and nobody translates a hundred of them into thirty languages either. The product sold is an unlock; the person chooses which test to spend it on inside the app, after the purchase is confirmed.
12Subscription, family and the stores
The paid tier is a subscription, and a family plan shares it — six places for a year, including the buyer's. What matters is what the family shares and what it does not: a family shares the right, not the data. Nobody sees anyone else's numbers, events or diary, and the person who paid sees free places and dates, not who is in them.
That is not a line in the small print; it is how it is built. Other people's measurements are not on the server at all, so there is nothing to accidentally expose in a family screen. Entering a code means agreeing to share a subscription, not agreeing to be identified.
Two implementation rules from this part have outlived the feature. First, the subscription and the family right are one flag in the app: a second question of the form "or maybe they are in a family" would be forgotten in exactly the places where it matters. Second, silence from the server does not revoke the right — the network drops far more often than a subscription ends, and an app that locks a paying customer out on a train has made an obvious choice badly.
Store policy shaped a lot of the surface here: what a microphone app may claim, how a paid tier may be presented, and the fact that a broken build cannot be pulled back with a hotfix. Which is why version policy — minimum supported version, forced update, maintenance mode and the message shown, in all the project's languages at once — is a server-side setting rather than something compiled in.
13Architecture: app, backend, registry
The architecture follows from the privacy promise: as much as possible on the phone, as little as possible on the server.
- The app does the analysis, holds the history and owns the voice profile. It is the whole product; the server is a support role.
- A light backend answers four kinds of request — settings, a one-off model download, support messages and subscription receipts. It has no user table, because it has no users to put in one.
- A configuration registry holds what would otherwise be hard-coded in the app: package identifier, API address, sign-in parameters, the language list, feature flags and the version policy. The values are generated into the source rather than typed there, and the generated file is marked not-to-be-edited for the plain reason that a hand edit is lost at the next generation.
- A pre-flight check gates every build: it refuses if the package identifier has drifted from the registry, if the version is not higher than the last one shipped, if the app's server is not answering, if a dictionary is incomplete in any of the project's languages, if static analysis is not clean, if tests fail, or if anything resembling a key is found in the source. It returns a non-zero exit code, which makes it usable as a gate in any CI.
- The paid tier is behind a flag that can be turned off without a rebuild and without a new store version.
The site is a small PHP application with no database of its own beyond support correspondence — the same principle applied one level out.
14Technology stack
- Flutter for iOS and Android from one codebase — with a design system in code, so colour, spacing and radius are declared in one place rather than at each widget.
- On-device speech recognition and on-device analysis: models are downloaded once and run locally, with the manifest describing them built from the files rather than written by hand.
- PHP 8.4 for the app backend and the site, with a small database used only for support correspondence.
- A configuration registry as the source of truth for app settings, with generated code and a pre-flight gate.
- Thirty language packs for the app and three for the site, with dictionary parity enforced by tests rather than by review.
- A strict content security policy on the site — no inline styles at all, computed values compiled into a stylesheet, and a self-hosted font, so the page about privacy does not fetch a single third-party resource.
15Design and UX
The visual language is one dark theme, taken from the product site so that what a visitor is promised is what they open. A second light theme was written into the tokens and deliberately not shipped: two themes mean two sets of screenshots and twice as many places where a layout breaks unnoticed.
Colour, spacing and radius live in one design file, and the transition between an alarming colour and a calm one goes through a warm yellow — interpolating directly gives an olive mud, which is the sort of thing that looks like carelessness and is actually a missing waypoint.
The app has a character, and the rules around it are about honesty as much as charm: mood is readable from the silhouette, not only from colour, so a colourblind person sees the same thing everyone else does; the mood is a continuous scale animated between values rather than five fixed pictures, because a jump reads as a different picture rather than the same friend; and at the anxious end the eyebrows go up at the inner ends, because down-and-in is anger at the person looking.
Everywhere else the interface follows the product's central rule: show what was measured, say when there is not enough to say anything, and never turn a person into a single number.
16How we worked
- The promise first. We wrote down what the app would never do — keep audio, analyse other people, ask who you are, score you as a person — before designing anything, because those decisions constrain the architecture rather than follow from it.
- Measurement core. On-device analysis, the counting model in rates, the index with its thresholds and its refusal to appear on thin data.
- Language work. Thirty dictionaries and rules, with parity enforced by tests across all of them at once.
- The other half. Compass, diary, programmes, runs, weekly report — everything that works without the microphone.
- Tests as a resource. A hundred self-check tests generated and validated, with their unlock ladder distributed by the generator.
- Monetisation. Subscription, family, the small set of store products, and a paid tier behind a flag.
- Release path. Registry, generated configuration, pre-flight gate, build registration and version policy.
- The site. Three languages, a strict content security policy and a landing page that shows the app's real screens.
Two things kept coming back during the build, and both are now rules. Anything the interface claims about a person's behaviour has to be checkable against a measurement, and anything the app promises about privacy has to be enforced by the code rather than by a note in a document — a shared understanding survives exactly until the next person who did not read it.
17The result
What came out is a measurement product for something people usually only guess at, built so that the measuring does not cost them their privacy.
- Speech analysis on the device: nothing recorded, nothing transcribed, other voices dropped.
- Everything reported per thousand words, so silence is not mistaken for progress.
- Irony, sarcasm and jokes told apart — and labelled as a guess that never moves the score.
- Thirty languages with dictionaries that land together, covered by tests across all of them.
- A values compass, a diary, programmes and a weekly report that admits when it has too little to compare.
- A hundred self-check tests as validated resources, with a small, maintainable set of store products behind the paid half.
- A family plan that shares the subscription and nothing else, because the data is not on the server to share.
18Takeaways
Kyndsy is the project where the hardest engineering was in the constraints. On-device analysis, no transcript, no account, no overall score, no analysing bystanders — every one of those made the build harder and the product possible. A version of this app with a server-side pipeline and a login would have been quicker to write and would not have deserved anyone's microphone.
The lesson we take forward is about how promises are kept: a guarantee that lives in a document is a guarantee until the next change nobody checks against it. The ones that held here are the ones expressed as code and covered by tests — parity across thirty languages, contrast checked as a number rather than by looking, motion verified by values rather than by screenshot, a build gate that refuses rather than warns.
If you are building a mobile product where privacy is the feature rather than the disclaimer, something that has to work in many languages at once, or an app whose numbers people are supposed to trust about themselves, this is the kind of work we take from idea to store.
