Cold Start & UX Patterns
This page documents the cold start problem in depth, lessons from prior proximity apps, and concrete UX patterns for onboarding, async delivery, network growth, and identity recovery — specific to an app with no accounts, no server, and no directory.
1. The Cold Start Problem
"Cold start" typically refers to a new user arriving on a platform with no existing network. For most social apps this means seeing an empty feed. For this app the problem is structurally deeper: zero contacts means zero functionality, not just an empty feed.
Three Distinct Cold Start Layers
Network cold start — the app has no utility until a user has at least one contact.
Compare to conventional apps:
| App | Value at zero contacts |
|---|---|
| Twitter / X | Full read access to public content |
| Signal | Can message yourself; import contacts by phone number |
| Imports your phone contacts on first launch | |
| Can compose and send to any address immediately | |
| This app | Zero. Nothing works. No messages to read, no people to find. |
This is not a bug — it is a direct consequence of physical-first trust. But it means the onboarding flow cannot afford to leave a user alone after account creation. The entire first session must orient the user toward their first contact exchange.
Discovery cold start — even with contacts, BLE sync only delivers messages when devices are physically near each other. A user in a city with no other installed base never receives anything, regardless of how many contacts they have in other cities.
This is fundamentally different from network cold start. A user could have 20 contacts on the app and still experience it as "broken" if they never physically encounter those contacts. The app can technically be working correctly while feeling completely dead.
Retention cold start — if users install and add a few contacts but rarely encounter them physically, the experience looks like a broken messenger. "I sent a message three days ago and it has never been marked delivered." This is an expectations problem, not a technical failure.
Without explicit framing, users apply the WhatsApp mental model: sent = delivered (usually within seconds), not delivered = something is wrong. The app needs to correct this model at onboarding and reinforce it throughout.
Comparison to Similar Cold Start Situations
| Project | Cold Start Strategy | Outcome |
|---|---|---|
| FireChat | Crisis-driven spike adoption (Hong Kong 2019: 100k downloads in 24h) | High spikes, near-zero retention after each event |
| Briar | Targeted activists and journalists who already trust each other. Cold start is an accepted limitation. | Small but dedicated user base; no general consumer growth |
| Meshtastic | Community builds physical infrastructure (LoRa nodes). Users ARE the network. | Growing enthusiast community; event-driven density clusters |
| Nearby Share / AirDrop | Ships on every device; single-use-case (file transfer); no social graph required | Ubiquitous — zero network dependency for core value |
| Mesh games (Walking Dead events) | Proximity gaming with real-world events. Users opt in for compelling experience. | Short-lived but proved users accept proximity constraints for the right experience |
Key insight from this comparison: The most successful proximity-constrained apps either (a) shipped pre-installed with zero friction or (b) targeted communities where members already congregate physically and already trust each other. General consumer growth is a trap.
2. Lessons from Failed and Succeeded Proximity Apps
Yik Yak — Failed
Yik Yak combined anonymous identity, proximity radius (~5 miles), and public broadcast. At its peak in 2014 it was the fifth most downloaded app in the US. It failed completely and was shut down in 2017.
What went wrong:
- Anonymous + proximity + public broadcast created a harassment and bullying vector that was impossible to moderate without breaking the core mechanic
- Their attempted fix — adding persistent handles — destroyed the anonymous value proposition. Users left immediately after handles were introduced
- The product was fundamentally a public square, not a private communication tool. There is no technical defense for public broadcast content
Lesson for this app: Never combine anonymity with public broadcast at proximity scale. The design must be private-by-default: content only goes to explicit contacts, never to "everyone nearby." The anonymous count of nearby devices (for ambient awareness) must never resolve to identifiable content.
FireChat — Succeeded Then Failed
Open Garden's FireChat used a mesh networking approach based on Apple Multipeer Connectivity. It gained significant traction in crisis contexts: Taiwan (2014), Hong Kong (2014, 2019), Iraq (2014), Catalonia (2017).
What worked:
- Zero infrastructure requirement perfectly matched crisis use cases (internet shutdowns, network overload at protests)
- App store availability meant rapid organic spread in crisis moments
- The core loop (send a message, it hops through the mesh) was novel and worked
What failed:
- No end-to-end encryption at launch. Messages were readable by any device in the mesh
- Retention collapsed to near zero after each crisis ended. Daily active users had no non-crisis use case
- The Hong Kong 2019 spike (100k downloads, 24 hours) was followed by abandonment within weeks
- The company was acquired and shut down in 2020
Lessons for this app:
- End-to-end encryption must be day one, not a later addition. Once a trust violation is discovered it permanently damages credibility
- Design for sustained daily use cases, not just emergencies. Crisis-readiness is a bonus, not a strategy
- A crisis-driven spike is not product-market fit
Bridgefy — Partially Succeeded
Bridgefy gained 12.5 million users between 2019 and 2020, driven by protests in Hong Kong, Chile, Iran, and Belarus, plus COVID-era use cases.
What worked:
- SDK distribution model: other developers could integrate Bridgefy's mesh into their own apps
- Crisis adoption at genuine scale proved a market exists
- App store visibility at the right moment
What failed:
- A 2020 security audit by researchers at Royal Holloway found multiple critical vulnerabilities: no authentication of identities, messages could be linked across sessions, passive observers could map the social graph, and man-in-the-middle attacks were trivial
- The security failures became a public news story. Trust was permanently damaged
- Bridgefy rebuilt on Signal Protocol (v2.0, 2021) but the reputational hit was already absorbed
Lessons for this app:
- Security is not a feature — it is the product. One published audit failure destroys the entire value proposition for the target audience (people who need private communication)
- Proactive independent audits before launch are table stakes. "We haven't been audited yet" is not acceptable for a privacy-first app
- The social graph is as sensitive as the message content. Protecting metadata (who communicates with whom) must be explicit in the architecture
Briar — Niche Success
Briar is a free, open-source messenger designed for activists, journalists, and people under authoritarian surveillance. It supports Bluetooth, WiFi, and Tor for transport.
What works:
- Cold start is solved by targeting users who already trust each other. Briar is not for meeting new people — it is for communicating privately with people you already know
- The security architecture is well-documented and has been independently audited
- The Tor integration provides internet-based delivery without metadata leakage
- It is genuinely used in high-risk environments (Belarus, Russia, Iran)
Limitations:
- Android only (no iOS)
- UX is functional but not polished; it does not compete with Signal on usability
- No proximity discovery — all contacts must be manually added by scanning QR codes (no passive BLE discovery)
Lessons for this app:
- A clear, specific target audience sidesteps the consumer cold start problem entirely
- The "people who already know and trust each other" framing makes the physical-first trust model an asset, not a limitation
- UX polish is a competitive advantage in the activist/journalist niche, where users often use Briar because they have no other option
Meshtastic — Growing Community
Meshtastic is an open-source LoRa mesh networking project. Users buy LoRa radio hardware, flash Meshtastic firmware, and form a physical network infrastructure.
What works:
- Infrastructure-first: enthusiasts build the mesh, then use it. The network is a community project, not a consumer product
- Event-driven density: hiking groups, festivals, disaster preparedness communities, ham radio clubs all create natural density clusters
- The community maintains open maps of deployed nodes
- Hardware hacking culture creates strong ownership and advocacy
Relevance to this app:
- Meshtastic proves that communities will invest real effort (buying hardware, configuring radios) to build shared infrastructure when the use case resonates
- Community-managed infrastructure is more sustainable than hoping for organic consumer density
- The event and preparedness framing creates ongoing motivation for engagement
Lesson: Event-driven adoption creates repeatable, sustainable density clusters. Design for communities that already congregate, not for individuals who happen to be near each other.
Nearby Share and AirDrop — Infrastructure Cold Start Solved by Default Installation
Both Apple AirDrop and Google Nearby Share solved the cold start problem by eliminating it: the feature ships on every eligible device and has a single, clear, non-social use case (file transfer).
Why this matters:
- The "network" is literally whoever is standing next to you at any given moment
- No social graph required before delivering first value
- Discovery is contextual (share a file → see nearby devices) rather than ambient
- There is no onboarding, no account, no expectation of a persistent network
Lesson: If possible, ensure the app delivers value for a single-person use case before the network grows. The equivalent here is: the app should be useful as a local, encrypted notes tool or offline journal even with zero contacts — something that prevents uninstall during the waiting period.
3. Onboarding Without Accounts
First Launch — What Happens
The onboarding flow must accomplish five things without a sign-up form, phone number, email address, or username:
- Generate a keypair silently
- Help the user understand that this device IS their identity
- Secure the keypair with a backup mechanism
- Show the user what to do next (find someone to add)
- Set correct expectations about message delivery
FIRST LAUNCH FLOW
┌─────────────────────────────────────────────────────────┐
│ "Welcome" │
│ │
│ No account. No email. No password. │
│ Your identity is a cryptographic keypair, │
│ generated right now on this device. │
│ │
│ [Generate my identity →] │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ "Back up your identity" │
│ │
│ If you lose this phone without a backup, │
│ your identity and contacts cannot be recovered. │
│ │
│ [Set up backup →] [Remind me later — skip for now] │
└─────────────────────────────────────────────────────────┘
│
▼ (if backup chosen)
┌─────────────────────────────────────────────────────────┐
│ "Your recovery phrase" │
│ (12 words, shown one at a time on tap) │
│ [Confirm phrase — type words 4, 7, 11] │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ "Ready." │
│ │
│ Here is your code. Show it to someone │
│ to add them as a contact. │
│ │
│ [QR CODE — large, centered] │
│ │
│ Or scan someone else's code to add them. │
│ [Scan a code] │
└─────────────────────────────────────────────────────────┘
The QR code on the final screen is functional immediately — no further setup required. Showing it on the final onboarding screen collapses the gap between "finished setup" and "first useful action."
The Backup Problem — Making It Feel Like Setup, Not a Warning
Crypto wallet teams have accumulated years of experience with this exact problem. The learnings:
What does not work:
- Red warning screens with ALL CAPS text ("DO NOT LOSE THESE WORDS")
- Requiring backup before any app functionality is available (high abandonment)
- Treating the recovery phrase as an afterthought at the bottom of settings
What works (observed from MetaMask, Rainbow, Argent, Ledger):
| Approach | What it does | Why it works |
|---|---|---|
| Progressive commitment | Allow limited use before requiring backup; show a persistent "You're not backed up" banner | Lets users see value first; banner is less alarming than a gate |
| Gamified confirmation | After showing 12 words, ask the user to confirm 3 random words by tapping | Proves they wrote it down; feels like a quiz, not a lecture |
| Narrative framing | "Your recovery phrase is like a spare key to your home" instead of "CRYPTOGRAPHIC SEED" | Human language reduces cognitive load |
| Show-one-at-a-time reveal | Words are shown one at a time, user taps to advance | Slows down the reveal; prevents screenshot-only backup |
| Trusted contact sharding | "Share recovery pieces with 3 trusted friends — you only need 2 to recover" | Social recovery feels more natural than writing down words |
Recommended pattern for this app:
- Show the backup option at end of onboarding, after keypair generation but before the first contact screen
- Frame it as: "Set up your recovery — takes 2 minutes"
- Show 12 words, one tap at a time, with a "hold to reveal" interaction
- Confirm with 3 random words before proceeding
- If the user skips: show a persistent but non-blocking banner: "Identity not backed up — tap to protect your contacts and messages"
- Offer Shamir secret sharing as an alternative for users who don't want to manage a phrase: "Share a recovery key with 3 people you trust. Any 2 can help you recover."
The Empty State After Onboarding
After setup completes, the user has: zero contacts, zero messages, a working cryptographic identity, and no idea what to do.
Empty state options, from worst to best:
| Approach | Problem |
|---|---|
| Blank screen with nav | User does not know what to do; churn risk is high |
| "Invite a friend" button | Requires the user to convince someone else to install first |
| Tutorial carousel | Users skip tutorials; information not retained |
| Contextual QR code + action prompt | Gives the user something to DO right now |
Recommended empty state UI:
┌─────────────────────────────────────────────────────────┐
│ │
│ Ready to connect. │
│ │
│ Find someone else with the app and show │
│ them this code to add each other. │
│ │
│ ┌──────────────────────────┐ │
│ │ │ │
│ │ [QR CODE — large] │ │
│ │ │ │
│ └──────────────────────────┘ │
│ │
│ Or scan their code: [Scan] │
│ │
│ ───────────────────────────────────────────── │
│ When you add your first contact, you'll see │
│ their messages the next time you're nearby. │
│ │
└─────────────────────────────────────────────────────────┘
Additional empty state patterns to consider:
- Achievement framing: "0 / 1 contacts — Add your first contact to get started" (progress toward a goal feels actionable)
- Ambient status: Show the BLE discovery state — "Listening for nearby contacts..." with a subtle animation. This makes the app feel alive even with no contacts.
- Pending messages note: "Messages from your contacts will appear here after your devices sync. Sync happens automatically when you're nearby."
First Contact Establishment UX — The NFC Tap
The contact exchange moment is the most important interaction in the entire app. It needs to feel instant, magical, and clear — not technical.
The NFC tap flow:
INITIATOR (Alice) RECIPIENT (Bob)
[Shows QR / holds phone near] [Holds phone near / scans QR]
│ │
└──── NFC field detected ────────────┘
"Tap detected" "Tap detected"
(haptic + visual pulse) (haptic + visual pulse)
│ │
└──── Key exchange (< 2 sec) ────────┘
"Connected to "Connected to
someone new!" someone new!"
"What do you want to "What do you want to
call them?" call them?"
[text input] [text input]
[Skip — name later] [Skip — name later]
│ │
└──────── Contact saved ─────────────┘
"Done. You'll get their "Done. You'll get their
messages when you're messages when you're
nearby." nearby."
Key UX decisions in this flow:
- The haptic feedback on NFC detection is critical — it confirms the physical gesture without requiring the user to look at the screen
- "Connected to someone new!" — not "Key exchange complete" or "Contact added" — the language is social, not technical
- Naming is optional and skippable. Before the user assigns a name, the contact appears as "New contact (met [date])" or, if the other person shared a display name, that name is used
- The post-exchange confirmation screen stays visible for several seconds and includes the next-step explanation: messages deliver when nearby
What data is exchanged at contact add time (minimum viable):
| Field | Required | Notes |
|---|---|---|
| Ed25519 public key | Yes | Identity key |
| X25519 DH public key | Yes | For key agreement |
| ML-KEM public key | Yes | Post-quantum key exchange |
| Display name (optional) | No | Chosen by each user for themselves; other party sees it or assigns their own |
| Timestamp | Yes | For "met on [date]" display |
Nothing else. No phone number, no email, no location, no profile picture at this stage.
Before a name is assigned, what is the contact called?
Options:
- "New contact" + relative date: "New contact — met today"
- Initials-style avatar with the date prominently shown
- If the other person shared a display name: use it immediately (they gave it to you)
- If not: "Person (April 3)" until the user sets a name
The key principle: never show a cryptographic public key hash as the name. That is a developer interface, not a social one.
4. Explaining Async / Delayed Delivery
This is the hardest UX challenge in the entire app. The expected mental model (WhatsApp: sent = delivered in seconds) is wrong. The correct mental model is much older.
The Mental Model Gap
| User's assumption | The actual model |
|---|---|
| "Sent" means the recipient got it immediately | "Sent" means it is queued on your device |
| Undelivered = broken | Undelivered = recipient not yet nearby |
| 3 days with no read receipt = ignored | 3 days undelivered = haven't been near each other |
| Internet required for messaging | BLE range (~30m) is the "internet" |
The correct analogies to plant in the user's head:
- Leaving a note at someone's house: the note is written and waiting. It is delivered when they come home. You are not notified immediately.
- Walkie-talkie: works perfectly, but only when you're in range of each other
- The postal system before email: messages are real, reliable, and tracked — but delivery time is measured in encounters, not seconds
- Sneakernet: physically moving data between machines by being near them
Message State Design
Every message needs clear state indicators that normalize the queue model:
MESSAGE STATES
✏ Composed — typed but not yet sent from device (draft)
◷ Queued — sealed and waiting on your device for next sync
✓ Synced — delivered to contact's device at last encounter
✓✓ Read — contact has opened the message (optional, privacy trade-off)
The key design decision: never show an error state for a message that is simply waiting. "Not delivered" implies failure. "Queued — will deliver when nearby" implies intentional design.
UI language for message states:
| State | Wrong language | Right language |
|---|---|---|
| Waiting to sync | "Not delivered" | "Queued — waiting for next sync" |
| Successfully synced | "Delivered" | "Synced" or "Delivered" |
| Contact not seen in 7+ days | "Message stuck" | "Last seen 7 days ago — will sync on next encounter" |
Contact Last-Seen Indicator
Each contact in the list should show their last sync time and, optionally, a coarse location:
Alice Last sync: 2 days ago, near Soho
Bob Last sync: 4 hours ago
Carol Never synced
Dan Last sync: just now ● (in range)
Privacy notes on coarse location:
- "Near Soho" is a neighborhood-level approximation, not coordinates
- This is opt-in: the user controls whether to share even coarse location data at sync time
- If opted out, show only the time delta: "Last sync: 2 days ago"
- Never store precise GPS coordinates; the coarse tag (neighborhood, district) is derived from the user's own opt-in and discarded after display
In-Range Notification
When a contact comes into BLE range and a sync occurs, the user should know:
─────────────────────────────────────────────
Synced with Alice — 3 messages delivered
─────────────────────────────────────────────
This notification does double duty:
- Confirms the async model is working ("see, it delivered when she was nearby")
- Creates a moment of delight — an unexpected message arrival is more satisfying than an expected instant delivery
For users with no contacts currently in range, a persistent status element (not a notification — just ambient UI) can show: "Listening for contacts... (0 in range)". This makes the app feel active rather than dead.
Setting Expectations at First Use
A dedicated onboarding screen — not a tooltip, a full screen — should explain the model before a user sends their first message:
┌─────────────────────────────────────────────────────────┐
│ │
│ Messages deliver when you're nearby. │
│ │
│ This app does not use the internet by default. │
│ Messages are delivered via Bluetooth when your │
│ phones are within range of each other. │
│ │
│ This means: │
│ │
│ ✓ Your messages never touch a server │
│ ✓ No one can intercept them in transit │
│ ✓ They deliver the next time you're near │
│ │
│ Think of it like leaving a sealed letter at │
│ someone's door — it will be there when they │
│ get home. │
│ │
│ [Got it →] │
│ │
└─────────────────────────────────────────────────────────┘
Frame this as a feature ("never touch a server"), not a limitation. The privacy-conscious user who is the target audience will respond positively to this framing.
5. Growing Your Network
Without a directory, search, or "people you may know" algorithm, network growth must be entirely physical and community-driven.
Natural Growth Vectors
1. In-person events and regular gatherings
The highest-density use cases are places where the same people repeatedly meet:
| Context | Why it works |
|---|---|
| Coworking spaces | High daily density; members see each other repeatedly |
| University campuses | High density, long dwell time, existing social clusters |
| Activist and mutual aid groups | Already need private communication; motivated users |
| Maker spaces and hackathons | Technical audience; early adopters; event-driven gatherings |
| Hiking / outdoor clubs | Regular group activities; offline context is natural |
| Local community groups | Geographic density; recurring meetings |
These contexts share a property: the physical gathering already exists. The app does not need to create density — it needs to be useful in density that already exists.
2. Contact-of-a-contact introductions
Alice can introduce Bob to Carol without them needing a server:
INTRODUCTION FLOW
1. Alice composes a signed introduction message:
"I'd like to introduce you to Carol [Carol's public key]"
2. Alice sends this to Bob (via BLE sync, next encounter)
3. Bob receives Alice's vouching for Carol
4. When Bob and Carol meet in person, they complete the
exchange (NFC tap / QR scan)
5. Bob's device confirms: "Carol introduced by Alice"
— this is a trust signal, not automatic contact add
The critical design constraint: the introduction lowers friction and creates context ("I know Carol through Alice"), but the in-person exchange is still required. The introduction cannot substitute for physical meeting. This preserves the physical-first trust guarantee.
3. QR codes on physical objects
Static QR codes can represent identities or groups:
- Business card QR → scan to queue a contact request; complete the exchange when you meet in person
- Venue sticker → "Connect with people here" → scan to join a proximity group for the venue
- Event flyer QR → organizer's identity; attendees scan and are queued as pending contacts
These are one-way introductions: the QR owner does not automatically receive a contact. The exchange must still be mutually completed, which can happen at the event.
4. Event-specific group codes
For a conference, meetup, or protest:
ORGANIZER CREATES EVENT GROUP
1. Organizer generates a time-limited group QR code
2. Code is printed, projected, or shared verbally as short numeric PIN
3. Attendees scan code or enter PIN
4. All scanning devices join a temporary proximity group
5. Group exists for the duration of the event
6. After the event, group members can convert to direct contacts by tapping phones
The "physical meeting" is the event itself.
This is the one sanctioned exception to strict one-on-one contact establishment. The event QR is a bounded trust context: everyone present at this location, at this time, agreed to participate.
The Density Problem and Its Mitigation
A proximity discovery feature ("see who's nearby") only works when local user density is high enough. This creates a trap: new users see no one nearby and uninstall, which prevents density from building.
Mitigation strategy: the app must be valuable as a private messenger for existing contacts before any proximity discovery feature matters.
This means:
- Messaging contacts (even with async delivery) must work well and feel complete
- The UX for messaging must be comparable to existing messengers (composed, clean, not "beta feeling")
- Proximity discovery is a bonus, not the core loop
Do not show a "people nearby" count when it will be zero. An empty list reinforces the "nobody uses this" perception. Instead: show a subtle ambient indicator ("listening for contacts") that does not quantify. When users start appearing in range, show them contextually.
Preventing Uninstall During the Growth Phase
| Risk moment | Mitigation |
|---|---|
| Just installed, zero contacts | QR code visible immediately; action prompt; no empty dead screen |
| Has contacts but hasn't synced in 3+ days | "Pending messages" indicator; explain the model; no false error state |
| Synced but no response from contact | No "read receipt" anxiety; framing around privacy value |
| Never encounters contacts physically | Offer online (Tor) opt-in as bridge; normalize async; suggest use cases |
6. Backup and Recovery UX
Recovery Scenarios
| Scenario | Path | Outcome |
|---|---|---|
| Phone lost, had mnemonic backup | New install → "Restore identity" → enter 12 words | Full identity restored; message history syncs over time on next contact encounters |
| Phone lost, had Shamir shares (3-of-3, threshold 2) | New install → "Restore identity" → "Use trusted contacts" → meet 2 of 3 in person | Full identity restored; requires physical meetings to collect shares |
| Phone lost, no backup | New install → "Start fresh" | Complete loss of identity; contacts still have message history; re-add contacts in person |
| Phone destroyed, backup exists | Same as scenario 1 or 2 above | Same recovery as above |
| Phone seized, backup secured offline | Same as scenario 1 or 2 above | Key not accessible on seized device if encrypted; backup remains secure |
The Mnemonic Restore Flow
NEW INSTALL — RESTORE PATH
[Install app]
┌─────────────────────────────────────────────────────────┐
│ "Do you have an existing identity?" │
│ │
│ [Restore with recovery phrase] │
│ [Use trusted contact recovery] │
│ [Start fresh — new identity] │
└─────────────────────────────────────────────────────────┘
↓ (restore with phrase)
Enter your 12 recovery words
[word 1] [word 2] ... [word 12]
Identity reconstructed.
┌─────────────────────────────────────────────────────────┐
│ Identity restored. │
│ │
│ Your key has been recovered. Your contacts │
│ will recognize you when you're near them. │
│ │
│ Your message history will sync back the next │
│ time you encounter each contact. │
│ │
│ [Continue →] │
└─────────────────────────────────────────────────────────┘
Important UX decision: do not promise to restore message history immediately. It cannot be restored from the key alone — the messages live on contacts' devices. The user needs to know: "Your identity is restored. Your history comes back gradually as you meet your contacts." This is accurate and prevents a support complaint ("I restored but all my messages are gone").
Trusted Contact Recovery (Shamir Shards)
For users who prefer not to manage a 12-word phrase, Shamir Secret Sharing lets them distribute the key across trusted contacts:
SETUP (done once, during backup configuration)
"Choose 3 trusted contacts to hold your recovery key.
You will need to meet 2 of them in person to recover
your identity."
[Select Alice] [Select Bob] [Select Carol]
→ A signed, encrypted shard is generated for each
→ Shards are sent to contacts via next BLE sync
→ Each contact's device stores the shard, encrypted to their key
RECOVERY (on new device)
"Recover with trusted contacts"
→ Meet Alice in person → Alice's device transfers her shard
→ Meet Bob in person → Bob's device transfers his shard
→ 2 shards = full key reconstructed
This approach has a UX advantage: it turns key recovery into a social, physical process. It reinforces the app's values (physical trust, no servers) rather than contradicting them.
Contact Notification of Device Change
When a user restores their identity on a new device, their contacts should know:
- The restored key signs a "device change" announcement message
- This message propagates via BLE when the restored device encounters contacts
- Contacts see: "Alice connected from a new device"
- This is a trust signal — contacts should verify with Alice in person if unexpected
No server-pushed notification is possible. The "device change" announcement propagates opportunistically through the BLE mesh. This is slower than a push notification but preserves the offline-first architecture.
The Start-Fresh Path — Dignity for Users With No Backup
A user who loses their phone and has no backup loses everything. The app must make this path dignified:
┌─────────────────────────────────────────────────────────┐
│ Starting fresh. │
│ │
│ Your previous identity cannot be recovered │
│ without a backup. │
│ │
│ A new identity has been created for you. │
│ │
│ Your contacts still have your past messages. │
│ When you meet them again, you can add each │
│ other as new contacts. │
│ │
│ This time, back up your identity immediately. │
│ │
│ [Set up backup →] [Skip — do this later] │
└─────────────────────────────────────────────────────────┘
Do not: show a red error screen, use the word "lost", or make the user feel punished. They will use the app again, and they can rebuild their network. This is genuinely true — the contacts still have the history, and the relationships are real.
7. Event-Driven Adoption Strategy
Based on the lessons above, general consumer growth is not a viable strategy. The only proven path to sustainable density is community cluster adoption.
Target Community Types
| Community type | Why they fit | Adoption trigger |
|---|---|---|
| Activist and protest organizers | Need private, surveillence-resistant comms; already trust each other | Explain the security architecture; get one technical champion |
| University student groups | High density; repeated physical meetings; early adopters | On-campus events; student tech orgs |
| Disaster preparedness / CERT groups | Need offline comms; already practice physical meetings | Works without internet — perfect pitch |
| Maker spaces and hackerspaces | Technical audience; community infrastructure mindset | Tool demos at member meetings |
| Mutual aid networks | Existing trusted relationships; privacy-conscious | Community organizer outreach |
| Local cycling / outdoor clubs | Regular group rides and hikes; offline-first is a natural fit | Event QR codes on ride sheets |
Event Feature Design
Events are the highest-density moments for these communities. Features to build around events:
Pre-event QR code:
- Organizer creates an event group with a time-limited QR code
- QR is printed on flyers, shared in existing channels
- Attendees scan to pre-join; exchange completes when physically present
At-event ambient presence:
- App shows "N people in range with the app" (anonymous count only — no names, no identity)
- This creates social proof without violating privacy: "there are people here using this"
- Do not show identity details of non-contacts; do not show a list of strangers
Post-event follow-up:
- Event group members can convert proximity contacts to direct contacts after the event
- "You were at [event] with 12 people. Tap phones with anyone you'd like to stay connected with."
- Group dissolves; bilateral relationships persist
Organizer controls:
- Organizer can set event group expiry (e.g., "group active for 6 hours")
- Organizer can send a single broadcast message to group (e.g., "Meeting moved to room 302")
- Organizer cannot read private messages between members
Community Infrastructure Investment
Meshtastic's lesson: if you get a community to invest in building infrastructure together, they become advocates and maintainers of that infrastructure.
For this app, the equivalent is not hardware — it is the social graph itself. When a community's trusted members all add each other, the BLE mesh among those members becomes community-owned communication infrastructure. Encourage this with:
- "Add everyone from your group" flow: a trusted member can share their contact list snapshot as a QR that others import pending in-person verification
- Group setup events: a 30-minute "everyone tap phones" session at the start of a new cohort
- Visible mesh indicators: "6 of your contacts are currently in range" — makes the community network tangible
8. UX Principles Summary
These principles are derived from the analysis above. They are intended to guide design and product decisions throughout development.
Core Principles
1. Useful on day one for existing relationships
The app must deliver value as a private messenger for people you already know, before any proximity discovery or network density effects apply. A user with 3 existing contacts and the app on all 3 phones should have a better messaging experience than Signal for privacy-sensitive conversations — even if they only sync when physically near.
2. Make backup feel like setup, not a warning
Key backup must happen at onboarding, framed as a completion step ("set up your recovery"), not as a security warning ("WRITE THESE WORDS DOWN"). Use progressive disclosure, gamified confirmation, and human-language framing. Offer Shamir social recovery as an alternative for users who find mnemonics alienating.
3. Normalize async delivery — never show a false error
"Not delivered" is never the correct message for a queued message. The message is not lost; it is waiting. Pending, queued, and waiting states must be clearly distinguished from failure states. Delivery on encounter should feel like a pleasant notification, not a resolution of an error.
4. Physical gestures should feel like superpowers
The NFC tap moment — the signature interaction of the entire app — must be designed to feel instant, delightful, and magical. Haptic feedback on detection. Smooth animation on key exchange. "Connected to someone new!" Social language throughout. If the tap feels like configuring a device, the product has failed.
5. Never show a count of nearby strangers
No "47 people nearby" view. No list of non-contact identities. A count of anonymous nearby users is acceptable (for ambient social proof at events); resolving that count to identities is a Yik Yak pattern. The only people with names in the UI are contacts who have been physically introduced.
6. Target communities, not consumers
Cold start cannot be solved with consumer viral growth for this type of app. It can be solved by targeting communities where members already trust each other, already meet regularly, and already have a communication need that existing tools handle poorly (due to surveillance risk or infrastructure dependency). Events, not algorithms, create density.
7. Crisis-ready, not crisis-dependent
The app should work excellently in crisis contexts (protests, natural disasters, network outages). It should not require a crisis to deliver value. Design the daily use case first: private messaging for people you trust, with no server involvement. The crisis utility follows from that design; it does not define it.
Anti-Patterns to Avoid
| Anti-pattern | Why it is harmful | Better alternative |
|---|---|---|
| "People nearby" stranger list | Harassment vector; Yik Yak lesson | Anonymous count only; contacts only in list view |
| Push notification for undelivered messages | Creates false urgency; breaks the mental model | Show queued state; notify on sync |
| "Failed to send" for queued messages | Implies error when system is working correctly | "Queued — will sync when nearby" |
| Import phone contacts on first launch | Leaks contact metadata; breaks anonymity model | Physical exchange only |
| Public profile / username directory | Enables surveillance; destroys anonymity | Keypair identity only; no namespace |
| Mandatory account before backup | Skews to server dependency; contradicts design | Keypair is the account; backup is local |
| "Find friends" features | Requires a directory; breaks the model entirely | Event-based group QR codes only |
| Delivery receipts by default | Metadata leakage; reveals contact graph timing | Opt-in read receipts only |
Decision Framework for New Features
When evaluating a proposed feature, apply these tests:
- Does it require a server to work? If yes, it is opt-in only, never default.
- Does it reveal the social graph to any third party? If yes, it cannot be built.
- Does it require PII (name, phone, email)? If yes, make it entirely optional and local.
- Does it create a "people you may know" signal? If yes, do not build it.
- Does it improve the experience for a user with zero contacts? If yes, prioritize it.
- Does it make the first NFC tap more delightful? If yes, prioritize it.
- Does it explain the async model more clearly? If yes, prioritize it.