Privacy Policy
The short version
BSFChat contains no analytics, no telemetry, no crash reporting, no advertising and no tracking of any kind. Not "anonymised" analytics. Not "essential" analytics. None. There is no analytics, advertising, attribution or crash-reporting SDK in either mobile app — no Firebase, no Google Play Services, no Crashlytics, no Sentry, no ad network, no install-attribution library. Nothing in the app reports back to us about what you do with it, and there is no server anywhere that we could read such reports from.
What is left is the data a chat program cannot work without: your name, your messages, the files you send, and who you send them to. This policy is mostly about where that goes — and the answer, unusually, is probably not to us.
1. Who actually holds your data
This is the most important section and it is the one that does not fit the boxes on an app store form, so it gets prose.
BSFChat is self-hosted software. The app on your device is a client. Your messages live on a server, and that server is a program someone downloaded and ran — on a rented box, in a company rack, on a Raspberry Pi in a spare room, or on the same laptop the app is running on. When you sign in to a server, you are trusting whoever runs that server. That person is usually not us.
We have no central service that your messages pass through. There is no BSFChat cloud. We cannot read, copy, index, moderate or delete anything on a server we do not operate, and in the ordinary case we do not know that the server exists.
We do run three things, and only for these are we the data controller:
| What we run | What it is |
|---|---|
chat.bsfchat.com |
One public chat server. One instance among many, not a hub. |
id.bsfchat.com |
The default sign-in provider (“BSFChat ID”). Optional — a server can use a different provider, or plain username-and-password accounts with no identity provider at all. |
bsfchat.com |
This website. |
Throughout this policy, “we” and “our servers” mean only those three. Where a section describes the server software generally, it is telling you what any BSFChat server does — so you know what to ask the person who runs yours.
Joshua Griffith, trading as BSFChat, is the controller for those three, and is contactable at [email protected]. BSFChat is not a registered company — it is one person running this, which is why a name appears here and not an entity.
2. What we do not collect
Stated plainly, because it is the whole point of the product and because it is checkable — the source is public and none of these words appear in it except in comments explaining their absence.
- No analytics or telemetry. The app never reports feature usage, session length, screen views, button presses or anything else.
- No crash reporting. There is no crash reporter in the app. If it crashes, we find out because you tell us.
- No advertising and no ad identifiers. No IDFA, no Android Advertising ID, no ad SDK, no ad network, and no plan to add one.
- No analytics, advertising, attribution or crash-reporting SDK of any kind. Not Firebase, not Google Play Services, not Crashlytics, not Sentry, not an ad network, not an install-attribution library. Not one, on either mobile platform. What the apps are built out of is described below the list.
- No device identifiers. The app never reads your device's serial, IDFA, Android ID or vendor identifier, and never generates a persistent identifier of its own to track you with.
- No location. No GPS, no location permission, no IP-based geolocation, no mDNS, Bonjour or multicast discovery of any kind. On iPhone you may still see the system's local-network prompt: that is there so the app can reach a chat server running on your own network and so a direct call can use it, not so it can look around. It does not scan for devices or announce itself.
- No contacts, no photo library, no calendar, no microphone-when-idle. The app has no photo-library permission at all: attachments come from the system file picker.
- No read receipts. Nobody is told that you read their message, and the app never receives or displays anyone else's read state either — there is no code in it that can. Your own reading position does go to your own server, so that your unread badges agree across your phone and your desktop; it is not shared onwards. Section 4.
- No profiling, no automated decision-making, no advertising or marketing use of anything here, and no sale of data to anyone, ever.
- No AI training on your messages. We do not have your messages, and we would not do it if we did.
What the apps are built out of, because “no SDKs” would be the wrong way to say it. Every program is assembled out of other people's libraries and this one is no exception. BSFChat uses Qt for its interface, networking and local database, OpenSSL for encryption, nlohmann/json for reading what the server sends and jwt-cpp for checking sign-in tokens. Where voice and video are built in it also uses libdatachannel for the WebRTC connection — which brings with it the standard pieces such a stack needs, libsrtp, libjuice and usrsctp — Opus for audio, libyuv for converting video frames, and, on desktop only, the AV1 encoder libaom and, on macOS and Linux, the H.264 encoder openh264.
These are ordinary open-source libraries, and the distinction we are drawing is a real one rather than a word game: a library does a job the app asks it to do; the kind of SDK listed above also reports back to the company that wrote it. Not one of the libraries above collects, measures or transmits anything about you. On Android specifically, the packaged app contains no Google Play Services, no Firebase and no AndroidX code — the only Java inside it is Qt's and ours.
One thing the apps do that is not tracking but is a network
call, so it belongs here: the desktop apps check
GitHub for a new release. The check runs about thirty seconds after
the app starts and then every six hours for as long as it stays
open, and you can turn it off in settings, which takes effect from
the next launch. It asks api.github.com for the list of
releases and sends nothing about you — GitHub sees an IP
address and the words BSFChat-Updater, as any web
request discloses something.
No update check runs on iPhone or Android, because the stores handle updates there. To be exact rather than flattering: the code is still inside the mobile apps, it is simply never started — nothing creates it, no timer runs and no request is ever made. An earlier version of this page said it was compiled out of them, which was not true.
3. What the app stores on your own device
All of this stays on your device. None of it is sent anywhere.
- Your sign-in tokens, your user ID, device ID, display name and the server addresses you have added.
- A local cache of recent messages and rooms, so the app opens instantly instead of re-downloading everything.
- Downloaded and viewed attachments, in the app's own cache folder.
- Your settings: theme, audio devices, per-person volume, notification preferences.
- A rotating local log file for debugging — the live file plus three older ones, 5 MB each. It records what the app is doing: connections, errors, timings. Message text and sign-in tokens are deliberately kept out of it.
Being precise about how this is protected: it is stored in the app's private, OS-sandboxed storage — on iPhone and Android, in the app container that other apps cannot read. It is not in the iOS Keychain or the Android Keystore, and the app does not add encryption of its own on top of the operating system's. On Android, automatic Google Drive backup of the app's data is explicitly disabled so your sign-in tokens are never copied to Google's servers.
Signing out removes the account itself — the server entry, its sign-in tokens, your user ID, device ID and display name. It does not wipe the message cache, the downloaded attachments or your settings; those stay until the app is deleted, and the cache is thrown away automatically if a different account signs in on that device. Deleting the app removes all of it, because the operating system removes the whole container.
4. What a chat server stores
This describes the BSFChat server software, so it is equally true of
chat.bsfchat.com and of a server your friend runs.
| What | Detail |
|---|---|
| Your account |
A user ID the server issues (like
@you:chat.bsfchat.com), your display name, your
per-server nickname if you set one, your avatar, when the
account was created, and — if it is a password account
rather than a BSFChat ID — a hash of your password.
|
| Devices | A device ID per sign-in, issued by the server. Not a hardware identifier: it identifies a session, not your phone. |
| Messages | Everything you send, with who sent it, where, and when. Also edits, edit history, reactions, replies, threads and mentions. Stored in plain text — see section 9. A second copy of each message body sits in the server's search index. |
| Attachments and avatars | The file itself, stored on the server's disk exactly as you uploaded it, plus its filename, size and type and the fact that you uploaded it. Metadata inside the file is not stripped — if you upload a photo straight from a camera, any GPS coordinates and camera details it contains are preserved and travel with it. |
| Membership | Which channels and direct messages you are in, and when that changed. |
| Your reading position | How far you have read in each channel, so unread badges work. It is never shown to anyone else. |
| Presence and typing | Whether you are online and whether you are typing. Held in memory only and never written to disk. Presence expires after two and a half minutes, typing after thirty seconds. |
| Sign-in tokens | Stored hashed, so a copy of the database is not a set of working logins. Ninety-day sliding expiry. |
| Moderation records | Bans, and an append-only audit log of administrative actions. See section 8 for blocks and reports. |
Your IP address is not written to the chat server's database. Not on login, not on any request: no table in it has a column for your address. It is held in the running process's memory to rate-limit sign-in attempts — minutes for a sign-in, up to an hour for a registration — and then gone. This is a deliberate design decision, not an accident of implementation.
Two honest exceptions to that. Setting up a call writes network addresses into the room's event table for about two minutes, because that is what the messages that negotiate a direct connection contain — section 7 describes them, and they are swept afterwards. And on our own deployment, IP addresses survive in the web-server log, and at Cloudflare in front of it — sections 9 and 13.
Messages are not end-to-end encrypted. We will not imply otherwise. Traffic between the app and the server is protected by TLS, and on our deployment the connection is HTTPS throughout. But the server can read what passes through it, and so can whoever administers it. If you need end-to-end encryption, BSFChat does not currently provide it.
Your messages are never sent to another server. The server does not federate: there is no code path by which your messages leave the server you sent them to.
5. Push notifications
There are none today. Neither app has an Apple Push Notification or Firebase Cloud Messaging integration: there is no code in either of them that registers for a push token, so no notification content is ever handed to Apple or Google. What that means in practice is that the iPhone app only shows you new messages while it is open, while Android keeps a background connection to your server and raises notifications locally, on your own device, with no third party involved.
The server software is capable of push, so it is worth being exact rather than claiming more than is true. The configuration we ship has push switched off and names no gateway, and no gateway is deployed. Even if it were switched on, a server only sends a notification to a destination that an app has registered with it — and no BSFChat app registers one, because there is no code in any of them that could. Nothing is sent.
We intend to add push notifications in a future release, and you should hear that from us now rather than on the day it ships. Getting a message to a phone that is not currently running the app means going through Apple's Push Notification service on iPhone and, most likely, Firebase Cloud Messaging on Android. From that point the content of a notification — typically who messaged you and the first line of what they said — passes through Apple's or Google's servers on the way to your phone. That is how push works on both platforms, and there is no version of it that avoids them. When it happens, section 14 applies: you will be told in the app before it takes effect, and this section will be rewritten to describe exactly what is sent.
6. The BSFChat ID sign-in service
If you sign in with a BSFChat ID, id.bsfchat.com holds
a separate, small account record:
- Your username and a hash of your password.
- Your display name and avatar URL.
- An email address, only if you chose to give one. It is optional, it is never verified, and nothing is ever sent to it — the service has no email capability whatsoever. There is no password reset by email. Give one only if you want it shown on your profile.
- Your two-factor secret, if you turned two-factor on.
- Which BSFChat servers you have signed in to, and when.
- Active sessions: when created, when they expire. No IP address, no browser, no device information is recorded against a session.
Email is coming, and this is the limit we are putting on it before it arrives. Both of those things are true today and neither is meant to stay true: we intend to add a verified email address and a password reset by email, because an account you cannot get back into is a bad account. Doing that means an email provider is involved in carrying the message — section 13 names the one we use. When it arrives, your email address will be collected to fulfil the service you asked for, and no more: confirming the address is yours, letting you back into your account, and any notice you switch on yourself. Not marketing, not a mailing list, not a profile, and not handed to anybody except the provider that delivers it.
Sign-in uses the standard OpenID Connect flow in your real browser (Apple's secure web sign-in sheet on iPhone, your browser on Android and desktop) — never an embedded web view that could read what you type. The token a chat server receives is bound to that one server's address and lives five minutes. Your email address is only ever included in it if the server asked for it and you agreed — though that agreement is all-or-nothing today: the consent screen offers Allow or Deny for the whole request, with no way to approve the sign-in while withholding the address.
The identity service makes no outbound network calls of any kind. It has no analytics, no logging of your email or username on failure, and IP addresses appear in its logs only truncated to a network range.
Deleting a BSFChat ID. The “Delete account” button in the app deletes your account on the chat server. It does not yet delete your BSFChat ID; there is no button for that. Email [email protected] and we will remove it by hand.
7. Voice and video calls
Voice and camera video work on macOS, Windows, Linux, iPhone and Android. Screen sharing is Android and desktop only — the iPhone app cannot share your screen, so the parts of this section about screen contents do not apply to it.
On iPhone, a call keeps running when you switch to another app or lock the screen. That is what the microphone usage prompt is asking about: while you are connected to a voice channel and not muted, the microphone is live, foreground or background. Leaving the channel stops it.
Calls are peer-to-peer wherever possible, and that has a privacy consequence you should know about. When your connection goes directly to the other people in the call, the media never touches a server — which is good — but the other participants' devices learn your IP address, and yours learns theirs. That is inherent to how direct connections work, not a flaw in BSFChat, and every peer-to-peer voice app behaves this way.
If you do not want that, turn on “Hide my IP address” in the voice settings. Every call is then forced through a relay server, so other participants see the relay's address rather than yours. If the setting is on and no relay is available, the call is refused rather than quietly connected directly — a privacy setting that silently stops working is worse than useless.
What the relay sees. A relay (a standard TURN
server; ours runs alongside chat.bsfchat.com) forwards
encrypted packets. It cannot hear your call or see your video. It
does see both ends' IP addresses, how much data flowed and for how
long, and the credential it was given, which contains your user ID.
Relay credentials are issued by your chat server, are unique to you,
and expire after an hour.
Call media is encrypted between participants using the standard WebRTC mechanisms — DTLS for audio, DTLS-keyed SRTP for video. This is not end-to-end encryption in the sense the phrase usually carries: there is no verification that the person you are talking to is who they claim, and no forward secrecy. We will not describe it as E2EE and neither should anyone else.
The signalling messages that set a call up briefly contain network addresses. They are delivered only to the person on the other end of the call, are never shown in the conversation or returned by a search, and are swept off the server about two minutes later.
8. Blocking, reporting, and links
Blocking
Your block list is stored on your chat server against your account, so it follows you to every device. The server does the filtering. A blocked person is never told — their messages and invitations are simply dropped on the way to you, which means they cannot detect the block by watching what happens.
Reporting
When you report a message or a user, the server records who reported it, who was reported, where, the reason you wrote, and a copy of the reported message — kept deliberately, so that deleting the message does not destroy the evidence. Reports are readable only by administrators of that server. The reported person is not notified. On our server, reports come to us; on someone else's, they go to them, and we never see them.
Reports are kept as a moderation record and are not deleted when the reported account is.
Link previews
When somebody posts a link in a channel, your device fetches that page directly to show a preview — the request comes from you, not from the server. The site being linked therefore sees your IP address and that someone opened its page. For a YouTube link this is two requests to Google: one to YouTube for the title, one to its image server for the thumbnail. This applies to any link anyone posts, so treat a link from someone you do not trust with the same caution you would in a browser.
There is no setting to turn this off yet, and there should be. Previews are fetched for up to two links per message as the message comes into view. This is the largest way in which simply reading a channel discloses something about you to somebody outside it, and it is the one part of this policy describing a thing we intend to change rather than to defend.
9. How it is protected, honestly
Passwords are hashed properly. BSFChat ID passwords use PBKDF2-HMAC-SHA256 at 600,000 iterations with a 128-bit random salt — the current OWASP recommendation. Chat-server passwords use the same algorithm at 524,288 iterations. Nobody, including us, can read your password out of a database.
Sign-in tokens are stored hashed on both services, so a stolen database backup is not a set of working logins.
Everything else on a chat server is stored unencrypted, and you should know that. The database holds every message in plain text, plus a second copy of each message in the search index. Uploaded files sit on disk as files. There is no database passphrase. Anyone who can read the server's disk — its administrator, a support engineer at its hosting provider, anyone who steals a backup — can read everything on it. This is true of most chat servers; it is simply not usually written down. On our own deployment the countermeasures are ordinary ones: the database is owner-readable only, deleted rows are overwritten rather than merely unlinked, and backups are written with restrictive permissions.
Attachments are access-controlled. Downloading a file requires a valid sign-in and membership of a channel where that file was posted — a link on its own is not enough. A refusal is indistinguishable from the file not existing, so the URL cannot be used to probe for content.
Our web server's logs. On
chat.bsfchat.com and id.bsfchat.com, nginx
sits in front and writes an access log containing your IP address,
the time, the request path, the response status and your app's
user-agent string. Sign-in tokens are stripped out of the address
before it is written to that log. Two caveats we would rather state
than have you discover: the stripping applies to the access log and
not to nginx's separate error log, which can still record the full
address of a failed request; and it only applies from the day it
was added, so older log files on the host may still contain live
tokens.
This log is the one place your full IP address is written down by
us, and it exists for security and debugging. Cloudflare sees the
same information before we do, for the reasons in section 13.
How long that log is kept, honestly: we do not yet enforce a period of our own. The file is rotated on the host operating system's default schedule, which we have not configured and therefore should not be describing to you as a promise. The intention is fourteen days. Until we have actually set that up, treat the honest answer as “rotated on a default schedule we have not verified”, and when it is enforced this paragraph will say so plainly instead. A policy that states a retention period it does not implement is exactly the kind of thing this document exists to avoid.
Backups. We back up
chat.bsfchat.com and id.bsfchat.com. A
backup contains everything described in section 4, in plain text.
There is no automatic schedule and no automatic
expiry. Backups are taken by hand and deleted by hand: the
script that makes them has no timer behind it and no rule that
removes old ones. The intention is a nightly backup kept for thirty
days, and this paragraph will say so once that is true. Until then,
assume a backup of your data may exist for longer than thirty days,
and read the deletion limits in section 10 with that in mind.
No security is perfect. This is a small project. If you find a hole, please tell us at [email protected].
10. How long things are kept, and deleting your account
Retention
- Messages and attachments: indefinitely, until somebody deletes them. There is no automatic expiry and no "messages older than X are purged" setting. A chat server is an archive by default.
- Deleted messages: deleting a message empties its content on the server, removes it from search, cancels any pending notification carrying its text, and revokes access to any file it linked. The old bytes are overwritten rather than just unlinked.
- Presence and typing: seconds to minutes, memory only.
- Call signalling: about two minutes.
- Rate-limiting records: minutes, memory only.
- Administrative audit log: kept permanently and cannot be edited or deleted, by design — it is the record of what administrators did, including to you.
Deleting your account
There is a Delete account button in the app, in your settings below Log out. You must type your username, and your password, to confirm it. It is immediate and it cannot be undone.
What it does:
- Destroys your password and every sign-in token, everywhere. You are signed out on every device and cannot sign in again.
- Erases your display name, nickname and avatar from your account.
- Removes you from every channel and direct message.
- Deletes your block list, your notification settings and your reading positions.
- Unlinks your BSFChat ID from that server.
What it does not do, and you deserve to be told this before you press it rather than after:
- The messages you have sent stay where you sent them. They remain in their channels, readable and searchable by the people who were in those conversations. This is deliberate. A conversation belongs to everyone in it, and deleting your account cannot mean silently cutting holes in other people's history. If you want particular messages gone, delete them individually before you delete your account.
- Your old display name and avatar remain visible in that history, because they are recorded inside the join and membership events already written into each channel.
- Files you uploaded are not deleted, because they are attached to those same messages. Your avatar is the partial exception: it stops being your avatar and is unlinked from your account, which makes the image itself eligible to be cleaned up later — but if you ever posted that same image into a channel, the copy in the channel stays, like any other file you sent.
- Your username can never be used again, by you or anybody else. A deleted account's ID is permanently retired so that nobody can register it and appear to be you in old conversations.
- Reports and audit records mentioning you survive, as moderation records.
- Backups still contain everything until they age out, as described in section 9.
If you want more than this from a server we run — a particular message gone, a file removed — email [email protected] and we will do what we can. On a server we do not run, ask its administrator; we have no access.
11. Children
BSFChat is not for children. You must be at least 13.
Age requirements for a service like this one vary from region to region, and in some places the age is higher than 13. Where the law where you live sets a higher age, that is the age that applies to you, not ours. We have tried to keep the app out of the regions where it would be unlawful for the people there to use it, and where we have got that wrong we will put it right as soon as we are made aware of it. We are not going to print a table of countries here, because a table we do not maintain is worse than no table.
We do not verify anybody's age, and would rather say so than imply a check that does not exist: the app asks for no date of birth and contains no age gate. We do not knowingly hold accounts for anyone younger, and we do not collect anything designed to be attractive to or targeted at children. If you believe a child has an account on a server we run, email [email protected] and we will remove it. The terms say the same thing.
If this policy is wrong about where you live. Privacy law differs by country, this document was written by a very small project rather than a law firm, and the section above is the most likely place for it to be out of date. If something here conflicts with the law in your jurisdiction — an age, a right we have not offered you, a disclosure we are required to make and have not — email [email protected], say which sentence and which law, and we will look at it properly and correct the page if you are right.
12. Your rights
If you are in the UK or the EU, you have the right to access a copy of your data, correct it, have it deleted, restrict or object to how it is used, and take it elsewhere. If you are in California or a US state with a similar law, you have comparable rights, and we do not sell or share personal information for advertising — there is no advertising.
For a server we run, email [email protected] and we will answer within 30 days. Please note the honest limits above: deletion works as section 10 describes and not otherwise.
For a server we do not run, we cannot help. Its operator is your data controller, not us.
Our legal basis for handling data on our servers is performance of the contract with you (running the service you signed up for) and our legitimate interest in keeping it secure and free of abuse.
13. This website, and the two companies in the path
bsfchat.com sets no cookies, runs no analytics, and
shows no consent banner because it has nothing to ask you about.
Every file it serves — including its typeface — comes
from this one address, so rendering a page here fetches nothing from
a third party. The download buttons are ordinary links to GitHub:
GitHub sees you only if you click one.
There is one script, and it is not ours. The pages
we write contain no JavaScript. Cloudflare, described below, has a
feature switched on that rewrites the email addresses on this page
so they cannot be scraped out of the source, and it injects a small
script from /cdn-cgi/ on this domain to turn them back
into readable text. It is served from here, it reports nothing about
you, and it is the only script the site delivers. An earlier version
of this page said there was no JavaScript at all, which was wrong.
Cloudflare. bsfchat.com,
chat.bsfchat.com and id.bsfchat.com all sit
behind Cloudflare, so every request you make to any of them reaches
Cloudflare before it reaches us. Cloudflare sees your IP address, the
address you asked for and your app's or browser's user-agent string,
and because it terminates the HTTPS connection it is technically
capable of seeing the contents of the request as well. We are not
going to tell you it cannot — that is what terminating TLS
means. It is there for one reason: to keep a small project's servers
standing up and to absorb the scanning and floods that any public
address attracts. We do not use it to track, profile, measure or
monitor you, and none of its analytics or tracking products are
enabled. Cloudflare is a processor acting for us, and it is a US
company, so that connection data leaves the UK and the EEA.
Proton. Email to and from a
bsfchat.com address is carried by Proton, in
Switzerland. If you write to us, Proton handles and stores that
message, so what you put in it is in their hands as well as ours.
They are also a processor for us. We picked them on purpose: their
business is paid subscriptions rather than advertising, so your mail
is not the product. That is a statement about where your mail goes,
not a claim that email is private in general — it is not, and
you should not put anything in an email to us that you would not
want read.
Cloudflare and Proton are the two companies that sit in the path of something you do with us. There is a third that does not: the hosting company whose machine our servers run on, which is why section 9 says plainly that its staff could read the disk. And there is GitHub, which sees you only when you click a download link or when the desktop app checks for an update.
14. Changes to this policy
If we change it, the date at the top changes and we will say what changed. If a change is significant — if we started collecting something we do not collect today — we will tell you in the app before it takes effect, not quietly in a footer.
Two such changes are already planned, and they are written into this document now rather than left for you to find out about later: push notifications, which would put notification content in front of Apple and Google (section 5), and email, which would involve an email provider and give us an address we do not have today (section 6). Both are exactly the kind of change the paragraph above is about, and both will get that in-app notice before they take effect.
15. Contact
[email protected] for anything in this policy, including data requests. [email protected] for vulnerabilities. See also the terms of service and the support page.