How optical file transfer works
Last updated: August 5, 2026
In one paragraph: the sending phone turns your file into an endless stream of QR codes and plays them as an animation. The receiving phone films that animation and rebuilds the file from whatever frames it manages to read. Because every frame is a random mix of the whole file rather than one specific piece of it, the receiver can start at any moment, miss as many frames as it likes, and still finish. There is no handshake, no back-channel, and no radio of any kind.
1. The channel is a screen and a lens
Every other way of moving a file between two phones borrows someone else's network: Wi-Fi, mobile data, Bluetooth, a cable, a server in a datacentre. Each of those can be absent, disabled, blocked by policy, or simply untrusted.
Beam uses the two pieces of hardware that are always present and never blocked — the sender's display and the receiver's camera. The file crosses the room as light. That is the entire physical layer, and it is why Beam works in airplane mode, abroad with no SIM, underground, and on networks that forbid device-to-device traffic.
It also sets a hard ceiling. A camera reads a finite number of frames per second, and each frame holds a finite number of bytes, so optical transfer is measured in kilobytes per second, not megabytes. Beam quotes about 24 KB/s for a 4 MB photo on its Fast profile and shows you the estimate for your actual file before you commit to it.
2. Every frame is self-describing
Each QR symbol carries a 24-byte header and then a block of data. The header is little-endian and holds a two-byte magic number, a protocol version, a frame kind, a random session id, a sequence number, the block count, the block length, the total payload length, a CRC-32 of the finished payload, and a flags byte marking whether the payload is encrypted and whether it was compressed.
That header is what removes the handshake from the protocol. A receiver that has just arrived learns from a single frame how big the file is, how many blocks it comes in, and how to check it when it's done. If the sender restarts, the new session id tells the receiver to discard what it had and begin again. There is nothing to negotiate, which is fortunate, because there is no channel on which to negotiate it.
A second frame kind, the beacon, carries a short human-readable summary of what's coming, so the receiving phone can show you the file's name and size long before it has enough data to reconstruct anything.
3. Fountain coding: any frame will do
The obvious design — cut the file into numbered pieces and show piece 1, 2, 3 … — fails badly on a one-way channel. Miss piece 47 and you must wait for the whole loop to come around again, and the sender has no way of learning which pieces you're missing.
Beam uses a Luby-transform fountain code instead. Frame n is the XOR of a pseudorandom subset of the file's blocks. The size of that subset — its degree, drawn from a robust soliton distribution — and the identity of the blocks are both derived deterministically from the sequence number and the session id, so the receiver can reconstruct the recipe for any frame from the frame itself. No table is transmitted.
The consequence is the useful part: the receiver rebuilds the file from any sufficiently large set of distinct frames, in any order. A frame lost to motion blur, autofocus hunting, or a badly-timed display refresh costs a little time and never costs correctness. The two devices' frame rates never have to match, or even be known to each other.
Both ends must generate bit-identical random numbers for this to work, which is why Beam ships its own PRNG and its own deterministic logarithm rather than trusting the platform's — a one-ulp disagreement in log() would shift a degree by one and quietly decode the stream to garbage.
How many frames you actually need
The figure usually quoted for LT codes is about 1.15× the number of source blocks. That is the asymptotic behaviour, and small transfers are nowhere near it. Measured over Beam's encoder:
| Source blocks | 50 | 126 | 300 | 800 | 2000 | 6000 |
|---|---|---|---|---|---|---|
| Frames needed, per block | 1.48× | 1.31× | 1.23× | 1.19× | 1.14× | 1.11× |
Small files are proportionally more expensive to send than large ones. Beam models this with a fitted curve rather than a flat constant, so its progress bar doesn't tell you you're 99% done for a third of the transfer. Correctness never depends on the estimate — only the ETA does.
4. Why you can start watching halfway through
Put the three properties together — self-describing frames, a deterministic recipe per frame, and a code where every frame is equally useful — and joining late becomes unremarkable. The sender loops until you stop it. The receiver can arrive ten seconds in, look away, come back, and keep accumulating. Nothing is ever "the beginning" of the stream, so there is no beginning to miss.
The same property makes stalling harmless. Re-aim the camera and progress resumes from where it stopped, because progress is a count of distinct frames collected, not a position in a file.
5. What actually sets the speed
Three physical limits, all of them stubborn:
- Refresh straddle. Every frame must occupy at least two display refresh cycles, or the camera catches a frame mid-transition and gets nothing. That alone caps a 60 Hz screen at 30 frames per second.
- Module resolution. A denser QR symbol carries more bytes per frame, but the receiver's camera has to resolve individual modules to read it — which means a bigger, sharper, closer, steadier view. Density is bought with fussiness.
- Capture yield. Real cameras don't decode every frame they see. Blur, autofocus hunting and refresh straddling each take a cut. Beam's estimates assume about 85% of transmitted frames are decoded, which is the propped-phone case; handheld is worse.
In-frame error correction is deliberately kept low on most profiles. QR's own ECC and the fountain layer solve genuinely different problems — corruption versus erasure — and on this channel a frame is either decoded whole or discarded whole. Paying a quarter of every frame for redundancy the fountain already provides is a bad trade.
Transfer profiles
Beam ships a ladder of profiles rather than making you reason about QR symbol versions, and picks a sensible default from the size of what you're sending. The everyday three:
| Profile | QR version | Frames per second | Best for |
|---|---|---|---|
| Steady | 19 | 12 | Poor light, older cameras, arm's length, a shaky hand |
| Balanced | 23 | 18 | The everyday setting — about a hand's width away |
| Fast | 27 | 24 | Noticeably quicker, with both phones propped up |
A version-27 symbol is 125 modules on a side. Holding that steady enough for a camera to resolve is the real constraint on going faster, which is why propping the phones up is a first-class mode in the app rather than an apology.
6. Encryption and integrity
The honest threat model for this medium: the stream is light in a room. Line of sight is the only access control the channel provides, and anyone who can see the sending screen can film it.
So Beam offers an optional PIN. A six-digit PIN is only about twenty bits of entropy, so the key derivation has to supply the rest of the cost: PBKDF2-HMAC-SHA256 at 210,000 iterations, which puts an offline sweep of the keyspace well outside "casual" — the realistic adversary for a transfer that already required standing in the room. The payload is sealed with ChaCha20-Poly1305, so a wrong PIN fails authentication outright instead of yielding plausible garbage.
Independently of encryption, the header carries a CRC-32 of the whole payload, checked once the container is reassembled. A file either arrives byte-identical or doesn't arrive.
7. What Beam is bad at
Worth saying plainly, because the honest version is more useful than the brochure version:
- Large files. At kilobytes per second, a long video is a coffee break, not a transfer. Beam shows you the time before you start precisely so you can decide it isn't worth it.
- Unattended transfers. Two phones must face each other for the whole duration.
- Bright, glary environments. Sunlight on the sending screen costs you frames, and frames are the currency.
- Being the fastest option. When Wi-Fi, a cable or AirDrop are available, use them. Beam is for when they aren't.
Where to go next
- What Beam is and when it saves you
- Support and troubleshooting — aiming, light, stalls and quality settings
- Privacy policy — what Beam does and does not collect