bitchat is two transports with two different privacy stories, and one persistent identifier riding through the mesh
bluetooth mesh chat, IRC vibes
At a glance
- What is it?
- permissionlesstech/bitchat is a Swift app that routes messages over a Bluetooth mesh or over Nostr relays, with Noise encryption on the mesh and a proprietary envelope on Nostr. It has no accounts and no servers, and the project's own documentation is candid about where that model leaks.
- Who is it for?
- Use bitchat when the people you need to reach are in Bluetooth range and the point is that no account or server sits between you, since the mesh relays through other people's phones for up to seven hops and works with the radio off. Do not use it as a general Nostr client, because the private envelope format is proprietary and only other BitChat clients can read it.
- Can I use it commercially?
- Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
No accounts, no servers, and one persistent per-device identifier on the mesh
The privacy claim is stated as no accounts, no phone numbers, no servers, and the same bullet carries its own exception. The mesh uses a persistent per-device identifier derived from your identity key, and the project points to the whitepaper for what a nearby radio can observe. That is the honest version of the claim, and it is the part worth reading twice. Noise Protocol encryption protects the message contents, but a stable identifier advertised to nearby devices is a different kind of exposure: a listener in range does not need to break any cipher to notice that the same handset was there yesterday and is there today. Consequence: encryption on the wire does not buy you unlinkability across visits, and the emergency wipe, which clears all data on a triple tap, is not documented here as regenerating the identity key, so do not assume a wipe makes the device unrecognizable to a radio that already logged it.
Forward secrecy is claimed for live sessions, and withheld from store-and-forward mail
The Bluetooth layer encrypts with the Noise Protocol and the documentation attaches a specific scope to that claim: forward secrecy applies to live sessions, and store-and-forward mail is sealed without it, with the whitepaper named as the place this is explained. The Nostr layer does not use Noise at all. It uses BitChat private envelopes, an app-specific construction layered on top of the relay network. Consequence: the two transports do not offer the same guarantee, and the case that loses forward secrecy, a message held and delivered later, is exactly what the app's own smart queuing feature produces when neither Bluetooth nor Nostr is reachable. If the property you care about is that a captured session cannot be decrypted later, a message that spent time in a queue is the case to think about first.
The Nostr side is a relay transport, not an interoperable Nostr client
This is the sharpest technical fact in the documentation. The private-envelope format is proprietary and is not NIP-17, NIP-44, or NIP-59 compatible. Nostr is used as a relay transport only, and private payloads travel inside kind-1059 events whose content carries a v2: prefix and is a BitChat-specific XChaCha20-Poly1305 construction rather than NIP-44 encryption. The project says outright that it only interoperates with BitChat clients. Behind that sits a network described as more than 440 relays distributed globally, and ephemeral keys generated fresh per geohash area. Consequence: a relay operator can see the shape of your traffic because it is ordinary Nostr events, yet cannot read the payload with standard tooling, and no other Nostr application can talk to a BitChat user. The fresh-per-area key is a privacy feature with a matching cost, since your identity is not the same across every region you visit.
Geohash length is the whole of the access control on a location channel
Location channels are defined by how many geohash characters you name, and the documented ladder runs from region at 2 characters for a country or large region, through province at 4, city at 5, neighborhood at 6, and block at 7 for city block level. The examples given are block #dr5rsj7, neighborhood #dr5rs, and country #dr. There is no key, invite, or secret in that scheme; the channel is the coordinate string. Consequence: anyone who obtains a geohash is in the room, so a channel is only as private as the string is unguessable, and a coarse setting is a large area rather than a small one. Shortening the string widens the room rather than hiding it, which is the opposite of what a private channel name implies, and there is no second factor between you and the conversation once the coordinate is known. The three example channels printed in the documentation are public knowledge by definition, which makes them a reasonable place to try the feature and a poor place to hold a conversation that matters.
Seven hops is the ceiling, and every one of them runs on someone else's phone
The mesh relays messages through nearby devices with a maximum of 7 hops, discovery and connection management are automatic, and power is handled by duty cycling so the radio is not always on. Private messages try Bluetooth first because a direct connection with an established Noise session is described as the fastest and most private option, and fall back to Nostr through the recipient's Nostr public key when Bluetooth is unavailable, with messages queued when neither transport exists. Consequence: your effective range is a function of how many strangers are running the app, so the same place gives you one hop on a quiet street and seven in a crowd, and the routing is automatic rather than chosen. Each additional hop is another party's device holding your message briefly, so a conversation you consider link to link is a conversation that crosses hardware you have no control over. That means a message you expected to travel over Bluetooth can instead be relayed across the global relay network, changing its privacy profile without any action from you, and the fallback is decided by the app rather than offered as a prompt.
The Play Store app exists, and the repository holds no Android source
The install links cover both stores, with an App Store listing and a Play Store package named com.bitchat.droid. The tree does not match that. The top-level entries are Swift: Package.swift, Package.resolved, bitchat.xcodeproj/, bitchat/, bitchatShareExtension/, bitchatTests/, localPackages/, a Justfile, and tooling configuration in .swiftlint.yml and .periphery.yml. The feature list itself names native support for iOS and macOS, and the build instructions are Xcode instructions. Consequence: someone auditing the app they install on Android finds nothing here to read. The verification story, which rests on a per-release hash manifest and on docs/VERIFYING-A-BUILD.md, is written around the source you can actually see, so it protects the Apple build and says nothing about the Play Store artifact.
Two build paths, and both refuse to modify your files
The build documentation goes out of its way to be non-invasive, and the details are specific. A signed device build starts by copying the example configuration into an ignored local file:
cp Configs/Local.xcconfig.example Configs/Local.xcconfigThat example derives unique app and App Group identifiers from your Apple Developer Team ID, and the entitlement files already reference $(APP_GROUP_ID), so no tracked project or entitlement file needs editing. Unsigned checks run from the repository root:
# macOS Debug build without signing
xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" \
-configuration Debug CODE_SIGNING_ALLOWED=NO build
# Full SwiftPM test suite
swift test
# iOS simulator tests
xcodebuild -project bitchat.xcodeproj -scheme "bitchat (iOS)" \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 17' testThe simulator destination is pinned to iPhone 17, and the fallback is to list what you actually have:
xcodebuild -showdestinations -project bitchat.xcodeproj -scheme "bitchat (iOS)"The second path wraps the same work:
brew install just
just check
just run`just build` and `just run` use the current bitchat (macOS) scheme and keep output in the ignored .DerivedData/ directory, they never patch source, project, configuration, or entitlement files, and `just clean` removes only .DerivedData/ and .build/ without invoking Git, so uncommitted work survives. Consequence: the one input you must supply is a Team ID through a file that is deliberately not committed, so a fresh clone cannot produce a signed device build until you create that configuration, and the documented simulator command fails on a machine that does not have an iPhone 17 destination.
Editorial conclusion
Use bitchat when the people you need to reach are in Bluetooth range and the point is that no account or server sits between you, since the mesh relays through other people's phones for up to seven hops and works with the radio off. Do not use it as a general Nostr client, because the private envelope format is proprietary and only other BitChat clients can read it. Before you rely on either transport, read WHITEPAPER.md rather than the feature list: forward secrecy is stated for live mesh sessions and not for store-and-forward mail, the mesh carries a persistent per-device identifier, and nothing in the documentation says whether a triple-tap wipe regenerates that identifier.
Frequently asked questions
Can bitchat send messages without any internet connection?
Yes, over the Bluetooth mesh, where messages relay through nearby devices for a maximum of 7 hops with no internet required, which the documentation frames as useful in disasters, protests and remote areas. Location channels such as block #dr5rsj7 and region #dr do require internet, because they connect to Nostr relays.
Is bitchat's private messaging compatible with other Nostr apps?
No. The private-envelope format is proprietary and is not NIP-17, NIP-44, or NIP-59 compatible, with private payloads carried inside kind-1059 events whose v2: prefixed content is a BitChat-specific XChaCha20-Poly1305 construction. It only interoperates with BitChat clients.
How do I verify a bitchat build is the real one?
The file docs/VERIFYING-A-BUILD.md covers checking source against the per-release hash manifest, and what to do if a compiled build is the only one you can get. The project states it has been the target of takedown demands and warns that mirrors appearing after a repository or releases page disappears cannot be checked.
What does the triple-tap gesture do in bitchat?
It triggers the emergency wipe, which the feature list describes as instantly clearing all data. The documentation does not state whether that wipe also regenerates the persistent per-device identifier the mesh derives from your identity key.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/permissionlesstech-bitchat)