Open Free and open source, read the code Get it Donate App help Contact
Messenger
The app
Developers
Project
Legal

A flamenet.io account is not a Flamenet Messenger account. The two sign-ins are separate.

What the server keeps

Encryption keeps your words private. It doesn't hide that you had a conversation at all, someone running the server can still see that a message went from you to someone else, and when. Here is everything the server keeps, and how long it keeps it for.

The short version

  • The server keeps who a message is for and when it arrived, because it cannot deliver it otherwise.
  • It keeps the message itself, still locked, until your app collects it, and it holds nothing that would open it.
  • It keeps your account details: username and the public half of your keys. On this server your password check and any recovery code live with the shared account service, and there is no email. A server with its own accounts also keeps your email and your password, stored scrambled.
  • It does not keep a record of when you added a friend, blocked someone, or joined a group. Those were removed on purpose.
  • Its own logs contain no account, device or address unless an operator deliberately turns on detailed logging.

The rest of this page is the same answer with every field spelled out.

Held while a message is in flight

The numbers below are read from this server's running configuration when the page is served, they are what this instance does, not what a document once said.

KeptWhy it has to beGone after
Recipient account and deviceAn envelope cannot be delivered without an addressthe moment your app confirms receipt, or 1 day(s) after delivery if it never does
Arrival time and exact sizeOrdering, and the size is the ciphertext itself, so the length of a message is not hidden, to the byte. Sizes group by kind: a read receipt is not the size of a photo, and a one-word reply is not the size of a paragraph. Nothing has to be decrypted to see that, and it is a weak but real guess about what an envelope carries. Hiding it means padding messages on the sending device before they are encrypted, a change to the apps rather than to this server, because the server cannot pad what it must not read. It has not been made yet.the moment your app confirms receipt, or 1 day(s) after delivery if it never does
Sender account and deviceIdentified sends only, a sealed send stores neitherthe moment your app confirms receipt, or 1 day(s) after delivery if it never does
The ciphertextIt is the message; the server holds no key that opens it30 days if never collected
Attachment blobs (photos, voice notes, stories, all ciphertext)Devices fetch them separately from the envelope that references them30 days
IntroductionsWhen somebody with no way to reach you yet looks you up by your username, or opens one of your contact links, the server hands them a pass good for one sealed message to you. It keeps the hash of the pass and which account it opens. It does not record who asked, from where, or when. The apps do not use this yet.When the pass is used, or 10 minutes after it was made
“This one is urgent”, a flag on the envelope, not storedA call has to ring while it is still ringing, so the sender tells the server to push at high priority instead of waiting for the app to poll. In practice that means the server can tell a call from a message, not who is calling, or about what, but that this one is time-critical. It is the single most informative thing a sender chooses to reveal, and it is a choice: nothing forces the flag on.Not stored as a value. But it leaves a trace, and saying “never written down” was wrong: every row in Ring attempts below is written only for an urgent envelope, so a row existing for your device is the flag. That is 7 days, with the device and the time, and no content.
“This one needs no attention”, the same shape, kept as one yes-or-no on the envelopeThe other side of the same coin: the sender says an envelope is housekeeping rather than something a person should be interrupted for, so the server sends a background wake instead of an alert. That tells it roughly as much as the flag above does, inverted. The alternative, sending nothing and letting the app decide after it decrypts, means relying on silent pushes that iOS throttles, so the honest trade is a small disclosure for notifications that actually arrive. The server keeps the answer on the waiting envelope so the number on the iPhone app's icon counts messages, not the receipts and keys that travel with them.With the envelope it belongs to: the moment your app confirms receipt, or 30 days if never collected.
Sign-up throttle counters (per IP)New accounts are limited per address per hour, and a counter needs the addressone hour, the counter lives only for its window

Held for as long as the account exists

