How to Integrate BitChat with Other Applications: Developer Guide for Nostr-Based Messaging
Yes, you can integrate BitChat with any application that supports Swift frameworks or speaks the Nostr protocol, using either direct API calls or the iOS Share Extension.
BitChat is a decentralized messenger built on the Nostr protocol, which means it uses a public, JSON-based WebSocket API rather than proprietary servers. This architecture makes integration straightforward for developers who want to embed privacy-focused messaging into their own apps. The core integration paths are defined in the permissionlesstech/bitchat repository, specifically within the bitchat/Nostr/ directory.
Two Methods to Integrate BitChat with Your Application
BitChat offers two distinct integration approaches depending on your technical requirements and platform constraints.
Nostr Client API: Direct Programmatic Integration
The Nostr client API lets your application send, receive, and subscribe to Nostr events programmatically. This method gives you full control over message flow, filtering, and relay selection.
The central component is NostrRelayManager.swift, which handles all WebSocket connections, exponential back-off reconnection, message queueing, and event deduplication. You interact with this manager through its public methods rather than managing raw WebSocket connections yourself.
Key components:
NostrRelayManager.swift— manages connections, reconnect logic, and message delivery guaranteesNostrRelaySettings.swift— stores and validates custom relay URLsNostrProtocol.swift— defines message types (EVENT,REQ,EOSE,NOTICE,OK,CLOSED)
iOS Share Extension: Zero-Code Integration for Any iOS App
The Share Extension allows any iOS application to forward content into BitChat conversations without implementing Nostr code. When a user selects BitChat from the standard iOS share sheet, ShareViewController.swift receives the payload, constructs a NostrEvent, and dispatches it through the same NostrRelayManager pipeline used internally.
This requires no code changes in the host application — only the standard UIActivityViewController invocation.
Why BitChat Integration Works Out-of-the-Box
Four architectural decisions in the BitChat codebase make third-party integration reliable and predictable:
-
Protocol-agnostic design — All network traffic flows through the pure Nostr layer. There is no proprietary BitChat server; any reachable Nostr relay suffices.
-
Configurable relay list — The app ships with four default public relays, but
NostrRelaySettings.add(_:builtIn:)supports up to eight custom relays including.onionaddresses. This enables corporate or privacy-focused deployments. -
Tor support — When enabled via
TorManager.shared,NostrRelayManagerautomatically routes WebSocket traffic throughTorURLSession.shared.session, supporting anonymous messaging integrations. -
Resilient message delivery — The manager queues outbound events when relays are offline (
messageQueue), applies exponential back-off (initialBackoffInterval,maxBackoffInterval), and retries transparently. Your code can fire-and-forget events.
Code Examples for BitChat Integration
Sending a Chat Message from Your Swift App
import BitChat
import Foundation
// Create a Nostr event with library helpers for signing
let messageText = "Hello from my app!"
let event = NostrEvent(kind: .textNote, content: messageText, tags: [])
// Send to all configured relays via the shared manager
NostrRelayManager.shared.sendEvent(event)
// Or wait for relay acknowledgment with the confirmed send API
NostrRelayManager.shared.sendEventImmediately(event) { accepted in
print(accepted ? "✅ Delivered" : "❌ Failed")
}
Source reference: NostrRelayManager.sendEvent(_:) and sendEventImmediately(_:completion:) handle serialization, signing, and delivery across all active connections.
Subscribing to Incoming Messages
let filter = NostrFilter(kinds: [.textNote], limit: 100)
NostrRelayManager.shared.subscribe(
filter: filter,
handler: { event in
// Process incoming chat message
print("🔔 New message: \(event.content)")
},
onEOSE: {
// End of stored events signal
print("✅ Finished loading recent messages")
})
Source reference: NostrRelayManager.subscribe(filter:id:relayUrls:handler:onEOSE:) in NostrRelayManager.swift manages subscription state across multiple relays.
Adding a Custom Relay for Private Deployments
let customRelay = "wss://my-private-relay.onion"
let result = NostrRelaySettings.add(customRelay,
builtIn: NostrRelayManager.builtInRelayURLs)
switch result {
case .success(let normalized):
print("✅ Added relay: \(normalized)")
case .failure(let err):
print("❌ Could not add relay: \(err)")
}
Source reference: NostrRelaySettings.add(_:builtIn:in:) normalizes URLs, validates reachability, and enforces the eight-relay limit.
Invoking BitChat from Another iOS App
// Standard iOS share sheet — no BitChat-specific code required
let text = "Check out this photo!"
let activityVC = UIActivityViewController(
activityItems: [text],
applicationActivities: nil
)
present(activityVC, animated: true)
The user selects BitChat from the share sheet. ShareViewController.swift automatically converts the payload to a NostrEvent and enqueues it via NostrRelayManager.shared.sendEvent(event).
Key Source Files for Integration Development
| File | Path | Responsibility |
|---|---|---|
NostrRelayManager.swift |
bitchat/Nostr/NostrRelayManager.swift |
WebSocket relay management, queuing, reconnection, deduplication |
NostrRelaySettings.swift |
bitchat/Nostr/NostrRelaySettings.swift |
Relay URL persistence, validation, normalization |
NostrProtocol.swift |
bitchat/Nostr/NostrProtocol.swift |
Event and filter type definitions |
NostrRelayURL.swift |
bitchat/Nostr/NostrRelayURL.swift |
URL parsing and Tor detection |
ShareViewController.swift |
bitchatShareExtension/ShareViewController.swift |
iOS Share Extension entry point |
Info.plist |
bitchatShareExtension/Info.plist |
Extension capabilities and entitlements |
Summary
- BitChat integrates with other applications through two mechanisms: direct Nostr API calls via
NostrRelayManageror the iOS Share Extension for zero-code sharing. NostrRelayManager.swiftprovides the complete interface:sendEvent(_:),sendEventImmediately(_:completion:), andsubscribe(filter:id:relayUrls:handler:onEOSE:).- Custom relays enable private or corporate deployments through
NostrRelaySettings.add(_:builtIn:). - Tor routing is automatically handled when
TorManageris active, requiring no additional integration code. - Message delivery guarantees include queuing, exponential back-off, and deduplication — your application can fire-and-forget events.
Frequently Asked Questions
Can I integrate BitChat with Android or web applications?
BitChat's core Nostr implementation is Swift-based for iOS, but any platform that speaks Nostr can interoperate. Web and Android applications can connect to the same relays using Nostr libraries in JavaScript (like nostr-tools) or Kotlin. The protocol is identical; only the NostrRelayManager wrapper is iOS-specific.
Do I need to run my own relay to integrate BitChat?
No. BitChat works with any public Nostr relay. However, running a private relay (added via NostrRelaySettings.add) gives you control over message routing, retention policies, and network access — useful for enterprise integrations.
How does the Share Extension handle different content types?
ShareViewController.swift inspects the NSExtensionItem attachments and builds appropriate NostrEvent objects. Text becomes kind: .textNote events; images and files are handled according to Nostr's media conventions. The same NostrRelayManager.sendEvent(_:) pipeline delivers all content types.
Is message delivery guaranteed when relays are offline?
Yes, via client-side queuing. NostrRelayManager maintains a messageQueue and applies exponential back-off (initialBackoffInterval, maxBackoffInterval) to retry delivery. Events are deduplicated by ID across reconnections, ensuring exactly-once delivery semantics without duplicate messages.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →