# How BitChat's Location Channels Use the bridgeGeohash Field to Connect Mesh-Only Peers

> Discover how BitChat uses the bridgeGeohash field to connect mesh-only peers. Enable internet communication for devices without direct Nostr connectivity via BLE mesh bridging.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: internals
- Published: 2026-07-30

---

**The bridgeGeohash field acts as a rendezvous TLV (type 0x06) that advertises a peer's ability to bridge BLE mesh traffic to a specific Nostr geohash cell, enabling mesh-only devices to communicate over the internet without direct Nostr connectivity.**

BitChat organizes conversations into three distinct transport layers, with **location channels** serving as geohash-based cells that synchronize messages between local mesh networks and Nostr relays. For devices operating exclusively on BLE mesh without internet access, the **bridgeGeohash** field provides the critical link needed to reach the Nostr network according to the `permissionlesstech/bitchat` source code. This article examines how the repository implements this bridging mechanism through TLV encoding, capability advertisement, and registry management.

## Understanding BitChat's Transport Architecture

### The Three Transport Layers

BitChat categorizes message transport into three layers: BLE mesh for local peer-to-peer communication, Nostr relays for global internet-based messaging, and **geohash-based location channels** that act as intermediaries. Location channels divide the world into hierarchical cells (country, city, neighborhood, pinpoint), allowing users to subscribe to chats based on geographic proximity.

### The Mesh-to-Nostr Connectivity Gap

**Mesh-only peers** lack internet connectivity and cannot subscribe to Nostr relays directly. When these devices need to participate in location channel conversations that also exist on Nostr, they require a bridge node—one peer in the mesh that also maintains a Nostr connection and can forward messages between the two networks.

## How the bridgeGeohash Field Advertises Bridge Capabilities

The **bridgeGeohash** field functions as a Type-Length-Value (TLV) structure that mesh peers broadcast to indicate which Nostr geohash cell they can bridge to. This enables automatic discovery of bridge nodes without manual configuration.

### Defining Bridge Capabilities in PeerCapabilities.swift

In [`localPackages/BitFoundation/Sources/BitFoundation/PeerCapabilities.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/PeerCapabilities.swift) (lines 23-26), the bridge capability is defined as a bit flag that peers set when they can forward mesh traffic to Nostr:

```swift
// PeerCapabilities.swift – bridge capability definition
public static let bridge = PeerCapabilities(rawValue: 1 << 7)   // bridges mesh ↔︎ geohash‑cell

```

When a peer sets this bit, it signals to the mesh that it can act as a gateway to the geohash cell specified in its `bridgeGeohash` TLV.

### Encoding and Decoding the TLV in BLEService.swift

The actual wire format for the `bridgeGeohash` field is handled in [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift). When creating announcement packets, the service appends TLV type 0x06 followed by the UTF-8 encoded geohash string (lines 2775-2782):

```swift
// BLEService.swift – encoding bridgeGeohash
if let bridgeGeohash = bridgeGeohash,
   let cellData = bridgeGeohash.data(using: .utf8) {
    data.append(TLVType.bridgeGeohash.rawValue)   // TLV type 0x06
    data.append(cellData)
}

```

On receipt, the decoder extracts the geohash from the same TLV type (lines 85-90):

```swift
// BLEService.swift – decoding bridgeGeohash
case .bridgeGeohash:
    bridgeGeohash = String(data: value, encoding: .utf8)

```

### Registering Advertised Geohashes in BLEPeerRegistry.swift

Once decoded, the geohash values are persisted in [`bitchat/Services/BLE/BLEPeerRegistry.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEPeerRegistry.swift) (lines 134-138), which maintains a registry of each peer's advertised bridge cell:

```swift
// BLEPeerRegistry.swift – bridgeGeohash storage
.compactMap(\.bridgeGeohash)

```

This allows higher-level services to query which peers can bridge to specific location channels.

## Bridging Mesh Traffic to Location Channels

### Establishing the Bridge Connection

