Guides » Communications » Jami & Tox VoIP

Decentralized VoIP: Jami and Tox Peer-to-Peer Calling

Jami and Tox both exist to answer a specific question: what does calling someone look like when there is no account, no phone number, and no company in the middle? Both generate a cryptographic identity locally, both find peers through distributed discovery, and neither has a registration service that could be subpoenaed.

That architectural choice is the whole point. Signal requires a phone number, which means the service operator knows every user's number and can be compelled to produce it. Jami and Tox have no such record to produce, because no server ever learns the mapping between your identity and your identity document.

The cost is usability and reliability. Both are peer-to-peer, which means calling requires the other party to be reachable — no server queues calls for a recipient who is offline. NAT traversal adds friction, and group calling is limited by the weakest participant's connection.

Jami command-line output showing a locally generated account with no phone number or email, file permissions on the key files, and zero active central connections
Figure 1 — Local identity: the Jami account is a cryptographic key pair generated on the device, with no registration record anywhere and keys readable only by the owner.

1. How the Protocol Protects You

Jami and Tox solve the same problem differently, and which one suits you depends on how you use it.

Aspect Jami Tox
Identity 40-char hex URI from a key pair 76-char hex Tox ID from key pair
Discovery Distributed hash table (OpenDHT) Mainline DHT (BitTorrent-based)
Calling Direct SIP-over-P2P to the URI Direct audio/video between Tox IDs
NAT traversal STUN/TURN where available UDP hole punching; struggles with symmetric NAT
Transfer Direct socket Direct socket, no size limit
Group call Supported for small groups Depends on the client; limited
Mobile reliability Better; handles push notifications Poor — DHT requires an always-on client

The mobile row is the deciding factor for most people. Tox's DHT model assumes a client that stays connected; on Android and iOS the OS suspends background apps aggressively, so calls only arrive when the app is open. Jami handles this better with push notification relays, though there is a tradeoff — a push relay learns that a call is arriving, even if not who is calling.

2. Setup Walkthrough

The verification that matters is confirming the identity is locally generated and that nothing was registered. Both are checkable from the command line.

# Jami on Linux (Debian/Ubuntu)
$ sudo apt install jami
$ jami-cli account list

# Tox - pick a client; toxcore-cli is the reference
$ sudo apt install toxcore-utils
$ tox_cli profile show

# Confirm the private key never left the machine
$ ls -la ~/.local/share/jami/*/privateKey
# Expect: -rw------- owned by your user, not world-readable

# Confirm no registration request went out during setup
$ sudo nethogs -t -c 5 2>/dev/null | grep -iE 'jami|tox'

If the private key file is group- or world-readable, fix it before doing anything else: chmod 600 privateKey. A P2P identity whose key is readable by other local users is not a private identity.

3. Configuration That Actually Matters

Both systems use self-authenticating identifiers — the URI contains the public key. That means no directory lookup exists, and it also means the exchange has to happen over a channel that cannot be tampered with.

# Compare the full identifier out of band, not just a screenshot of the QR.
# The URI's last block IS the public key fingerprint:
#   jami: 8f3a9c21 b4e7d056 2a1c9f8b 3d4e5a6f 7c8b9d0e 1f2a3b4c 0d1e2f3a 4b5c6d7e
#          ^^^^^^^^^ -- compare at least the first two blocks verbally

# Tox ID = public key (64 hex) + nospam (8 hex) + checksum (4 hex)
# The first 64 characters are the identity that cannot be forged.

# Practical rules:
#  1. Exchange by voice or in person when the contact matters.
#  2. The QR code is fine for convenience; verify the fingerprint once.
#  3. A Tox ID pasted into a chat app can be altered in transit - the UI
#     shows a short checksum for exactly this reason. Check it.

The checksum embedded in a Tox ID is the mechanism designed for this: if a single character is altered in transit, the client rejects the ID rather than silently connecting you to an attacker's endpoint.

4. Limitations & Known Leak Paths

Both clients will happily use any available relay. Constrain that, and remove the features that reintroduce an account.

# Jami - review settings that create external dependencies
#  - Disable the default TURN/STUN if you run your own or accept
#    direct-connection-only calls
#  - Do not link an account to a "Jami username" (the name
#    registration service reintroduces a central directory)
#  - Do not enable the backup account - it uploads your account
#    archive so you can restore on another device

# Tox - verify no proxy is being used unless you set one
$ grep -i proxy ~/.config/tox/*.json 2>/dev/null

# Confirm no central server is contacted at startup
$ sudo ss -tunp | grep -E 'jami|tox' | grep -v '127.0.0.1'

# Android: restrict background data for the app to limit
# discovery traffic leaking to the mobile carrier

The Jami username registration feature is the one to avoid. It maps a human-readable name to your URI through a registration server, which is precisely the central directory the rest of the design avoids. Use the raw URI instead.

Tox command-line client showing a generated Tox ID with DHT status and tcpdump output confirming peer-to-peer UDP discovery with no central relay
Figure 2 — Tox DHT path: the client is online through distributed discovery, and tcpdump shows direct UDP traffic to peers rather than a relayed stream.

Frequently Asked Questions

Can Jami or Tox replace my phone number?

For voice calls with people who also run the client, yes. For reaching anyone with a regular telephone, no — neither interconnects with the PSTN. They replace a calling app, not a phone line.

Why do Tox calls fail on mobile networks?

Carrier-grade NAT on mobile networks frequently uses symmetric NAT, which UDP hole punching cannot traverse without a relay. The DHT model also assumes a persistently connected client, and mobile operating systems suspend background apps. Jami handles both better.

Is Jami's username feature really a problem?

It is a privacy tradeoff rather than a flaw. Registering a name makes you findable and requires a server holding the name-to-URI mapping — the same centralisation the protocol otherwise avoids. If convenience matters more than that, use it knowingly; if it does not, share the URI.

Sources & References


This VoIP client audit guide reflects what we actually observed on our test box — expect small differences with other releases, and run the verification section before considering the work finished.