Mándamele
Back to guides

Guides

How browser-to-browser transfers work

A direct transfer has two separate paths: the service coordinates the meeting, while the browsers exchange content over the DataChannel they negotiate.

Updated 2026-08-07 · approximately 710 words

Control passes through the service; transferred content uses a separate path.

Two planes with different jobs

The clearest way to understand Mándamele is to separate the control plane from the data plane. The control plane creates the Pase, admits the second browser, maintains state and carries WebRTC negotiation messages. It uses a WebSocket and a Durable Object associated with the code. That component knows which two connections belong to a Pase, but it does not receive transferred text or file chunks.

The data plane starts when the browsers manage to open an RTCDataChannel. From that point, text messages and files are sent over that channel. Client code does not provide a second route that copies content into the WebSocket. If the direct connection fails, the product reports an error rather than quietly changing to a server upload.

1. Creating a Pase

Selecting “Send something” opens a WebSocket to the creation endpoint. The Worker generates a six-character code from a 31-symbol alphabet that avoids several ambiguous characters. Where Web Crypto is available, generation uses cryptographic random values and rejects byte values that would otherwise introduce bias when selecting a symbol.

The Durable Object records the connection state it needs: code, participants, creation and activity times, and WebSocket connections. An anonymous Pase that has not connected expires after ten minutes. The server returns the code to the first browser, which also creates a link and QR carrying that same code.

2. Joining the second browser

The second browser normalises the code, opens its own WebSocket and asks to join. In this QA configuration and the current public flow, manual approval is disabled, so the first browser automatically approves a valid request. The shared protocol still contains approve and reject events, but this test pass deliberately does not add another waiting screen to the product flow.

After pairing, each side receives the other participant’s technical identifier. Those identifiers direct offers, answers and ICE candidates to the correct browser. They are control data. No file has been sent yet, and knowing the code cannot retrieve earlier content because the service does not keep a transfer inbox or content history.

3. Negotiating WebRTC

The browser that created the Pase builds an RTCPeerConnection and an ordered DataChannel labelled “mandamele”. It produces an SDP offer and sends it over the WebSocket. The second browser sets that as its remote description, creates an answer and returns it through the same control path. Both sides forward ICE candidates as the browser discovers them.

Configuration includes stun:stun.l.google.com:19302 to help discover usable addresses. It does not include TURN. If firewalls, NAT, VPNs or browser policy leave no route between the endpoints, negotiation may stall or fail. Following a connection failure, the owner attempts an ICE restart and waits eight seconds before treating recovery as unsuccessful.

4. Opening the channel and transferring

Each side announces that its DataChannel is ready. When the local channel is open and the remote side has confirmed readiness, the interface enables transfer controls. Text is serialised as a message on the DataChannel. A file begins with validated metadata — name, type, size and chunk count — and continues as ordered 64 KiB binary blocks.

The sender waits when bufferedAmount goes above 1 MiB and resumes once it falls towards the configured 512 KiB threshold. This is backpressure, not remote storage. The receiver collects chunks, validates the expected size and creates a local Blob. Files over 50 MB are rejected before transfer begins.

5. Ending the session and understanding limits

While a Pase is connected, the client sends a control ping every 25 seconds. Anonymous sessions close after thirty minutes without activity. Closing a tab or leaving the Pase disconnects the other browser. These times describe connection state, not server file retention, because transferred content is not uploaded there.

“Direct” describes the implemented content path, not a guarantee that every network combination will connect, a particular speed, or the absence of local copies. Performance depends on both devices and networks. The recipient decides whether to download, copy or retain the result, and each user should verify an important file before depending on it. A completed interface state is evidence of receipt in that session, not a durable backup.

  • WebSocket: code, state and signalling.
  • DataChannel: text, metadata and file chunks.
  • No open DataChannel: there is no server fallback for content.