# How BitChat Enables Offline Communication Using Bluetooth Low Energy (BLE) Mesh

> Discover how BitChat uses Bluetooth Low Energy (BLE) mesh for offline communication. Learn about its dual-transport architecture and multi-hop peer-to-peer networking for encrypted messaging without internet.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-08-19

---

**BitChat implements a dual-transport architecture that pairs the global Nostr protocol with a local Bluetooth Low Energy mesh, allowing encrypted messages to route through a multi-hop peer-to-peer network when internet connectivity is unavailable.**

BitChat (permissionlesstech/bitchat) is an open-source messaging application designed to function without centralized infrastructure. By leveraging a **Bluetooth Low Energy (BLE) mesh** transport layer, the application establishes direct device-to-device communication that operates entirely offline, falling back to Nostr only when no mesh peers are available.

## Dual-Transport Architecture Overview

The application operates on a **dual-transport** principle that prioritizes local connectivity. When internet access is present, BitChat can utilize the Nostr protocol for global message propagation. However, when connectivity drops or users choose to remain offline, the system seamlessly transitions to the BLE mesh transport. This mesh functions as a **multi-hop, packet-radio stack** built on CoreBluetooth, enabling devices to discover each other, form ad-hoc networks, and relay encrypted packets up to **seven hops** away according to the mesh topology constraints defined in [`README.md`](https://github.com/permissionlesstech/bitchat/blob/main/README.md).

## Layered BLE Mesh Stack

BitChat’s Bluetooth implementation follows a strict layered architecture defined in [`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md), separating concerns to ensure deterministic behavior on resource-constrained devices.

### BLELinkLayer (CoreBluetooth Interface)

The `BLELinkLayer` serves as the sole interface to CoreBluetooth, handling all direct radio operations including **scanning, advertising, connection scheduling, MTU handling**, and **back-pressure buffers**. This layer exposes only `LinkEvent` and `LinkCommand` abstractions to higher levels, remaining completely agnostic to packet contents or encryption sessions. By isolating CoreBluetooth imports to this layer alone, the architecture prevents cross-cutting dependencies and simplifies testing.

### Mesh Engine (Protocol State Management)

The **Mesh Engine** operates on a dedicated serial queue that owns all protocol state, including **fragmentation, deduplication, relay policy, peer registry, topology management, gossip sync**, and **Noise orchestration**. Running all mesh logic on a single-writer queue guarantees deterministic ordering and eliminates deadlock scenarios during complex routing decisions. This engine implements the **fan-out selector** that determines which peers receive specific packets, optimizing broadcast scope to conserve battery life.

### Feature Modules and App Boundary

Individual capabilities such as private media sharing, voice messages, and courier services each maintain their own state as **Feature Modules**, registering for specific message types without modifying the core engine. The `BLEService` class acts as the **App Boundary**, implementing the `Transport` protocol that the UI layer consumes. Located in [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift), this façade forwards events to the UI via `BitchatDelegate` and delegates outbound messages to the underlying mesh layers.

## Offline Message Routing Flow

When operating without internet connectivity, BitChat follows a deterministic sequence for message propagation through the BLE mesh.

### Discovery and Mesh Formation

Each device simultaneously operates as both a **Central** and **Peripheral**, advertising a common service UUID (`F47B5E2D-...`). The `BLELinkLayer` continuously scans for nearby peers and establishes connections automatically. Once connected, devices exchange capability information and populate the peer registry maintained by the Mesh Engine.

### Multi-Hop Relay and Fan-Out

Outbound messages undergo encoding into a **compact binary protocol** optimized for BLE’s limited MTU of approximately 512 bytes. If messages exceed the default fragment size, the Mesh Engine handles fragmentation transparently. The engine serializes packets and passes raw bytes to the link layer via `LinkCommand` instructions. For delivery, the **fan-out selector** determines the optimal next-hop neighbors, limiting unnecessary broadcasts while ensuring packets progress toward their destinations up to the configured hop limit.

### Store-and-Forward Queuing

If a recipient is temporarily out of range, the Mesh Engine implements **smart-queuing** logic described in [`README.md`](https://github.com/permissionlesstech/bitchat/blob/main/README.md) (lines 89-102). The engine stores undelivered messages locally in a persistent queue. When the target peer reconnects directly or appears through an intermediate node, the queued message automatically transmits without user intervention. This store-and-forward mechanism ensures message persistence across intermittent connectivity.

## Security and Reliability Mechanisms

### Noise Protocol Encryption

All traffic traversing the BLE mesh undergoes encryption using the **Noise Protocol**, providing forward secrecy for active sessions and end-to-end confidentiality for stored messages. The Mesh Engine orchestrates Noise handshake and decryption routines, ensuring that packet contents remain encrypted during multi-hop transit and are only decrypted by the final recipient.

### Power Management and TTL

To prevent battery drain and network congestion, the mesh enforces a **Time-To-Live (TTL)** counter on each packet, defaulting to **5 hops** (with a maximum of 7). When a packet’s TTL expires, nodes discard it automatically. Additionally, the `BLELinkLayer` maintains **back-pressure buffers** to prevent overwhelming the radio, while the Mesh Engine employs **adaptive power** logic that throttles scanning and advertising frequencies based on device battery state. The `BLEPeerRegistryStore` provides lock-backed peer state for fast, non-blocking reads essential for low-latency routing.

## Implementation Code Examples

Initialize the BLE mesh service and configure the delegate:

```swift
import bitchat

// Initialize the singleton BLE service
let bleService = BLEService()

// Configure the delegate to receive messages
class ChatViewModel: BitchatDelegate {
    func didReceivePublicMessage(_ msg: BitchatMessage) {
        // Handle message received via BLE mesh
        print("Received: \(msg.payload)")
    }
}

let viewModel = ChatViewModel()
bleService.delegate = viewModel

```

Send a text message with TTL constraints:

```swift
// Create a message with 5-hop maximum
let message = BitchatMessage(
    type: .text,
    payload: "Offline mesh test".data(using: .utf8)!,
    ttl: 5  // Expires after 5 hops
)

// Send through the mesh (encrypts with Noise, fragments if needed)
bleService.sendMessage(message)

```

The `sendMessage` method in [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift) (approximately lines 200-210) internally routes the payload through the Mesh Engine, which handles Noise encryption, packet fragmentation, and fan-out selection before handing raw bytes to the `BLELinkLayer` for transmission.

Handle queueing when no peers are available:

```swift
// This returns immediately even if no peers are connected
bleService.sendMessage(urgentMessage)

// The Mesh Engine automatically queues the message.
// When a peer appears (directly or via relay), 
// transmission occurs without additional code.

```

## Summary

- BitChat combines **Nostr** and **BLE mesh** in a dual-transport architecture that prioritizes offline peer-to-peer communication.
- The **Mesh Engine** manages routing, encryption, and queuing on a serial queue, while the **BLELinkLayer** handles all CoreBluetooth interactions.
- Messages can travel up to **7 hops** through the mesh using a **fan-out selector** that optimizes for battery efficiency.
- **Noise Protocol encryption** ensures end-to-end security across multiple relay nodes.
- **Store-and-forward queuing** automatically handles intermittent connectivity, delivering messages when peers become available.

## Frequently Asked Questions

### How many hops can a message travel in the BitChat BLE mesh?

Messages can traverse up to **seven hops** through the mesh network, though the default **Time-To-Live (TTL)** is set to **5 hops** to balance delivery reliability with battery conservation. Each intermediate node decrements the TTL before relaying; when TTL reaches zero, the packet drops automatically to prevent infinite circulation.

### What encryption protocol does BitChat use for BLE mesh messages?

BitChat encrypts all BLE mesh traffic using the **Noise Protocol**, which provides **forward secrecy** for active sessions. According to the architecture documentation in [`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md), the Mesh Engine orchestrates Noise handshake routines, ensuring that only the intended recipient can decrypt message contents even when packets traverse multiple intermediate nodes.

### How does BitChat handle messages when the recipient is out of Bluetooth range?

When a recipient is unreachable, the Mesh Engine activates its **smart-queuing** mechanism (detailed in [`README.md`](https://github.com/permissionlesstech/bitchat/blob/main/README.md) lines 89-102). The message persists in local storage until the recipient comes within direct range or appears through a newly connected intermediate node. At that point, the engine automatically retransmits the queued message without requiring user action, effectively providing store-and-forward capability across the mesh.

### Does BitChat require internet to form a BLE mesh?

No. The BLE mesh operates **completely offline** using CoreBluetooth to form ad-hoc networks between nearby devices. The mesh forms automatically when devices running BitChat detect each other’s advertised service UUID (`F47B5E2D-...`). Internet connectivity is only required when falling back to the Nostr protocol for global message propagation; local mesh communication requires only Bluetooth Low Energy hardware.