Skip to main content
Every flag and environment variable that floe, Floe’s CLI, reads, its exit codes and timeouts, and what a script needs to know.

The short version

Most transfers need no flag at all. Use --server, or set FLOE_SERVER once, to use a self-hosted server, and --relay-only to keep your IP address from the other person. On floe receive, -o picks the folder and -y skips the question. In a script, read the exit status: 0 worked, 1 failed, 130 was stopped.

Global flags

Every command accepts these, but only send and receive act on them. floe version and floe update accept them and do nothing with them, so floe version --server https://floe.example.com changes nothing. The one exception is the pair --relay-only and --no-relay, which every command refuses together. --server. Give the address with its https://, or http:// on a local network. A bare hostname such as floe.example.com fails before any transfer starts, with lines that point at the network instead. floe send, for example, prints Warning: could not reach signaling server for TURN credentials. Using STUN only. and then Error: failed to connect to signaling server: with the cause. floe trusts the certificates your system trusts and has no option to skip that check. --no-relay. It is one-sided: the peer, the other device, can still offer a relay, and if that path wins the CLI proceeds over it. Pass the flag on both ends when it has to be a guarantee. When no path forms at all, the attempt fails like any connection that cannot be made (see Timeouts), never with a message about the relay. --relay-only. It is the command-line twin of the desktop app’s Hide my IP address switch (see Hide my IP), and it applies to your side only. While it is on, the 2 GB relay cap applies to every transfer, even on a network that could have connected directly; see File size limits. It needs a relay to exist. Against a server that offers STUN only, the command stops before the transfer starts and names the flag. It cannot be combined with --no-relay, and FLOE_RELAY_ONLY=1 sets it too. --web. The web address in the share link is worked out from --server. https://api.floe.one maps to https://floe.one, http://localhost:3001 maps to http://localhost:3000, and any other server maps to itself, on the assumption that one origin serves both the API and the web app. The server is matched in any capitalization, with or without its default port (:443, or :80 for http) and a dot at the end of the hostname. Set --web only when your web app has its own hostname. --iface. Repeat the flag or separate names with commas, so --iface Ethernet --iface Wi-Fi and --iface Ethernet,Wi-Fi do the same thing. Use it when a VPN or virtual-machine adapter (Tailscale, VMware, WSL, Hyper-V) slows connection setup; see slow to connect. Your system lists the names: Get-NetAdapter in PowerShell on Windows, ip link on Linux, ifconfig on macOS. If no interface on this computer matches any name you give, floe stops before it pairs, with Error: --iface matches no network interface on this computer; check the name, or drop the flag, and exits with status 1. The check reads names only, so an adapter that exists but is down passes it. floe 1.11.7 and earlier do not check the name, so one that matches no interface is accepted without a word, and the connection fails after pairing. The desktop app has equivalents for three of these. --server and --web are Server address and Share link address, under Advanced in Settings, and --relay-only is the Hide my IP address toggle under Privacy. --no-relay and --iface have no desktop equivalent: Floe Desktop can require the relay but never refuse it. See Desktop app settings.

floe send flags

Specific to the send command. With --to, no link is printed, so --web has no effect, and the request link has to belong to the server in effect. See Send through a request link. With --link-only, no file is named until the receiver has proved it holds the link’s link key, and a receiver that shows no proof within 15 seconds ends the send with status 1. See Send only to a receiver that proves it holds the link.

floe receive flags

Specific to the receive command.

floe update flags

Specific to the update command. --check. On an up-to-date binary the flag changes nothing: floe update prints Already up to date (1.12.0) and stops either way (the installed version carries no leading v). On a package manager install the update guard runs first, so --check stops with the upgrade command for your package manager instead of a version report. On a build compiled from source, it stops with Error: Cannot update a dev build. See Update the CLI.

Help and version flags

These come from the CLI framework rather than from Floe itself. floe help comes from the same place, and so does the floe completion command, below.

Shell completion

floe completion bash, floe completion zsh, floe completion fish and floe completion powershell each print a tab-completion script for that shell. Run the same command with --help, for example floe completion powershell --help, to see how to load it. Once it is loaded, pressing Tab asks floe what fits where the cursor is:
  • --iface offers this computer’s network interface names. Bash, Zsh and PowerShell offer the names that begin with what you have typed, PowerShell in any letter case, and fish also matches the middle of a name. The flag itself matches any part of a name, in any letter case.
  • In Bash and Zsh, -o and --output offer folders only. In PowerShell and fish they offer files and folders, as for any path.
  • The paths of floe send offer files and folders.
  • A code or link for floe receive, --to, --server and --web offer nothing, and neither do floe version and floe update.
Before 1.11.6, completion offered file names for every flag’s value and for the argument of floe receive, floe version and floe update.

Environment variables

floe has five environment variables of its own. If you run your own signaling server, set it once in your environment instead of passing --server on every command. The last three act only on the exact value 1: true, yes or any other value does nothing. While FLOE_SERVER names your own server, a link made on floe.one, whose room is on floe.one’s server, is refused before any network call, by floe receive and by floe send --to. Pass --server https://api.floe.one for that one command. See Use a self-hosted server. A flag always beats its variable, so you can override the setting for a single command without unsetting anything:
macOS and Linux
On Windows PowerShell:
Windows
Trailing slashes are trimmed, so https://floe.example.com/ and https://floe.example.com behave the same. Set FLOE_WEB only when your web app runs on a different host from your signaling server. Leave it unset and share links point at the same host as your server, which is what you want when one domain serves both. The only exceptions are Floe’s own deployment and the local dev pair, which are special-cased to their web hosts as described under --web above. floe also follows the usual proxy variables, HTTPS_PROXY, HTTP_PROXY and NO_PROXY. They apply to its connection to the signaling server and to every web request it makes: the code lookup, the relay details, the byte-count report, and the update check and download. The files themselves travel over the WebRTC connection between the two devices, which does not go through such a proxy. floe turns off some log lines of Pion, the WebRTC library inside it: lines that are only noise, and lines that can quote text a stranger chose. Setting a PION_LOG_ variable that turns a log level on, such as PION_LOG_TRACE=ice, brings all of them back, so set one only while debugging.

In scripts and CI

floe reads no configuration file and asks one question, so a job needs only flags, environment variables and exit codes.
  • Accept without a prompt. floe receive asks Accept? [Y/n] before it saves anything. Pass -y to skip the question.
  • With nothing to read, the prompt accepts. The prompt declines only on n or no. A closed or piped stdin gives it an empty answer, which accepts, so echo | floe receive <code> receives without -y. Leaving -y out therefore does not stop a job from receiving. Pass it anyway, so the intent is on the command line rather than in the shell’s plumbing.
  • Exit codes. 0 is success, 1 is any error, and 130 is an interrupt (Ctrl+C, SIGTERM, or on macOS and Linux a hangup). There are no others. See Exit codes.
  • What success means for a send. It depends on the receiver. See File checks.
    • floe send --to exits 0 only after the other side’s Floe confirmed that every file arrived.
    • A plain floe send to floe receive 1.11.0 or later, or to Floe Desktop 0.3.0 or later, exits 0 only after the receiver said it saved every file. To a browser it exits 0 only after the page said it holds every file.
    • To an older receiver, it exits 0 once the other side’s connection has acknowledged all the data.
  • A send waits as long as it takes. floe send has no time limit of its own while it waits for the other side to connect, so give the job a timeout if it must not hang. It does end, with status 1, if its own connection to the signaling server drops while it waits.
  • Pass the link when the wait may be long. A room code stops working after 10 minutes at most, and the link works for as long as that floe send runs: see How long a code and a link last. floe receive takes either. In floe 1.12 and later the link holds an & and a link key, so keep it in quotes, and the process list and any log that repeats the command then hold that link key.
  • Environment variables. Set the server once with FLOE_SERVER. Set FLOE_NO_STATS=1 on a job that receives, so test transfers do not add to the public counter, and FLOE_NO_UPDATE_CHECK=1 if the job runs floe version. See Environment variables.
  • Streams. Status lines, the boxes, the prompt, progress and Warning: lines go to stdout. Errors, every refusal line and the Canceled. line go to stderr.
  • Progress in a log. The progress line is written even when stdout is not a terminal: it is redrawn in place with carriage returns, at most once every 65 milliseconds, 80 columns wide. There is no flag that turns it off, so a script that reads stdout has to skip those frames.
  • Error text. An error line is cut at 2,000 characters. A control character in text that Floe did not write, such as a server’s message, prints as a visible escape like \x0a.