KeptWhy
Username, display name; email and password hash only on a server with its own accountsIt is an account
Public keys per deviceThey are published on purpose, that is what a prekey bundle is
Buddy list, until you take it offPresence is shown only to people on your list, so the server holds it to enforce that. Settings offers "Take my contact list off the server": the list then lives only in your devices' encrypted stores (and rides your encrypted history export), and the honest cost is that buddies see you as offline, a presence design that needs no stored graph is the planned replacement. One more limit, because it is a limit and not a detail: removing your list also clears the per-conversation rows that name the same people, in both directions, except where such a row is also carrying a read position or a per-conversation setting. Those stay, with the acceptance cleared, because deleting them would lose state you never asked to lose and bring threads back unread on your other devices. So where you have read a conversation, the fact that it exists survives the removal.
BlocksThe server enforces them, so it has to know them. It cannot enforce one against a message that does not name its sender, blocking someone also cancels the passes you gave them, which is the part that can be aimed at one person.
Who is in each groupNot in the clear. The server keeps each group’s member list encrypted, with no account numbers in it anywhere: members are known to it only by random tokens it cannot tie back to anybody, and the list itself is a blob it has no key to. The half that was missing is done: the apps now make groups that way, and the old plaintext table is empty, measured, not assumed. Here is the honest shape of what that buys, which has not changed. It protects you from a copy of this database being stolen, or being handed over, the ordinary way this kind of thing actually goes wrong, and worth having. It does not hide your groups from whoever is running the server while it runs, because messages are addressed to each device: watching who receives a group’s traffic still gives the group away. So the promise this earns is “a dump of this database does not reveal your groups”, and not “the server cannot see who you talk to”. Those two sound alike and are not, and we are not going to blur them.
What each group is calledNot held. It once was, and it should not have been: the name sat in a column the server never actually used for anything, so “Chemotherapy support” or the name of a union drive was sitting on a machine that can be broken into or handed a court order, and it bought nobody anything. It is gone, and the names that were already stored were deleted rather than just stopped. The only places the name can live now are the phones of the people in the group, which tell each other over the same encryption everything else uses. Two things follow, and neither is hidden from you. The app half of this is out now on Android and in the iPhone TestFlight beta, until it reaches your phone, every group reads as “Group”, which is the server declining to answer rather than anything lost. And a group you made before the change shows as “Group” until somebody in it renames it, because the old name was deleted here and no phone had ever been given a copy: there is nothing left to restore it from. Renaming arrived in that same version, for exactly this reason.
PresenceCoarsened to the online window before it is written, never to the second
Which app version each device last polled withThe marketing version and nothing else: “0.25.0”, never a build number, a device model or an operating system. Overwritten rather than appended, so there is no record of what you upgraded and when. It answers one question that cannot be answered another way: whether every app still talking to this server is new enough that something can be taken off the server. The thing being taken off is the buddy list above. Removing it while older apps still read their contacts from here would empty those contact lists, so the choice is between this column and never making the change. We would rather keep one version string than keep your contact graph.
Delivery-key digest, one per deviceThe hash only. The key itself never reaches the server except inside a sealed submission. Each of your devices has its own key, so the server keeps one hash per device and accepts any of them; it used to keep one per account, and a second device publishing replaced the first one’s. Removing a device removes its hash.
Presence tokens, per deviceFor each contact a device lets see when you are online, the hash of a random token that device gave them over the encrypted channel. The server cannot tell which hash stands for whom, so what it holds is how many contacts each device has issued one to. Removing a device removes its hashes. An older app publishes one set for the whole account instead; a device that publishes its own set replaces that one.
Whether people can find you by your usernameOne yes or no, and yes unless you change it. Turned off (Unlisted), every way of looking an account up by its username, or of asking who an account number belongs to, answers as it does for a name nobody has: the same reply, after the same wait. People already in touch with you keep reaching you; somebody new needs one of your contact links. Usernames are unique, so trying to sign up with yours still says it is taken. Unlisted means people cannot find or add you by your username. It does not make your username a secret. The apps do not offer the switch yet.
Contact linksUp to five links that let somebody start a conversation with you without knowing your username. The server keeps the hash of each link and which account it leads to. It does not keep when you made one, who has used it, or how often. Revoking a link deletes it.
Per-device last-activity stampCoarsened to the hour before it is written. It exists so a device that falls silent for 90 days can be expired, its keys unpublished, its queued mail deleted, rather than staying addressable for ever. An account's newest device is never expired, and an account holds at most 6 devices. Only your own account is shown it, along with when each of your devices was registered. Any member who asked about your account used to see both, which told them when you were last on your phone.
Reports you send usKept 365 days, then deleted. A report names the account reported and the account reporting, the reason chosen, and the copy of the message you chose to attach, in readable form. Your phone can read that message even though the server cannot, and the box offering to attach it is ticked by default, so this is the one place readable message text exists here. Untick it and the report carries no copy. See reporting someone.
Ring attemptsKept 7 days. When the server tries to make a phone ring for an incoming call, it records which device it tried and whether Apple accepted the push, so a call that never arrives can be diagnosed instead of guessed at. No content, and nothing about who was calling. Worth saying plainly, because the row above it is where you would look: these are written only for envelopes the sender marked urgent, so the existence of a row is itself the record that the flag was set.
Per-conversation stateWhich of your own conversations you have read up to, so a thread does not come back unread on another of your devices. No content. It is worth being exact about what a row here holds, because this description used not to be: a row names both accounts, yours and the other person’s, and it records that you accepted them as a correspondent. It no longer records when, which it did until recently and should not have. Nor does it record which conversations you star or archive: those were stored here and never read by anything, so the server stopped taking them and cleared the ones it had. They belong on your devices.
NotificationsCounts and flags for the badges the apps show. A read one is deleted after 7 days, and any one after 30, read or not. Today there is one kind, “somebody added you as a contact”, and it carries that person’s display name, which is why it is not kept longer.
Invitation codesCodes issued to let somebody create an account: who issued each one while it is unused, and when it was used. A used code no longer says who issued it or which account it made. The server used to keep both ends of every invitation, which is a record of who invited whom, and nothing read it; it stopped, and cleared the pairs it already held.
Extra mailboxesIf you have told the app to keep mail at another relay as well, which relays those are.
Device sign-out ordersA pending instruction that a device you signed out remotely should erase itself, held until that device collects it.

Held for ever, on purpose