When a user selects a location channel in [`LocationChannelManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/LocationChannelManager.swift), the system checks peer capabilities to find a suitable bridge. If a mesh peer has advertised the bridge capability with a matching `bridgeGeohash`, the manager instantiates a bridge service (lines 312-320):

```swift
// LocationChannelManager.swift – creating a bridge
if capabilities.contains(.bridge), let cell = peer.bridgeGeohash {
    bridge = BridgeService(cellGeohash: cell)
}

```

### Bidirectional Message Flow

The bridge facilitates two-way communication between transport layers:

- **Outbound forwarding**: Mesh-only peers send messages to the bridge node, which signs them as a regular Nostr client and publishes them to the relay for the specified geohash cell.
- **Inbound injection**: Nostr events received for the bridged cell are wrapped in bridge packets and injected back into the local mesh, reaching all connected peers.

This architecture allows mesh-only devices to participate in global location channel conversations without implementing full Nostr client functionality.

## Practical Implementation Example

The following Swift code demonstrates how to create an announcement packet that advertises bridge capabilities, decode it on a receiving peer, and utilize the bridge for location channel communication:

```swift
// 1️⃣ Create an announce packet that advertises the bridge capability
let caps = PeerCapabilities([.meshDiagnostics, .bridge])
let bridgeGeohash = "u4pruy"               // cell that will act as the bridge
let packet = AnnouncePacket(
    capabilities: caps,
    bridgeGeohash: bridgeGeohash)

// 2️⃣ Decode the packet on a receiving peer
guard let decoded = AnnouncePacket(data: inboundData) else { fatalError() }
print(decoded.bridgeGeohash)   // → "u4pruy"

// 3️⃣ When the user selects a location channel, the manager creates the bridge
locationChannelsModel.select(.location(GeohashChannel(level: .city, geohash: "u4pruy")))
if let bridge = BridgeService.shared {
    bridge.send(message: meshMessage)   // forwards to Nostr cell “u4pruy”
}

```

Unit tests verifying this wire format are available in [`bitchatTests/Protocols/BridgeWireFormatTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Protocols/BridgeWireFormatTests.swift).

## Summary

- The **bridgeGeohash** field (TLV 0x06) serves as a rendezvous mechanism that links BLE mesh networks to Nostr geohash cells.
- Peers advertise their bridging capability using the `bridge` bit flag (`1 << 7`) in [`PeerCapabilities.swift`](https://github.com/permissionlesstech/bitchat/blob/main/PeerCapabilities.swift) and specify their target cell via UTF-8 encoded geohash data.
- [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift) handles wire-format encoding and decoding of the TLV, while [`BLEPeerRegistry.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEPeerRegistry.swift) stores advertised geohashes for service discovery.
- [`LocationChannelManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/LocationChannelManager.swift) automatically establishes bridge connections when users select location channels, enabling transparent message forwarding between mesh-only peers and the Nostr network.

## Frequently Asked Questions

### What is the wire format of the bridgeGeohash field?

The field uses a Type-Length-Value encoding where the type byte is `0x06`, followed by the length, and the value contains the UTF-8 encoded geohash string (typically 6 characters for city-level precision). This format is implemented in [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift) for both packet creation and parsing.

### How do mesh-only peers discover available bridge nodes?

Mesh peers discover bridges by receiving announcement packets from peers that have set the `bridge` capability bit in `PeerCapabilities`. The `BLEPeerRegistry` automatically extracts and stores the `bridgeGeohash` value from these announcements (lines 134-138), making it available to the `LocationChannelManager` when selecting channels.

### Can a single peer bridge multiple geohash cells simultaneously?

According to the current implementation in `permissionlesstech/bitchat`, each peer advertises a single `bridgeGeohash` value per announcement packet. To bridge multiple cells, a peer would need to either rotate advertisements or multiple bridge-enabled peers would need to cover different cells in the same mesh.

### Does using a bridge compromise message privacy or authenticity?

No. The bridge node signs forwarded events as a regular Nostr client, but message content remains encrypted using the same cryptographic primitives as direct Nostr communication. The bridge merely acts as a transport layer translator and does not possess special decryption capabilities.