Skip to content
Direct
How it works
Appearance
Accent

Kept on this device. The accent is the only colour the interface spends, so changing it changes nothing else.

Android

The same transfer, as an app.

A Flutter client on the same protocol and the same signaling service as this page, so a phone and a browser are two ends of one transfer rather than two products. What it adds is the thing a tab cannot have: the transfer keeps running when you leave.

The Android app showing an incoming transfer of one 101 MB file, with Accept and save, and Decline.
A tapped link opens here, not in a browser.
A transfer in progress at 32.8 percent, showing 391 KB/s, time remaining, and a throughput graph.
Rate, remaining and throughput, while it moves.
The Android notification shade showing Direct receiving a file at 10 percent, 9.7 MB of 101 MB, 290 KB/s.
Leave the app. It keeps going, and says so.
The appearance sheet with Light, Auto and Dark, and five accent colours: signal, ion, ember, violet and bone.
The same two theme axes as this site.

What the app adds

It survives the background

A foreground service holds the transfer open when you leave the app, with progress in the notification. A browser tab cannot promise that — leave it and the transfer dies with it.

Links open the app

A share link sent in a chat is claimed by the app rather than the browser, verified against this domain. The offer arrives on the phone straight from the tap.

Files land in Downloads

Bytes are written in 64 KB pieces as they arrive, never held whole in memory. Each file moves into the phone's Downloads only once its SHA-256 matches, so a half-received file never appears there under a name that suggests it is ready.

One protocol, two clients

The wire contract lives in a pure Dart package with no Flutter dependency, so it is tested without a device — and its tests deliberately assert the same things as the TypeScript ones: manifest validation, filename sanitising, and the arithmetic that routes one chunk across a file boundary.

That duplication is the point. If the two drift, a phone-to-browser transfer fails somewhere down in WebRTC, which is a painful place to find out. Pinning the contract on both sides means it fails in a test instead.

Getting it

Android only, and not on a store: the APK comes straight from the releases page. Most phones want the first one.

Android will ask before installing an APK from outside the Play Store, because it should. The build is reproducible from the source below if you would rather not take a binary on trust.

An iOS client is the same Dart on the other side of a platform channel, but the background transfer is the reason this app exists and iOS does not grant it the same way, so it is not worth shipping until that part has an honest answer.