BitChat Private Message Types: The 6 Encrypted Formats Defined in the Source Code

TLDR: BitChat supports six distinct encrypted private message types—privateText, privateMedia, privateMediaReceipt, privateMediaStatus, privateMessageReceipt, and privateMessageStatus—each declared in the MessageType enum and wrapped in a Noise-encrypted envelope before transmission.

The permissionlesstech/bitchat repository implements peer-to-peer messaging through a strict MessageType classification system. Understanding the different types of private messages supported by BitChat is essential for anyone building on or auditing the protocol, because every encrypted payload is tagged with one of these six enum cases before it leaves the client.

The Six Private Message Types Defined in MessageType.swift

In localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift, the MessageType enum lists every variant that can travel inside an encrypted peer-to-peer envelope:

  • privateText — The standard end-to-end encrypted text message. This case handles plain-string payloads exchanged in one-on-one conversations.
  • privateMedia — An encrypted media payload such as an image, video, or audio file. Peers must advertise the privateMedia capability in PeerCapabilities.swift before these messages are exchanged.
  • privateMediaReceipt — A cryptographic receipt confirming that a privateMedia message was received and deduplicated by the recipient.
  • privateMediaStatus — A fine-grained status update for a media item, indicating actions like "viewed" or "downloaded".
  • privateMessageReceipt — A generic delivery-and-read receipt for a privateText message.
  • privateMessageStatus — Granular status tracking—such as sent, delivered, or read—for a private text conversation.

How BitChat Encrypts and Routes Private Messages

Each case is wrapped in a Noise-encrypted envelope at the protocol level. In BitchatMessage.swift, the BitchatMessage struct pairs a MessageType value with its serialized payload, sender ID, and recipient ID. Because the type tag travels with the ciphertext, the recipient can branch on the enum case immediately after decryption to determine the correct decoding logic and UI behavior.

Code Examples for Sending and Receiving Private Messages

Sending a Private Text Message

Use PrivateMessagePayload to build the body, then set type to .privateText in the BitchatMessage initializer:

let text = "Hey there!"
let payload = try PrivateMessagePayload(text: text)
let message = BitchatMessage(
    type: .privateText,
    payload: payload,
    sender: myPeerID,
    recipient: recipientPeerID
)
chat.send(message)

Sending a Private Media Message

Create a PrivateMediaPayload with the raw asset, a MIME type, and an optional thumbnail, then tag the outer message with .privateMedia:

let imageData = try Data(contentsOf: localImageURL)
let media = PrivateMediaPayload(
    data: imageData,
    mimeType: "image/png",
    thumbnail: thumbnailData
)

let message = BitchatMessage(
    type: .privateMedia,
    payload: media,
    sender: myPeerID,
    recipient: recipientPeerID
)
chat.send(message)

Handling a Private Media Receipt

Incoming messages are dispatched by type. When the case is .privateMediaReceipt, update the local delivery state:

func handleIncoming(_ message: BitchatMessage) {
    switch message.type {
    case .privateMediaReceipt:
        // Peer confirmed storage — update the UI accordingly
        chat.markMediaAsDelivered(message.id)
    default:
        break
    }
}

Key Source Files That Define Private Message Behavior

Summary

  • BitChat defines six private message types in the MessageType enum inside MessageType.swift.
  • The types cover text, media, receipts, and status updates, all encrypted via Noise.
  • BitchatMessage.swift wraps each typed payload with sender and recipient metadata.
  • PeerCapabilities.swift gates feature support so peers only receive privateMedia if both sides advertise the capability.

Frequently Asked Questions

What are the exact private message types supported by BitChat?

BitChat supports privateText, privateMedia, privateMediaReceipt, privateMediaStatus, privateMessageReceipt, and privateMessageStatus. These cases are declared in localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift and represent every encrypted payload category the protocol handles.

How does BitChat encrypt private messages?

BitChat wraps every private payload in a Noise-encrypted envelope. The BitchatMessage struct in BitchatMessage.swift pairs the MessageType tag with the encrypted bytes, ensuring only the intended recipient can decrypt and interpret the payload.

What is the difference between privateMediaReceipt and privateMediaStatus?

privateMediaReceipt confirms that a media message was successfully received and deduplicated by the peer. In contrast, privateMediaStatus signals user-facing actions—such as "viewed" or "downloaded"—after the initial delivery occurred.

Where in the BitChat codebase are private message types declared?

All private message types are declared in localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift as cases of the MessageType enum. Supporting logic lives in BitchatMessage.swift, PeerCapabilities.swift, and PrivateMessagePayload.swift.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →