Engineering
Building a messenger without phone numbers: the hard problems
Updated November 6, 202616 min read
In September 2026, Signal's lead Android developer announced something new in the app's beta: signing up without a phone number, for a one-time $3 fee. According to Android Authority, the fee is there to stop scammers from creating lots of accounts and flooding the network.
That fee says a lot. A phone number isn't just a login. It quietly does a whole list of jobs for a messenger, and the moment you take it away, every one of those jobs lands on your desk.
We built Morse for messaging without a phone number from day one. Not as an option and not as a beta: there's no phone number in the app and none on our server. This is how we replaced each job a number does, including the parts that turned out much harder than they look, and what we're still working on.
What a phone number quietly does
Look at how the big messengers work and you'll see the phone number doing five jobs at once:
- Identity. The number is your account: one number, one person, and everyone already knows how to write one down.
- Finding people. Upload your address book and the app tells you which friends are already there.
- Keeping spam out. Every account needs a working SIM card, which costs money and effort, so mass sign-ups get expensive.
- Getting back in. Lost your phone? A code by text message and you're back.
- Knowing who's who. A message from your friend's number is probably from your friend.
Each of those is a real feature. Take the number away and you have to rebuild all five, without any of the shortcuts.
Five jobs a phone number does, and how Morse does them
- IdentityWith a phone number:Your number is your accountIn Morse:A random Morse ID, made on your phone
- Finding peopleWith a phone number:Upload your address bookIn Morse:Share your ID or username; they accept your request
- Keeping spam outWith a phone number:Every account needs a SIM cardIn Morse:Paid accounts, and strangers need your OK
- Getting back inWith a phone number:A code by text messageIn Morse:No reset code to steal; your keys stay on your phone
- Knowing who's whoWith a phone number:It's your friend's numberIn Morse:A safety number you can compare
Why we didn't want phone numbers anyway
Those five jobs come at a price, and it's the user who pays it. A phone number is one of the most stable identifiers most people have. In many countries it's registered to your name, it sits in countless company databases, and it's in the address book of everyone you've ever texted.
It's also surprisingly easy to lose. In a SIM swap, criminals get a mobile carrier to move your number to a SIM card of their own, and from then on your text message codes go to them. In the UK, unauthorised SIM swaps rose by 1,055% in 2024, according to the fraud prevention service Cifas, and by another 38% in 2025. An account that never had a number has nothing there to take, which is also why Morse is a messenger without a SIM card at all.
And the friendliest of the five jobs, finding your friends, works by checking phone numbers against everyone on the service. In November 2025, researchers at the University of Vienna and SBA Research showed what that can leak. Using WhatsApp's contact discovery, they checked more than 100 million phone numbers an hour and confirmed over 3.5 billion active accounts in 245 countries, along with public keys, timestamps and, where they were public, profile photos and About texts. WhatsApp has since fixed the issue, and no messages were ever exposed (here's what WhatsApp's encryption does and doesn't cover). But as one of the researchers put it:
This end-to-end encryption protects message content, but not necessarily the associated metadata.
We wanted to protect that metadata too. Our answer to contact discovery is to not have it: Morse never uploads an address book, and there are no phone numbers to match in the first place.
Problem 1: an identity without a number
Every Morse account is born on the phone. The app picks a random Morse ID, 8 characters long, and generates the account's keys right there. The private keys never leave the phone. The server only ever receives the public half, and it checks their signatures before it accepts the account.
Eight characters is short enough to read out loud, write on a napkin or type into a friend's phone. When an ID replaces a phone number, that matters more than you'd expect: people don't share what they can't remember.
There's no password either. To log in, the phone signs a random challenge from the server with its identity key, and the server checks the signature against the public key it stored. The login tokens it hands out are stored only as hashes. So even if our user database ever leaked, it wouldn't hold a single credential that lets someone log in as you.
One more detail does a lot of quiet work: your Morse ID isn't where your messages go. At sign-up the server also gives your account a separate, random inbox ID, and messages are delivered to inboxes, never to Morse IDs. Your Morse ID is for being found. Your inbox is for receiving, and a message waiting there is stored with no sender attached.
Problem 2: finding people without an address book
Morse never reads your address book, and our server has no contact lists at all. So how do people find each other? Three ways:
- Share your Morse ID. Say it, text it, write it down.
- Pick a username and share it, so people can reach you without ever seeing your Morse ID.
- Send a group invite link. The secret part of the link sits after the # sign, a part of the address browsers never send to a server, so it never reaches ours.
Whichever way someone finds you, the first message is always a contact request, and nothing reaches your chats until you accept. Click through it:
A contact request, step by step
Step 1 of 6Alex has your Morse ID or username and sends you a contact request, encrypted so only your phone can open it.
Under the hood, that permission is a random token. Our server stores only a hash of it, never the token itself, and it keeps no contact lists at all. Block someone and their permission is revoked on the server, which still keeps no block list. A message that comes in without a valid permission never raises a push notification on your phone.
One catch took a while to spot: a permission only ever raises a push on the account that issued it. A message carrying a permission meant for someone else still arrives, but silently. Otherwise a paying account could use a token it holds to make a stranger's phone show a notification with text of its own choosing.
The price of all this is growth. No address book means no "12 of your friends are already here" moment. Every connection on Morse is one person deciding to add another. For a private messenger, we think that's the right trade.
Problem 3: spam when accounts don't need a SIM card
This is the one everyone asks about. Without phone numbers, an account costs nothing but a few seconds to create. Leave it at that, and you'll soon have more bots than people.
Signal ran into the same wall, which is why its sign-up without a number costs a fee. Morse handles it in layers, so no single trick has to carry the whole load:
- Accounts are paid. Morse is a subscription, so every account costs real money. It's our business model, and it's also the strongest spam filter we have: creating thousands of accounts stops being cheap.
- Strangers need your OK. Every first contact is a request you accept or ignore. A spammer who gets hold of your Morse ID still can't put a message in your chats.
- Calls work the same way. Only your contacts, and people you sent a request to, can ring you.
- Permissions can be taken back. Blocking someone revokes their permission to message you, right on the server.
- Sending is rate limited, per account and per permission.
- Reports carry no messages. A report says who is reported and why, never what was said, so reporting someone never breaks anyone's encryption.
No single layer would be enough on its own. Together, they make spam on Morse expensive and slow, without us ever needing to know who you are.
Problem 4: usernames without building a directory
Usernames make people easy to find. They also make it easy to build a list of everyone on a service, which is exactly what we don't want. So a username in Morse is optional, there's no way to browse or search all users, and your public profile stays off until you turn it on.
Then there are lookalikes. Every name is reduced to how it reads to a person before it's compared, so nobody gets to be adm1n or m0r5e:
How a username reads to a person
adminadmlnReservedadm1nadmlnReads as admin, refusedm0r5emorseReads as morse, refusedrnorsemorseReads as morse, refusedoffic1a1offlclalReads as official, refusedalex_2alex2Allowed
Our own name gets a stricter check: a name that reads as "morse" anywhere in it is refused. "mrse" counts too, but there the underscores stay in, because without them every mrs_emily would read as it.
Public profiles get the same care. A public name or bio can't contain invisible characters, symbols that draw as a blank, like the Braille blank, or piles of stacked accent marks: the usual tools for a name that looks empty or looks like someone else's.
Problem 5: a key for a name that doesn't exist
That still left the hardest question: can anyone find out whether a name exists at all? Every answer our server gives about a name is a chance to leak that, so we went through them one by one.
The page is the easy part. Unless its owner turned a public profile on, a name's page is the same for every name: the same text, the same status code, the same preview, never indexed.
Requests are harder. To send a request through a username, your app first asks for that name's request key, then seals the request to it. If only real names had keys, the key itself would answer the question. So every name gets one.
For a name nobody has, or one that doesn't take requests, the server makes a key up from the name. It hashes the name with a secret only the server holds, onto the curve, then into the same group every app's key comes from. The result looks exactly like a real key and stays the same every time you ask. And nobody knows its private key, not even our server, so a request sealed to it can never be opened.
Asking for the request key of a name
@alexSomeone has this name and takes requests. Their phone made this key.
@ghostNobody has this name. The server makes a key up from it.
- 1HashThe name, a counter and a secret only the server holds#01→9c4f 1e7a …3b81 d02c …
- 2On the curve?About half of all values aren't. Then count up and hash again.Not on the curve, try againOn the curve
- 3Into the groupMultiply by a fixed multiple of 8, which lands it in the group every real key lives in× 8
Two keys. Which one has a real person behind it?
Random bytes wouldn't have worked. About half of all 32-byte values aren't on the curve at all but on its twist, and most points that are on it sit outside the group real keys come from. Anyone can test for both, so a made-up key has to pass both tests, just like a real one.
Our first version had a flaw, found in review: the made-up key was the public half of a private key the server derived from the name. Whoever held both the secret and the database could have opened requests sent to names that take none. We changed it before any app used it.
It also means that secret can never change. A new one would give every made-up key a new value at once while the real keys stayed put, and anyone who had looked up names before would see exactly which ones are real.
Then the rest of the trail. A request to a name like that is filed just like a real one: it shows "pending" and later "expired", exactly like a request nobody answered, and it's simply never delivered. Every answer about a name's requests waits for the same minimum time, so the clock gives nothing away. Picking a name works the same way: "taken" takes just as long for a reserved name as for one in use, and the limit on how often you can try is checked before anything about the name, so hitting it says nothing either.
Requests are sealed to a separate request key, never your identity key, so a stranger never gets hold of that. Your Morse ID only reaches the other person once you accept.
Problem 6: giving up a name without handing it over
A contact's @username comes from their own profile, and that profile is end-to-end encrypted. Our server never sees it. So on its own, a contact could claim any name: a brand, someone else's, or one we'd never allow.
That's why your app only shows a contact's @username when it comes with a certificate from our server that ties the name to that contact's identity key. The certificate itself is tiny: a version, two times and a signature. Your app already knows the name, from the profile, and the key, the one it saved for that contact. It's signed with a key our server uses for nothing else, and the apps have its public half built in.
Certificates are short-lived, and the owner's app renews them quietly. But that opens a race: someone gives up a name, and a stranger grabs it while the old owner's contacts still hold a certificate that's valid.
Why a released name waits
The name is released
- The old owner's last certificate, still trusted by their contacts
- Held: only the previous owner can take it back
- Free for anyone
So a released name is held for longer than any certificate can live, and during that time only its previous owner can take it back. By the time anyone else can claim it, every certificate for the old owner has expired, so no phone can confuse the two.
One more edge case: a Morse ID becomes free again when its account is deleted, so a new account could register that same ID and count as the "previous owner". So deleting an account wipes its Morse ID from every hold, and that name simply waits until it's free for everyone.
Problem 7: delivery without a record of who sent what
Phone numbers make routing easy, because the server simply knows who's talking to whom, and usually keeps it. We wanted a server that delivers messages without keeping that record.
So every one-to-one message in Morse travels in a sealed envelope. Inside it are the sender's Morse ID and identity key and the message, already end-to-end encrypted with the Signal Protocol. The envelope itself is encrypted to the recipient, with a fresh key pair for every message, and addressed only to their inbox. What our server stores is an inbox ID, scrambled bytes and the time they arrived, with no sender.
What our server stores of a message
Sealed envelope
Encrypted to the recipient with a fresh key for every message, sender inside, addressed only to an inbox
End-to-end encrypted
With the Signal Protocol, for this chat only
Your message
"See you at 8?"
What our server stores
- Inbox
- 7c1e…a90b
- Message
- x9#Qv%2k&Lp…
- Arrived
- 10:42
- Sender
- none
An inbox ID, scrambled bytes and when they arrived. No sender, no name, nothing readable.
Apple's and Google's servers can only read "New message".
A waiting message is deleted as soon as the recipient's phone confirms it has stored it, and it's never kept for long if the phone doesn't. Push notifications never carry anything readable: what Apple's and Google's servers can read is always the same line, "New message".
One honest note: when a message comes in, our server still sees which account is sending it, it just doesn't write that down. Hiding the sender at that moment too, for one-to-one chats and groups alike, is the next big project on our list.
Problem 8: notifications for a locked app
Here's one most people never think about. When Morse is locked with a PIN, its database stays closed, even in the background: locking closes it and wipes the keys that open it from memory. So when a message arrives at 3am, your phone can't decrypt it to show you who it's from.
Showing just "New message" every time would be safe, and annoying. So the sender's phone adds a short preview to each message: the sender's name and the start of the text. It's signed with the sender's identity key and sealed to a separate preview key on your phone, kept outside the PIN lock along with the few things needed to ring for calls. None of them opens your database or any chat.
The sender only ever learns your preview key from your own messages, never from our server, so the server can't slip in a key of its own. And before showing anything, your locked phone runs a list of checks:
What a locked phone checks before showing a preview
- Opens with this phone's preview key
- Signed by the identity key saved for this contact
- Names this account as the recipient
- Recent, and not shown before
- Not from someone you blocked
3:04
Fail any one of them and you just see "New message".
There's an honest trade-off here. A preview is sealed outside the chat's session, so it doesn't get the session's forward secrecy or post-quantum protection. It only carries the start of a message, and turning previews off replaces the preview key, so anything sealed to the old one can no longer be opened.
Problem 9: getting back in without a text message
This is the hardest one to make friendly, and we'll be straight about it. With a phone number, recovery is easy: prove you still have the number and you're back in. Without one, there's nothing to send a code to.
We chose not to build a back door to fill that gap. Your account lives on your phone. On the iPhone, its keys are stored for that phone only, so a backup can't be read on any other device. On Android, Morse is left out of cloud backups and phone-to-phone transfers altogether.
If you set a PIN, your database key and account keys are encrypted twice: once under a key derived from your PIN, and again under a key that can't be taken out of the phone, held by the Secure Enclave on the iPhone and the Android Keystore on Android. So a copy of the phone's storage is useless on its own: testing a PIN guess needs that phone's own hardware. The PIN itself is never stored, not on your phone and not with us. Forget it and nobody can reset it, including us.
Where your Morse account lives
Your phone
- Your private keys, stored for this phone only
- Your messages, contacts and groups, in an encrypted database
- Your PIN: never stored, anywhere
Your cloud backup
- iPhone: a backup can't be read on any other device
- Android: Morse is left out of cloud backups
Our server
- Your Morse ID, inbox ID and public keys
- Waiting messages, encrypted, until delivered
- No phone number, email, name or contact list
The flip side is that today, a Morse account lives on one phone, and a new phone means a new account. We're designing a direct transfer from your old phone to your new one that never parks a copy of your account on a server. It isn't there yet.
And if your phone is ever taken from you, the panic button erases your account in one step, right from the unlock screen if you like, without unlocking the app.
Problem 10: knowing who you're talking to
With phone numbers, trust is borrowed: you assume your friend's number is your friend. Morse gives you something you can actually check.
Every contact has a 60-digit safety number, calculated from both of your identity keys. Compare it in person and you know for certain that nobody, not even Morse, is sitting between you. Then you can mark the contact as verified.
There's a lighter check too. When you open a contact's safety number, your phone asks our server for that contact's current key and compares it with the one it saved when you added them. If they match, you see "Encryption checked". If they ever don't, the chat warns you.
What's next
Being honest about what isn't done yet is part of the deal. Here's what's on our list:
- Hiding the sender from our server at the moment a message comes in, for one-to-one chats and groups.
- Moving to a new phone, through the direct transfer we're designing.
- More than one device per account. Morse runs on one phone today, with no web or desktop app.
If you want all the details, our security overview and security white paper document the protocol, the formulas and exactly what the server stores.
What it adds up to
Every one of these problems would have been easier with a phone number, which is why the biggest messengers still ask for one. Going without cost us real things: no address book to grow from, no text message to get you back in, and, for now, one phone per account.
What it bought is just as concrete. Your identity is a random ID, not the most tracked number you own. Nobody reaches your chats without your OK. Nobody can test which usernames exist. The server delivers messages without keeping a record of who sent them, and there's no text message code to steal.
If you're weighing your options, we've compared the messengers without a phone number side by side, the most secure messaging apps on encryption, phone numbers and open source, and Signal and Morse in detail.
Sources
- 1.Signal will finally let you register without a phone number, for a priceAndroid Authority, 17 September 2026.
- 2.Researchers discover security vulnerability in WhatsAppSBA Research and the University of Vienna, 19 November 2025.
- 3.Hey there! You are using WhatsApp: Enumerating Three Billion Accounts for Security and PrivacyGegenhuber, Frenzel, Günther, Ullrich and Judmayer, NDSS Symposium 2026.
- 4.1,055% surge in unauthorised SIM swaps as mobile and telecoms sector hit hard by rising fraudCifas, 7 May 2025.
- 5.Fraudscape 2026: Fraud cases hit record highs as criminals adapt and scaleCifas, 12 March 2026.
- 6.Morse security white paperHow Morse encrypts messages, checks keys and what its server stores.
FAQ
Questions people ask
Keep reading
- Is Telegram end-to-end encrypted?Short answer: only sometimes. Which Telegram chats are end-to-end encrypted, which aren't, and how to turn it on.
- The most secure messaging apps in 2026Signal, WhatsApp, Telegram, Threema, Session, SimpleX and Morse, honestly compared, catches included.
- Is WhatsApp safe?What WhatsApp protects, where the protection stops, and the settings worth changing today.