Inspiration
We wanted to build a communication tool that works in environments where infrastructure fails (e. g. festivals, protests, natural disasters, crowded events with saturated networks). We researched peer-to-peer Bluetooth mesh protocols and found that most existing solutions either required WiFi, a central server, or proprietary hardware. We built the version that didn't.
What it does
- Broadcasts messages to every device in the mesh, useful for announcements or finding people in a crowd
- Direct encrypted messages to contacts added via QR code scan, end-to-end encrypted using NaCl
- Topic channels: subscribe to a named channel like mainstage and see every message sent to that name, no invite needed
- Meeting points: drop a pin on a map and send it to a contact over the mesh; the app notifies them automatically when you arrive within 15 metres using GPS geofencing Everything works with zero internet, zero servers, zero accounts your identity is a nickname and a cryptographic keypair generated on your device
How we built it
- React Native + Expo for cross-platform mobile (iOS + Android)
- Bluetooth Low Energy dual-role : every phone simultaneously advertises as a GATT peripheral and scans as a central, creating a fully connected mesh of direct BLE links
- Custom native modules for iOS and Android to run the BLE peripheral/advertising layer, which React Native libraries alone can't handle
- Flooding with TTL deduplication as the mesh routing algorithm: Every packet carries a 4-char ID, each node relays it once and drops duplicates via a seen-cache with a 60-second expiry
- Haversine formula for GPS-based arrival detection on meeting points
Challenges we ran into
- iOS BLE peripheral restrictions: iOS doesn't allow advertising a GATT server the standard way when the app is backgrounded, requiring a custom native Expo module and specific entitlements. Background scanning is also throttled.
- MTU limitations: BLE packets have a small max payload (~512 bytes after MTU negotiation on Android, less on iOS), requiring us to keep packets compact enough to fit in a single write
- Build times: native modules (Kotlin + Swift) require full native builds; no Expo Go support, every change needed a device rebuild
- Loop prevention: without the seen-cache, a single broadcast would bounce infinitely between nodes. Getting the deduplication + TTL logic right across concurrent BLE connections was non-trivial. ## Accomplishments that we're proud of
- A fully working serverless mesh: messages genuinely hop multiple devices to reach a recipient out of direct range
- End-to-end encryption that requires zero manual key exchange. Keys propagate automatically through packet metadata
- A clean layered architecture (transport → router → UI) with interface contracts, making the routing logic fully testable without any BLE hardware
What we learned
- BLE dual-role (central + peripheral simultaneously) and GATT server architecture on iOS and Android
- Epidemic routing algorithms and the tradeoffs vs. more sophisticated protocols like AODV or DSR
- Writing custom native Expo modules in Swift and Kotlin to expose hardware APIs not available in JS NaCl box cryptography and passive key distribution in a trustless peer-to-peer network
What's next for Toot
- Probabilistic/gossip relay to replace pure flooding and reduce BLE bandwidth consumption in dense crowds
- Delivery acknowledgements: Currently, there is no confirmation that a message reached its destination
- Add private Groupchats features (Not the same as the Topic feature, because topics can be accessed by anyone)
- SOS broadcast — a high-priority packet type with maximum TTL that pre-empts normal routing
Built With
- kotlin
- react-native
- react-native-ble-plx
- switft

Log in or sign up for Devpost to join the conversation.