Opting out of the global counter

After a successful transfer, the receiver sends only the total byte count to the signaling server it is connected to, for the public “transferred globally” counter. That is api.floe.one by default, or your own server when you set --server or FLOE_SERVER. No file names, contents, or identity are included. The sender never reports, and a transfer of only empty files sends nothing. Errors are ignored, so a failed report never changes the outcome of a transfer. The request goes out after every file is written and the summary has printed. It has a 5-second timeout, so an unreachable server can delay floe receive from exiting by a few seconds but never affects the files. To opt out for a single transfer, pass --no-report:
Terminal
To opt out permanently, set FLOE_NO_STATS=1 in your environment (for example in your shell profile):
Terminal
When opted out, no request is sent to the server and the global counter is not incremented for that transfer. The transfer itself is unaffected. The browser and Floe Desktop have a switch of their own for the same report. See Aggregate statistics.

Exit codes

On 130, Floe prints Canceled. to stderr and removes the .part file it was writing, waiting at most 5 seconds for that before it exits. Once connected, a plain floe send first tells the receiver that the sender stopped, and floe receive tells the sender, each within about a second. floe send --to prints its own line instead, Canceled. Nothing was sent. or You stopped this drop. with how many files were saved. On macOS and Linux, a hangup counts as an interrupt. Closing the terminal window, losing the SSH session, or sending SIGHUP stops floe the same way as Ctrl+C, as described above. A closed terminal cannot show the line, but the exit status and the notice to the other side are the same. floe 1.11.7 and earlier stop at once on a hangup: they tell the other side nothing and leave the .part file. A floe started under nohup ignores the hangup and keeps going:
Terminal
A mistake in a command’s arguments or flags prints one Error: line and no usage text, and exits 1. For example, floe send with no file prints Error: requires at least 1 arg(s), only received 0, and floe receive with no code prints Error: accepts 1 arg(s), received 0. Both relay flags at once print Error: if any flags in the group [relay-only no-relay] are set none of the others can be; [no-relay relay-only] were all set. --link-only with --to, in floe 1.12 and later, prints Error: if any flags in the group [to link-only] are set none of the others can be; [link-only to] were all set. floe with no arguments prints help and exits 0.

Timeouts

Floe gives up rather than hanging, and the limits differ by phase. The ones you are most likely to meet: During setup, a peer that leaves ends the wait at once, with the other side left before the connection was established. A connection that fails outright ends it too, with Error: WebRTC setup failed: connection failed (state: failed). A floe receive can sit for up to about 10 seconds after printing its summary. That is a 5-second grace period so the final acknowledgment reaches the sender, plus the report. When that acknowledgment is slow to reach the sender, it waits up to 35 seconds from sending it before the report. The full list is in the transfer protocol reference, and every Floe limit is collected in Limits.

Examples

Use a local dev server for both sender and receiver:
Terminal
Disable relay fallback (direct connections only):
Terminal
Hide your IP address from the other side by forcing the relay (the 2 GB cap applies):
Terminal
Point the browser link at a custom web client:
Terminal
Save received files to a specific folder and auto-accept:
Terminal
See Use a self-hosted server for more server configuration examples.
Last modified on November 5, 2026