Most chat apps are just thin clients for a server somewhere.
Your messages travel from your phone, to a data center, back to the other phone. The "chat" is really two HTTP requests with a middleman in between who stores everything indefinitely.
I wanted to build something where the middleman simply does not exist.
The constraint
One rule from day one: no server. Not a minimal backend. Not a lightweight relay. Zero infrastructure I own or operate.
That constraint forces every decision downstream. No user accounts (nothing to authenticate against). No message history (nothing to store). No push notifications via my own service (no server to send from). No analytics (no pipeline to send to).
It also means zero server costs, zero GDPR surface area, and zero incentive to monetize user data because there is no user data.
How the connection works
The app uses two Apple frameworks:
AirDrop via universal links for the initial pairing. You tap share, your phone generates a link, you AirDrop it to the person next to you. When they tap it, iOS opens the app and passes a session identifier. Same gesture as sharing a photo. Zero friction for anyone who has used an iPhone.
Multipeer Connectivity for the actual chat. Once both devices have the session identifier, they establish a direct peer-to-peer connection over Bluetooth or WiFi Direct. No internet involved at any point. The connection is local, encrypted by the framework, and exists only while both devices are in range and the app is open.
The ephemeral part is not a feature, it's a consequence
When you close the app, the Multipeer session is torn down. There is no persistence layer because I never built one. Messages live in memory and nowhere else.
I did not add a "save conversation" option deliberately. The moment you add persistence you need to think about encryption at rest, iCloud sync, backup exclusions, and a dozen other things. Removing the feature removes the problem entirely.
What Multipeer Connectivity gets wrong
Device names. By default, Multipeer uses the device display name (usually the owner's name) as the peer identifier. I override this with a generated session alias so your real name is never exposed to the other device.
Discovery range is also inconsistent. Bluetooth range varies significantly by environment. In a crowded venue with lots of RF interference, connections that should work at 10 meters sometimes fail at 3. I handle this with a retry mechanism and a clear in-app indicator of connection quality, but it is an inherent limitation of the hardware.
What surprised me
Multipeer Connectivity is genuinely underused. Most developers reach for a WebSocket and a Node server because that is the familiar pattern. But for proximity use cases, the framework handles encryption, discovery, and transport for you. The hard part turned out to be UX, not networking.
The AirDrop handshake also turned out to be the right call. I experimented with QR codes and manual code entry. AirDrop won every usability test because people already know how to do it.
Where it is now
Launched 15 days ago. One-time $1.99. Freemium version with 20 free messages is currently pending Apple review (third submission, long story).
If you want early access before the freemium launch and a 25% discount: https://loothy.site
App Store: https://apps.apple.com/us/app/loothy/id6758581273
Happy to go deeper on any part of the architecture in the comments.
Top comments (0)