The key transparency log: which public keys an account published, and when each device was added, revoked, or expired. It is append-only and permanent because its entire value is that it cannot be quietly rewritten, it is how your app detects a server showing different keys to different people. It contains public keys and lifecycle events only, which account, which device, which kind of event, when, and nothing else: no addresses, no request metadata, no message rows. Those fields are the chain; there is no operational residue riding along with it.

Deliberately not kept

These were removed rather than retained. Each was written and never read, which made them a durable record of how a social graph formed in exchange for nothing:

  • Who uploaded an attachment. The load-bearing one: a sealed envelope stores no sender, and then the attachment it pointed at named the uploader for the life of the blob.
  • When a buddy was added.
  • When a block was set.
  • When someone joined a group.
  • Who invited whom. A used invitation code keeps when it was used and nothing about either person.
  • Which conversations you star or archive.
  • Who asked to be introduced to you, or used your contact link.

No AI, anywhere

Nothing in the app or on this server calls a language model. Nothing reads your messages, nothing summarises them, and nothing is trained on them, because nothing here can decrypt them. That is not a policy that could be changed quietly; it is what the design leaves possible.

Push notifications

Android needs no push service: the app holds its own connection to this server, and no third party is involved. On iOS the wake-up goes through Apple, and what Apple sees is held still by a test, not a promise: the payload is the fixed strings "Flamenet" and "New message", a sound, and at most a count of waiting envelopes, never a sender, never a thread, never a word of content. Apple learns that a device was woken and when; the device then collects and decrypts its mail itself and writes its own banner. The push token is stored per device and deleted on sign-out, and when Apple reports the app gone.

Signal prefers Google's FCM on Android wherever Play Services exists, so its wake-up passes through Google, and it falls back to its own socket where they do not. This app has no FCM path to prefer. On iOS the position reverses, and Apple sits in ours.

What the maker of your phone sees

No messenger controls this part, which is why it is on this page. On a Google-certified Android, Play Protect scans every app on the phone whatever route it arrived by, and Google's documentation says it may receive information about the apps installed on a device "through Google Play or other sources". So Google can know this app is on the phone. It learns nothing about using it: there is no Firebase, no Play Services and no push service in this app, so nothing about a message passes a Google machine. On a phone without Google's services none of it applies.

Google intends to require a developer to register an identity, a package name and a signing key before an app installs smoothly on a certified device. Four countries are covered from 30 September 2026, the rest from 2027. An app from a developer who has not registered stays installable, but only after a one-time setup on the phone that includes a 24-hour wait. What this project does about that is not yet decided. This page will say which way it went.

iOS is stricter in the other direction. The app reaches an iPhone only because Apple reviewed it and Apple distributes it, so Apple knows who installed it, and no Google-free iPhone exists to step around it.

Logs

At its default level the server logs operational lines that name nobody: start-up, the hourly retention sweep's counts, and refused requests, with any account or device id in the request's path masked before the line is written, because who was refused is exactly what must not accumulate in a file nothing sweeps. Below that, debug has to be switched on deliberately: it records full request URLs and every database query, and a protocol URL contains a device id, which would turn the log file into a durable record of who fetched whose keys.

One of the sweep's counts is about message sizes. Every hour it records how many messages arrived at each rough size, and how many of them were already padded to one of the fixed sizes the apps are moving to, split by app version (“FlamenetMessenger 0.31.0”) and nothing else: no account, device or conversation. It exists to tell when every app in use pads its messages, so the server can start refusing ones that do not.

Whatever sits in front of the server keeps its own access log. That is the operator's to configure, and on a server you run, the operator is you. On the server operated at this domain, the edge proxy writes a line for every request: the connection's address, the path, the size and the time. On the machine those lines are overwritten every day at 03:30 UTC, once that day's copy has reached an off-site archive; if the copy fails, they stay until one succeeds. The archive copy is encrypted and kept for 90 days, so that an intrusion noticed weeks later can still be traced. So an address at the front door lives about a day on the machine and 90 days in the archive. The server's own log is separate, is not archived, and holds no addresses.

Some questions can now be asked without signing in, with the account being asked about inside the request rather than in its address: which devices an account has, what is needed to start a conversation with it, whether contacts are online, and introductions. Their address lines in the access log name nobody. The connection's IP address is still seen, and it is usually the same one your app signed in from a few seconds earlier. The apps do not use these yet.

That log also records the size of every request, which is the same disclosure as the row above arriving by a second door, and it is worth saying plainly that the log outlives the envelope: the envelope is erased the moment your app confirms receipt, and the line recording how large it was stays in the access log for about a day on the machine and 90 days in the archive. Padding messages on the sending device is what would hide both, because both are measuring the same bytes. That has not been done yet. An operator who wants neither can turn the access log off; this one is kept because without it there is no way to see whether the site is reachable at all.

What none of this changes

A server necessarily observes the connection that delivered a message, including its address. Sealed sender removes the sender from the stored row, not from the network. Anyone claiming a hosted messenger is metadata-free is describing something else.

See also the privacy policy for the retention windows in full, and self-hosting for how to change them.

Free and open source · No ads · No phone number · Your own server if you want one