Reactions Interoperability Guide
March 10, 2026 · View on GitHub
How to implement emoji reactions compatible with MeshCore One.
Message Hashing
Reactions target messages by a hash of their content. Every node that received the original message can compute the same hash independently.
- Concatenate the message's UTF-8 text bytes with the sender's original timestamp as a little-endian
UInt32 - SHA-256 the result
- Take the first 5 bytes (40 bits)
- Encode as 8 characters of Crockford Base32
SHA-256( UTF-8(text) + LE(UInt32(senderTimestamp)) )
→ first 5 bytes → Crockford Base32 → "b45pc4ek"
Use the sender's original timestamp, not your local receive time in order for all nodes to agree on the hash.
Why Crockford Base32?
Crockford Base32 maps 5 bytes to exactly 8 characters using only alphanumerics — no special characters that could conflict with the wire format delimiters (@, [, ], \n). Hex would need 10 characters for the same data. Base64 fits in 8 but uses +, /, =. The parser is case-insensitive and normalizes common substitutions (O → 0, I/L → 1).
Wire Format
Reactions are sent as regular mesh messages with a specific text format.
Channel (includes target sender to disambiguate identical messages from different users):
{emoji}@[{targetSenderName}]\n{hash}
Example: 👍@[AlphaNode]\nb45pc4ek
DM (two-party, sender is unambiguous):
{emoji}\n{hash}
Example: 👍\nb45pc4ek
Receiving Reactions
When you receive a message, check if it matches the reaction format before treating it as a regular message.
If it's a reaction: look up the target message by hash. If the target hasn't arrived yet (out-of-order delivery is common on mesh), queue the reaction and match it when the target appears.
If it's a regular message: compute its hash and index it so future reactions can find it. Also check your pending queue for reactions already waiting on this hash.
Deduplicate by (targetHash, senderName, emoji) — a node may relay the same reaction more than once.